Thursday, March 24, 2016¶
super()
in the __str__()
of a python_2_unicode_compatible¶
Here is now how to reproduce #844.
The following code snippet was used to reproduce #844:
>>> from lino import startup
>>> startup('lino_welfare.projects.std.settings.doctests')
>>> from lino.api.doctest import *
>>> obj = households.Member()
>>> print(obj)
Member object
Explanation starts in lino_xl.lib.households.models
which
defines:
@python_2_unicode_compatible
class Member(mixins.DatePeriod):
def __str__(self):
if self.person_id is None:
return super(Member, self).__str__()
if self.role is None:
return unicode(self.person)
return u"%s (%s)" % (self.person, self.role)
This code, on its own, is not problematic. The problem comes only when
Lino Welfare extends the Member model. In
lino_welfare.modlib.households.models
it says:
class Member(Member, mixins.Human, mixins.Born):
...
And in lino.mixins.human
we have:
from lino_xl.lib.households.models import *
@python_2_unicode_compatible
class Human(model.Model):
def __str__(self):
return self.get_full_name(nominative=True)
The rule of thumb is: Don’t use :func:`super` in the :meth:`__str__` method of a `python_2_unicode_compatible` model.
My explanation is that python_2_unicode_compatible causes something
to get messed up with the mro for the __str__()
method, but I
wont’t dive deeper into this right now because my problem was fixed by
changing the relevant line:
return super(Member, self).__str__()
into an explicit copy of the code which I want to run there (defined
in the super()
of Django’s Model
class):
return str('%s object' % self.__class__.__name__)
I added a section about “Member objects” in welfare.specs.households to cover it.
Moving from fabric to invoke¶
I wanted to get the Lino test suite pass on Travis CI. It took me
almost the whole day. Lots of subtle changes in atelier
.
The main problem was to understand how invoke does configuration and to decide how to store current_project and how to define configration variables. I added an invoke.yaml to most projects.
Many more inv
commands now work.
fab bd
was the easiest: it simply wasn’t yet imported into the
atelier.tasks
module.
There was a bug in atelier.utils.confirm()
which made it fail
under Python 2 when the prompt was a unicode string with non-ascii
characters.
# -*- coding: UTF-8 -*-
from __future__ import unicode_literals
from atelier.utils import confirm
confirm("Ein schöner Tag?")
Above script gives:
Traceback (most recent call last):
File "0324.py", line 4, in <module>
confirm("Ein schöner Tag?")
File "/atelier/atelier/utils.py", line 213, in confirm
ln = input(prompt)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 7: ordinal not in range(128)
A simplified version:
# -*- coding: UTF-8 -*-
from __future__ import unicode_literals
from atelier.utils import confirm
confirm("Ein schöner Tag?")
But finally I can not do:
$ pp inv clean
$ pp inv prep test bd pd
I released Atelier 0.0.20 to PyPI (needed because Travis CI uses the released version)
And the reward: the Lino test suite now passes on Travis CI using invoke instead of fabric! At least for Python 2.