[F] views: fix 2 unicode errors
1. You can now use valid unicode strings in ValidationError exception.
Previously, if 'err' contains unicode, UnicodeDecodeError was raised by format_errors()
>>> templstr = '<li>%s</li>\n'
>>> e = ValidationError(None, {None: u'oué, une exception en unicode!'})
>>> templstr % e
'<li>None (None): ou\xc3\xa9, une exception en unicode!</li>\n'
>>> templstr = u'<li>%s</li>\n'
>>> templstr % e
u'<li>None (None): ou\xe9, une exception en unicode!</li>\n'
2. The message of an Exception can contains unicode. But it now properly managed by “informal” string representation.
We can easily fix the problem by using the Exception.message attribute that still contains the original message.
>>> a = AssertionError(u'séfdsdf')
>>> a.message
u's\xe9fdsdf'
>>> str(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 1: ordinal not in range(128)
>>> a = ValueError(u'fsdfsdéfsdfs')
>>> str(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 6: ordinal not in range(128)
>>> a
ValueError(u'fsdfsd\xe9fsdfs',)
>>> unicode(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 6: ordinal not in range(128)
>>> a.message
u'fsdfsd\xe9fsdfs'
Fondements du framework CubicWeb
=============================
Le moteur web d'cubicweb consiste en quelques classes grant un ensemble d'objets
chargs dynamiquement au lancement d'cubicweb. Ce sont ces objets dynamiques, issus
du modle ou de la librairie, qui construisent le site web final. Les diffrents
composants dynamiques sont par exemple :
* cot client et serveur
- les dfinitions d'entits, contenant la logique permettant la manipulation des
donnes de l'application
* cot client
- les *vues* , ou encore plus spcifiquement
- les boites
- l'en-tte et le pied de page
- les formulaires
- les gabarits de pages
- les *actions*
- les *controleurs*
* cot serveur
- les crochets de notification
- les vues de notification
Les diffrents composants du moteur sont :
* un frontal web (seul twisted disponible pour le moment), transparent du point
de vue des objets dynamiques
* un objet encapsulant la configuration
* un `vregistry` (`cubicweb.cwvreg`) contenant les objets chargs dynamiquements
Dtail de la procdure d'enregistrement
---------------------------------------
Au dmarage le `vregistry` ou base de registres inspecte un certain nombre de
rpertoires la recherche de dfinition de classes "compatible". Aprs une
procdure d'enregistrement les objets sont affects dans diffrents registres
afin d'tre ensuite slctionn dynamiquement pendant le fonctionnement de
l'application.
La classe de base de tout ces objets est la classe `AppRsetObject` (module
`cubicweb.common.appobject`).
API Python/RQL
--------------
Inspir de la db-api standard, avec un object Connection possdant les mthodes
cursor, rollback et commit principalement. La mthode importante est la mthode
`execute` du curseur :
`execute(rqlstring, args=None, eid_key=None, build_descr=True)`
:rqlstring: la requte rql xcuter (unicode)
:args: si la requte contient des substitutions, un dictionnaire contenant les
valeurs utiliser
:eid_key:
un dtail d'implmentation du cache de requtes RQL fait que si une substitution est
utilise pour introduire un eid *levant des ambiguits dans la rsolution de
type de la requte*, il faut spcifier par cet argument la cl correspondante
dans le dictionnaire
C'est l'objet Connection qui possde les mthodes classiques `commit` et
`rollback`. Vous ne *devriez jamais avoir les utiliser* lors du dveloppement
d'interface web sur la base du framework CubicWeb tant donn que la fin de la
transaction est dtermine par celui-ci en fonction du succs d'xcution de la
requte.
NOTE : lors de l'xcution de requtes de modification (SET,INSERT,DELETE), si une
requte gnre une erreur lie la scurit, un rollback est systmatiquement
effectue sur la transaction courante.
La classe `Request` (`cubicweb.web`)
---------------------------------
Une instance de requte est cre lorsque une requte HTTP est transmise au
serveur web. Elle contient des informations telles que les paramtres de
formulaires, l'utilisateur connect, etc.
**De manire plus gnrale une requte reprsente une demande d'un utilisateur,
que se soit par HTTP ou non (on parle galement de requte rql cot serveur par
exemple)**
Une instance de la classe `Request` possde les attributs :
* `user`, instance de`cubicweb.common.utils.User` correspondant l'utilisateur
connect
* `form`, dictionaire contenant les valeurs de formulaire web
* `encoding`, l'encodage de caractre utiliser dans la rponse
Mais encore :
:Gestion des donnes de session:
* `session_data()`, retourne un dictionaire contenant l'intgralit des
donnes de la session
* `get_session_data(key, default=None)`, retourne la valeur associe
la cl ou la valeur `default` si la cl n'est pas dfinie
* `set_session_data(key, value)`, associe une valeur une cl
* `del_session_data(key)`, supprime la valeur associ une cl
:Gestion de cookie:
* `get_cookie()`, retourne un dictionnaire contenant la valeur de l'entte
HTTP 'Cookie'
* `set_cookie(cookie, key, maxage=300)`, ajoute un en-tte HTTP `Set-Cookie`,
avec une dure de vie 5 minutes par dfault (`maxage` = None donne un cooke
*de session"* expirant quand l'utilisateur ferme son navigateur
* `remove_cookie(cookie, key)`, fait expirer une valeur
:Gestion d'URL:
* `url()`, retourne l'url complte de la requte HTTP
* `base_url()`, retourne l'url de la racine de l'application
* `relative_path()`, retourne chemin relatif de la requte
:Et encore...:
* `set_content_type(content_type, filename=None)`, place l'en-tte HTTP
'Content-Type'
* `get_header(header)`, retourne la valeur associ un en-tte HTTP
arbitraire de la requte
* `set_header(header, value)`, ajoute un en-tte HTTP arbitraire dans la
rponse
* `cursor()` retourne un curseur RQL sur la session
* `execute(*args, **kwargs)`, raccourci vers .cursor().execute()
* `property_value(key)`, gestion des proprits (`CWProperty`)
* le dictionaire `data` pour stocker des donnes pour partager de
l'information entre les composants *durant l'xcution de la requte*.
A noter que cette classe est en ralit abstraite et qu'une implmentation
concrte sera fournie par le *frontend* web utilis (en l'occurent *twisted*
aujourd'hui). Enfin pour les vues ou autres qui sont xcuts cot serveur,
la majeure partie de l'interface de `Request` est dfinie sur la session
associe au client.
La classe `AppObject`
---------------------
En gnral :
* on n'hrite pas directement des cette classe mais plutt d'une classe
plus spcifique comme par exemple `AnyEntity`, `EntityView`, `AnyRsetView`,
`Action`...
* pour tre enregistrable, un classe fille doit dfinir son registre (attribut
`__registry__`) et son identifiant (attribut `id`). Gnralement on n'a pas
s'occuper du registre, uniquement de l'identifiant `id` :)
On trouve un certain nombre d'attributs et de mthodes dfinis dans cette classe
et donc commune tous les objets de l'application :
A l'enregistrement, les attributs suivants sont ajouts dynamiquement aux
*classes* filles:
* `vreg`, le `vregistry` de l'application
* `schema`, le schma de l'application
* `config`, la configuration de l'application
On trouve galement sur les instances les attributs :
* `req`, instance de `Request`
* `rset`, le "result set" associ l'objet le cas chant
* `cursor`, curseur rql sur la session
:Gestion d'URL:
* `build_url(method=None, **kwargs)`, retourne une URL absolue construites
partir des arguments donns. Le *controleur* devant grer la rponse
peut-tre spcifi via l'argument spcial `method` (le branchement est
thoriquement bien effectu automatiquement :).
* `datadir_url()`, retourne l'url du rpertoire de donnes de l'application
(contenant les fichiers statiques tels que les images, css, js...)
* `base_url()`, raccourci sur `req.base_url()`
* `url_quote(value)`, version *unicode safe* de de la fonction `urllib.quote`
:Manipulation de donnes:
* `etype_rset(etype, size=1)`, raccourci vers `vreg.etype_rset()`
* `eid_rset(eid, rql=None, descr=True)`, retourne un objet result set pour
l'eid donn
* `entity(row, col=0)`, retourne l'entit correspondant la position donnes
du "result set" associ l'objet
* `complete_entity(row, col=0, skip_bytes=True)`, quivalent `entity` mais
appelle galement la mthode `complete()` sur l'entit avant de la retourner
:Formattage de donnes:
* `format_date(date, date_format=None, time=False)`
* `format_time(time)`,
:Et encore...:
* `external_resource(rid, default=_MARKER)`, accde une valeur dfinie dans
le fichier de configuration `external_resource`
* `tal_render(template, variables)`,
**NOTE IMPORTANTE**
Lorsqu'on hrite d'`AppObject` (mme indirectement), il faut **toujours**
utiliser **super()** pour rcuprer les mthodes et attributs des classes
parentes, et pas passer par l'identifiant de classe parente directement.
(sous peine de tomber sur des bugs bizarres lors du rechargement automatique
des vues). Par exemple, plutt que d'crire::
class Truc(PrimaryView):
def f(self, arg1):
PrimaryView.f(self, arg1)
Il faut crire::
class Truc(PrimaryView):
def f(self, arg1):
super(Truc, self).f(arg1)
XXX FILLME diagramme interaction application/controller/template/view