20101130

UnicodeDecodeError

Dann hier noch ein UnicodeDecodeError, der nicht auf dem Developtment Server passiert:

Traceback (most recent call last):
  File "/var/snapshots/django/django/core/handlers/wsgi.py", line 265, in __call__
    response = self.get_response(request)
  File "/var/snapshots/django/django/core/handlers/base.py", line 160, in get_response
    response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
  File "/var/snapshots/django/django/core/handlers/base.py", line 109, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
  File "/var/snapshots/lino/lino/ui/extjs/ext_ui.py", line 900, in api_element_view
    error=e))
  File "/var/snapshots/django/django/utils/translation/__init__.py", line 62, in ugettext
    return _trans.ugettext(message)
  File "/var/snapshots/django/django/utils/translation/trans_real.py", line 283, in ugettext
    return do_translate(message, 'ugettext')
  File "/var/snapshots/django/django/utils/translation/trans_real.py", line 269, in do_translate
    result = getattr(t, translation_function)(eol_message)
  File "/usr/lib/python2.5/gettext.py", line 404, in ugettext
    return unicode(message)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe9 in position 96: ordinal not in range(128)

Der Fehler tritt auf in Zeile 900:

   try:
       return a.run(self,elem)
   except Exception,e:
       msg = _("Action %(action)s failed for %(record)s: %(error)s" % dict(
           action=a,
           record=obj2str(elem),
           error=e))
       logger.info(msg)
       logger.exception(e)
       return error_response(e,msg)


  File "/usr/lib/python2.5/zipfile.py", line 339, in __init__
    self.fp = open(file, modeDict[mode])
IOError: [Errno 2] Aucun fichier ou r\xe9pertoire de ce type: u'/usr/local/lino.../fr/contracts/Konvention.odt'

Hier ein kleines Skript, das den Fehler reproduziert:

import locale

for locale_setting in 'fr_BE','de_BE':
    locale.setlocale(locale.LC_ALL,locale_setting)
    try:
        open('nonexisting_file')
    except Exception,e:
        print e

Wenn ich das ausführe, kommt folgendes:

lsaffre@lino:~$ python tmp.py
[Errno 2] Aucun fichier ou r▒pertoire de ce type: 'nonexisting_file'
[Errno 2] Datei oder Verzeichnis nicht gefunden: 'nonexisting_file'

Da steht wohlbemerkt nicht “répertoire”, sondern “r▒pertoire”. Bis auf weiteres nehme ich an, dass das ein Bug in Python sein könnte. Das kommt nach docs/tickets/17.

Der Auslöser der Fehlermeldung war ein Bug in Lino (er suchte nach dem Template im fr-Verzeichnis obwohl es dort kein Template gibt), der ist jetzt behoben und folglich kann docs/tickets/17 zur Zeit warten.

Localized templates in appy.pod

Lino now sets Python’s locale.setlocale to the document’s language while rendering an appy.pod template. So now I can render a datetime.date object using the following expression:

self.date_decided.strftime('%A, %d. %B %Y')

In a German document this will render a String of type “Sonntag, 28. November 2010”, in French it gives “dimanche, 28. novembre 2010”.

Unfortunately that’s only almost correct; in French there must be no dot after the day’s number.

I tried the following:

def datefmt(d):
    return d.strftime(locale.nl_langinfo(locale.D_FMT))

But nl_langinfo is not available on all systems.

So now I have my own little localization database extension in lino.mixins.printable

Fuzzy side effects on date fields

Worked on the following bug report:

  • Ich hatte applies_from in einem Vertrag mit Hilfe des Kalenders auf 3. Januar 2010 gesetzt und gespeichert:

    201011-27 06:57:28 INFO dblogger : Contract #1 (Vertrag Nr. 1) modified by lsaffre : applies_from : None –> 2011-03-01

    Danach das Feld duration von 0 auf leer gesetzt:

    201011-27 06:58:42 INFO dblogger : Contract #1 (Vertrag Nr. 1) modified by lsaffre :
    duration : 0 --> None
    applies_from : 2011-03-01 --> 2011-01-03
    
It’s because a detail form submits the value as '03.01.2010'
while the grid submits '2010-01-03T00:00:00'.

In der Grid sind DatenFelder als Ext.grid.DateColumn definiert. Auszug aus dem ExtJS-Code:

