======================== Monday, January 25, 2016 ======================== Ticket :ticket:`741`: today Gerd and I decided to make a minor release in Eupen, actually only for :ticket:`730`. As a preparative step I wanted to have the test suites pass, including build of the Sphinx document trees. This turned out to be quite some pain, mostly caused by ticket :ticket:`36`. The futurize script and the damage done ======================================= While building the Welfare docs (:file:`/welfare/docs_de/aids.rst:174:`) there was a problem. The Sphinx build says:: Exception: unicode argument expected, got 'str' in code: from django.utils import translation from lino.utils.xmlgen.html import E ses = rt.login('alicia') translation.activate('de') for msg in settings.SITE.get_welcome_messages(ses): print(tostring(msg)) I tried to reproduce this problem here in the blog (and testing it with ``python -m doctest docs/blog/2016/0125.rst)``. First attempt: >>> from lino import startup >>> startup('lino_welfare.projects.std.settings.demo') >>> from django.conf import settings >>> from django.utils import translation >>> from lino.api import rt >>> from lino.utils.xmlgen.html import E >>> ses = rt.login('alicia') >>> translation.activate('de') >>> for msg in settings.SITE.get_welcome_messages(ses): ... print(tostring(msg)) Du bist beschäftigt in Consultation mit COLLARD Charlotte (118) (Versammlung beenden). Du hast 2 Einträge in Zu bestätigende Hilfebeschlüsse. Du hast 3 offene Datenkontrollen. But that code passes. The problem is not easily reproducible. Next attempt: >>> from lino import startup >>> startup('lino_welfare.projects.std.settings.demo') >>> from django.conf import settings >>> from lino.api import rt >>> context = dict() >>> context.update(globals()) >>> code = """\ ... from django.utils import translation ... from lino.utils.xmlgen.html import E ... ses = rt.login('alicia') ... translation.activate('de') ... for msg in settings.SITE.get_welcome_messages(ses): ... print(tostring(msg)) ... """ >>> exec(code, context) Du bist beschäftigt in Consultation mit COLLARD Charlotte (118) (Versammlung beenden). Du hast 2 Einträge in Zu bestätigende Hilfebeschlüsse. Du hast 3 offene Datenkontrollen. That code also passes. And here comes a third (passing) snippet. I don't remember having wanted a test to *fail* as much as today. >>> from builtins import str >>> from lino import startup >>> startup('lino_welfare.projects.std.settings.demo') >>> from django.conf import settings >>> from lino.api import rt >>> context = dict() >>> context.update(settings=settings) >>> context.update(rt=rt) >>> code = """\ ... from django.utils import translation ... from lino.utils.xmlgen.html import E ... with translation.override('en'): ... ses = rt.login('alicia') ... translation.activate('de') ... for msg in settings.SITE.get_welcome_messages(ses): ... print(tostring(msg)) ... """ >>> code = str(code) >>> exec(code, context) Du bist beschäftigt in Consultation mit COLLARD Charlotte (118) (Versammlung beenden). Du hast 2 Einträge in Zu bestätigende Hilfebeschlüsse. Du hast 3 offene Datenkontrollen. But here it is finally: >>> from lino import startup >>> startup('lino_welfare.projects.std.settings.demo') >>> from django.conf import settings >>> from lino.api import rt >>> context = dict() >>> context.update(settings=settings) >>> context.update(rt=rt) >>> code = """\ ... from django.utils import translation ... from lino.utils.xmlgen.html import E ... with translation.override('en'): ... ses = rt.login('alicia') ... translation.activate('de') ... for msg in settings.SITE.get_welcome_messages(ses): ... ln = tostring(msg) ... print(ln) # this is line 8 of the string ... """ >>> import sys >>> from io import StringIO >>> old = sys.stdout >>> buffer = StringIO() >>> sys.stdout = buffer >>> exec(code, context) >>> sys.stdout = old Testing above snippet reports a failure:: Failed example: exec(code, context) Exception raised: Traceback (most recent call last): File "/usr/lib/python2.7/doctest.py", line 1316, in __run compileflags, 1) in test.globs File "", line 1, in exec(code, context) File "", line 8, in TypeError: unicode argument expected, got 'str' But what does it mean? Above code comes from :class:`Py2rstDirective ` which uses `StringIO `_ class. I can simplify above snippet and reproduce the error by running the following script directly: .. literalinclude:: 0125a.py The explanation is that we cannot simply convert:: from StringIO import StringIO into:: from io import StringIO And here a working version: .. literalinclude:: 0125b.py This turns out to be another example of the damage caused by the `futurize `_ script. BTW there was another bug in :func:`atelier.utils.confirm`:: ln = raw_input(prompt) Had become:: ln = eval(input(prompt)) This was probably also introduced by `futurize `_. Though actually git shows that it was first changed (correctly) to:: ln = input(prompt) and only in the next commit it was wrapped into `eval`. Actually the title is wrong: it is not `futurize `_ the guilty, but our uncomplete test suite. A new user's guide for Lino Welfare in French ============================================= Thanks to Mathieu who contributed a second pdf user guide in French (see for :ref:`welfare.fr`). Duplicate log messages ====================== During the last weeks I often observed that logger messages were duplicated or even tripled. Actually this had started after our upgrade to Django 1.8 and 1.9. Now I had a closer look at this. It is probably related to the fact that Django imports our :xfile:`settings.py` module twice, sometimes even three times. The :func:`lino.utils.log.configure` function always had the following lines:: if len(logging.getLogger().handlers) != 0: msg = "Not changing the existing logging configuration." logging.info(msg) return And it seems that this test no longer works correctly. After reading `this `_ I tried the trick of setting an attribute of the logger module itself as described there. Hmm.