python script to download multiple reports from odoo
Wasted looping

Let's do a pop quiz on this code:


partner = ([p for p in self.partners if p["id"] == invoice_id])[0]



If self.partner contains a million values,
and the first value has id equal to invoice_id,
how many values will be visited?


       All of them :(


That's unfortunate.
It would be better to spell out a loop:

for p in self.partners:
    if p["id"] == invoice_id:
        partner = p
        break
else:
    partner = None


Sure, this is longer, but it avoids a performance issue waiting to happen,
and it also handles the case gracefully when there is no matching value.

A compact alternative is possible using generator expressions, which are very cool:

partner = next(p for p in self.partners if p["id"] == invoice_id)


However, in this case, you would still need to handle the case when there is no matching value.
You would do that by expecting StopIteration to be raised.

Avoid wildcard imports

It's good to avoid wildcard imports.
It makes it easier to understand where symbols come from.
When you import *,
it can easily become confusing to tell where some names come from.

In this code the wildcard import seems pointless:


from dateutil.relativedelta import *
today = date.today()
nextmonth = today+relativedelta(months=+1)
nextmonth = nextmonth+relativedelta(day=1)

return nextmonth



It seems the only thing it imports is the relativedelta,
so you could write just that instead of using a *.

Also, I think that the last 3 statements are actually easier to read inlined:

return today + relativedelta(months=1) + relativedelta(day=1)


Import at the top of the file

It's recommended to import packages at the top of the file, not inside functions.

The above link is part of PEP8, a collection of recommended guidelines that should help you achieve the goals such as maintainability outlined in your question.

Drop pointless statement

In the constructor of UniReportPrinter there is this line:


odooconnection1 = ''



I'm wondering if you might be confusing odooconnection1 with self.odooconnection1.
They are different variables.
The first is a local variable,
the second is a field of the object being created.

If you want to unset self.odooconnection1, assign None to it instead of an empty string.

Getters should return something

I would expect functions with "get" in the name to return something.
The __get_partner_details function doesn't return anything.
I suggest to rename the method. Perhaps replace "get" with "fetch".

Be consistent

In some places I see print("string"), in others print "string".

In some places I see '{}/foo'.format(bar), in others '%s/foo' % bar, or bar + '/foo'.

It's good to be consistent.
And to consistently use the right techniques.
In each of these examples the right technique is the first.

Use '...'.format(...)

Especially when formatting complex strings like here,
definitely use '...'.format(...) instead:


return str(partner['partner_id'][0])+'-'+partner['reference'] + '.pdf'