Ext.grid.DateColumn = Ext.extend(Ext.grid.Column, {

    format : 'm/d/Y',
    constructor: function(cfg){
        Ext.grid.DateColumn.superclass.constructor.call(this, cfg);
        this.renderer = Ext.util.Format.dateRenderer(this.format);
    }
});

Konfigurationsparameter der Kolonne:

{ xtype: "datecolumn", format: "d.m.Y", editable: true,
  filter: { type: "date" },
  editor: last_login38 }

Und der Editor (last_login38) ist mit xtype=’datefield’ definiert:

last_login38 : { xtype: "datefield", format: "d.m.Y",... }

Aber das alles wird in Ext.form.BasicForm.submit gar nicht benutzt, der AJAX-Request schickt einfach die Strings, die in den DateField-Elementen stehen ab.

Eigentlich ist es das ja auch was ich will: Datenfelder sollen gefälligst im von mir gewählten Format submittet werden, und nicht mit browserspezifischen Strings.

Also eigentlich ist es meine Lino.GridPanel.on_afteredit, das ich ändern muss! Und dann brauche ich den fuzzy dateparser gar nicht mehr.

Statt meine Lino.GridPanel.on_afteredit zu ändern (das ist nämlich gar nicht so einfach) könnte ich auch mal schauen, ob der ux.grid.RowEditor nicht sowieso viel besser wäre: http://edspencer.net/2009/09/using-the-extjs-row-editor.html

Ja, das ging leichter als ich gedacht hatte… nur: auch der RowEditor verwendet nicht das im DateField Format, um Datumsfelder abzuschicken.

Den RowEditor muss ich mir merken falls das irgendweann mal interessant wird, aber bis auf weiteres bleibe ich wenn möglich lieber noch bei der “primitiven” Methode, jede Zelle einzeln zu submitten.

Der Tipp Using date fields in the Ext.grid.GridPanel and Ext.grid.EditorGridPanel von Eugen Hartmann hat mir geholfen zu verstehen, wo das fehlende Puzzlestück war: Auch die Felder eines Stores haben auch ein Attribut dateFormat! Das wird von ExtJS nur beim Laden des Stores benutzt. Danke für den Artikel, Eugen. Aber dass du am Ende in deinem afteredit-Handling das Datum einfach als formatierten String im Record speicherst, das ist imho nicht richtig. Ich konvertiere die Daten erst beim Abschicken:

var p = {};
for(k in e.record.getChanges()) {
    var v = e.record.get(k);
    var f = e.record.fields.get(k);
    if (f.type.type == 'date') {
        p[k] = Ext.util.Format.date(v, f.dateFormat);
    }else{
        p[k] = v;
    }
}

17.40 Uhr, der Bug ist endlich behoben. Den fuzzy dateparser benutze ich momentan gar nicht. Allerdings darf man reports.Report.date_format momentan nicht verändern, das muss vorläufig auf 'd.m.Y' stehen bleiben, denn ich habe noch keinen Konvertierer, der dieses Format (in der ExtJS-Syntax) ins Format von strftime konvertiert.

17.55 Uhr: oder besser gesagt: wenn man das Datumsformat ändern will, muss man es an drei stellen ändern, die jetzt immerhin alle untereinander im Modul lino zentralisiert sind.

Check-in und nochmal ein update der Version 0.8.13 in Eupen.

Noch Änderungen:

  • lino.modlib.contacts.utils.name2kw() erkannte diverse Namenspräfixe noch nicht (‘van der’, ‘vom’, ‘von’
  • Neues Feld CompanyType.contract_type. Das wird erstmals dynamisch in eine bestehende Klasse eingepflanzt. Die Technik kannte ich noch nicht. Funktioniert! Cool!
  • Feld Company.type war noch nicht sichtbar.
  • Aber Contract.type wird jetzt noch nicht automatisch ausgefüllt, weil Django sich weigert, den Vertrag ohne ausgefüllte Vertragsart anzunehmen. (wenn CompanyType.contract_type ausgefüllt ist).
  • bug fized: “IntegrityError: contacts_company.street may not be NULL”
  • Contract.type wurde noch nicht automatisch ausgefüllt (wenn CompanyType.contract_type ausgefüllt ist), weil man mit Django ein non-nullable field nicht auf None setzen darf.
  • Die “Konsole” zum Anzeigen von Meldungen nimmt jetzt weniger unnützen Platz (ist jetzt immer collapsed und die Meldungen werden im Title angezeigt).

01.12.10 4 Uhr : Check-in und nochmal ein update der Version 0.8.13 in Eupen.