20110615¶
Noch ein UnicodeDecodeError¶
Gestern trat ein paarmal folgender Fehler auf bei dem Kunden, dem ich die neue Version installiert hatte:
Traceback (most recent call last):
File "/var/snapshots/django/django/core/handlers/base.py", line 111, in get_response
response = callback(request, *callback_args, **callback_kwargs)
File "/var/snapshots/lino/lino/ui/extjs3/ext_ui.py", line 1118, in api_element_view
error=e)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 52: ordinal not in range(128)
Und hier der dazugehörige Code:
try:
return a.run(ar,elem)
except Exception,e:
msg = _("Action %(action)s failed for %(record)s: %(error)s") % dict(
action=a,
record=obj2str(elem),
error=e) ## lino 1118
logger.warning(msg)
logger.exception(e)
return error_response(e,msg)
Also fast die gleiche Lektion wie vor 2 Wochen: “When you pass more than one formatting argument to a logger function, and one of them is a unicode string, then the other argument(s) may not be bytestrings containing non-ascii chars.”
Mit der Verallgemeinerung, dass das für alle
String-Formatierungen (Operator %
) gilt, und zwar
sowohl für Positionsargumente wie für Keyword-Argumente.
Der Fehler ist reproduzierbar, indem ich auf Vertrag # 88 gehe und dort Drucken klicke.
Beim Einchecken und Testen entdecke ich, dass die Sache noch perverser ist als gedacht.
Wenn ich die Exception nicht selber abfange, dann tut Django das, und der kann es. Der schickt dann dem Benutzer eine freundliche 500-Meldung und den Systemverwaltern (setting:`ADMINS) eine E-Mail, dank derer ich erstmals überhaupt die Exception an sich sehe:
Traceback (most recent call last):
File "/var/snapshots/django/django/core/handlers/base.py", line 111, in get_response
response = callback(request, *callback_args, **callback_kwargs)
File "/var/snapshots/lino/lino/ui/extjs3/ext_ui.py", line 1111, in api_element_view
return a.run(ar,elem)
File "/var/snapshots/lino/lino/mixins/printable.py", line 407, in run
bm.build(self,elem)
File "/var/snapshots/lino/lino/mixins/printable.py", line 186, in build
tpl_leaf = self.get_template_leaf(action,elem)
File "/var/snapshots/lino/lino/mixins/printable.py", line 162, in get_template_leaf
tpls = action.get_print_templates(self,elem)
File "/var/snapshots/lino/lino/mixins/printable.py", line 399, in get_print_templates
return elem.get_print_templates(bm,self)
File "/var/snapshots/lino/lino/mixins/printable.py", line 610, in get_print_templates
(ptype.__class__.__name__,ptype,bm.template_ext))
Exception: Invalid template configured for ContractType "Art.60§7 intern". Expected filename ending with '.odt'.
Der besagte Code ist:
if not ptype.template.endswith(bm.template_ext):
raise Exception(
"Invalid template configured for %s \"%s\". Expected filename ending with '%s'." %
(ptype.__class__.__name__,ptype,bm.template_ext))
Also das “§”-Zeichen in “Art.60§7 intern” ist der Auslöser.
Was ich noch nicht wusste: es gibt Python issue #2517, : Eine Exception mit einem Unicode-String führt zumindest in Python 2.6 noch allgemein an vielen Stellen zu Problemen.
Lektion : Exceptions dürfen ausschließlich ASCII-Code enthalten und folglich auch nicht internationalisert sein. Im obigen Beispiel reicht:
if not ptype.template.endswith(bm.template_ext):
raise Exception(
"Invalid template configured for %s %r. Expected filename ending with %r." %
(ptype.__class__.__name__,unicode(ptype),bm.template_ext))
Dass ich meine Instanz ptype noch selber in ein unicode() einpacken muss, ist unlogisch und liegt daran, dass Djangos Model.__repr__() unter Umständen einen Unicode-String zurückgeben kann. Ich habe das in Django ticket #16261 gemeldet, aber das werden die wohl kaum akzeptieren, weil das ziemlich unkompatibel wäre.
Nachdem mir das klargeworden ist, habe ich noch ein Problemchen entdeckt:
in meiner lino.utils.log.configure()
muss ich den AdminEmailHandler
nicht nur den Logger django
hinzufügen, sondern auch meinem Logger lino
.
Neuer Testcase lino.apps.dsbe.tests.dsbe_tests.test01b()
.
Voilà. Jetzt bin ich zufrieden: Der Bentuzer kriegt eine Meldung “Action Drucken failed for Contract #88 (Vertrag # 88). An error report has been sent to the system administrator.” und die Systemverwalter eine E-Mail mit detaillierter Fehlerbeschreibung, unter anderem “Invalid template configured for ContractType u’Art.60xa77 intern’. Expected filename ending with ‘.odt’.”
All das ist die Checkin-Serie 20110615, die noch mit nach https://www.lino-framework.org/releases/2011/0613.html reinkommt.
Viele kleine Benutzerwünsche¶
Person.get_full_name()
now renders thePerson.last_name
in all-uppercase lettersPerson.address_person_lines()
now usesPerson.get_full_name()
.Person.get_full_name()
now includes asalutation
.
New field
PersonGroup.ref_name
used for ordering.New field
Person.duties_person
Field
Person.native_language
replaced byLanguageKnowledge.native
New function
lino.utils.babel.dtomy()
available inlino.mixins.printable.AppyBuildMethod
.
Erstes Check-in der Serie 20110615b um 19.35 wegen Feierabend.
Release 1.1.17¶
Um die bereits erfassten Muttersprachen zu übernehmen, musste ich mir was Neues einfallen lassen. Erstens eine kleine Liste der bestehenden Fälle:
>>> import codecs
>>> from lino.apps.dsbe.models import Person
>>> f = codecs.open('nl.txt','w',encoding='utf-8')
>>> f.write('\n'.join(["%s : %s + %s" % (unicode(p),p.native_language,', '.join([unicode(x) for x in p.languageknowledge_set.all()])) for p in qs]))
>>> f.close()
Aber vor allem: Personen, die bisher in native_language etwas stehen haben,
sollen stattdessen jetzt einen Eintrag in LanguageKnowledge
haben.
Manchmal existiert der schon (und muss dann nur native=True
gesetzt kriegen
und manchmal nicht (und muss dann erstellt werden ohne Angaben für spoken und written)
Und weil die evtl. bestehenden LanguageKnowledge-Records
ja noch gar nicht gespeichert worden sind während der objects(), kann ich in
der create_contacts_person() nicht schauen,
ob schon ein Eintrag für die Muttersprache existerte oder nicht.
Also muss ich den Kram in eine Liste NATIVES einsammeln und erst
später speichern, wenn alles andere eingelesen ist.
Deshalb die neue Funktion after_load, die vom lino.utils.dpy.Deserializer
nach dem Speichern der objects ausgeführt wird (wenn sie existiert).
Und dann noch was cooles Neues: Modul :mod: lino.apps.dsbe.migrations. Um die Konvertierung nicht manuell in die Dump-Datei beim Kunden reinkopieren zu müssen, habe ich ein neues System ausgedacht, damit ich die Migration einmal schreiben kann und die Dump-Datei sie sich automagisch installiert. Ganz automagisch geht das allerdings noch nicht: die entsprechenden Zeilen müssen manuell rauskommentiert werden.
Weiteres Check-in der Serie 20110615b zwecks Installation beim Kunden.
Released https://www.lino-framework.org/releases/2011/0615.html.