Ok, donc le contexte général de cette question est que j'essaie de créer une classe de dictionnaire personnalisée qui va créer une représentation sous forme de chaîne du dictionnaire qui est juste une recherche de l'une des valeurs (qui sont toutes des valeurs Unicode). Dans le code réel, selon une logique interne, l'une des clés est choisie comme valeur par défaut pour la recherche, de sorte que unicode(dict_obj)
renverra une seule valeur dans le dictionnaire comme u'Some value'
ou si la valeur n'existe pas pour le courant clé par défaut: u'None'
Erreurs Unicode sur les objets proxy de sécurité zope
Cette fonctionnalité fonctionne sans problème. Le vrai problème réside dans l'utilisation dans l'application à partir des modèles de pages zope qui enveloppent l'objet dans un proxy de sécurité. L'objet mandaté ne se comporte pas comme l'objet original.
Voici le code bouilli vers le bas de la classe dictionnaire personnalisé:
class IDefaultKeyDict(Interface):
def __unicode__():
"""Create a unicode representation of the dictionary."""
def __str__():
"""Create a string representation of the dictionary."""
class DefaultKeyDict(dict):
"""A custom dictionary for handling default values"""
implements(IDefaultKeyDict)
def __init__(self, default, *args, **kwargs):
super(DefaultKeyDict, self).__init__(*args, **kwargs)
self._default = default
def __unicode__(self):
print "In DefaultKeyDict.__unicode__"
key = self.get_current_default()
result = self.get(key)
return unicode(result)
def __str__(self):
print "In DefaultKeyDict.__str__"
return unicode(self).encode('utf-8')
def get_current_default(self):
return self._default
Et les autorisations ZCML associées pour cette classe:
<class class=".utils.DefaultKeyDict">
<require
interface=".utils.IDefaultKeyDict"
permission="zope.View" />
</class>
J'ai laissé les déclarations d'impression dans les deux __unicode__
et __str__
méthodes pour montrer le comportement différent avec les objets mandatés. créant ainsi une classe dictionnaire factice avec une clé par défaut prédéfini:
>>> dummy = DefaultKeyDict(u'key2', {u'key1': u'Normal ascii text', u'key2': u'Espa\xf1ol'})
>>> dummy
{u'key2': u'Espa\xf1ol', u'key1': u'Normal ascii text'}
>>> str(dummy)
In DefaultKeyDict.__str__
In DefaultKeyDict.__unicode__
'Espa\xc3\xb1ol'
>>> unicode(dummy)
In DefaultKeyDict.__unicode__
u'Espa\xf1ol'
>>> print dummy
In DefaultKeyDict.__str__
In DefaultKeyDict.__unicode__
Español
Tout fonctionne comme prévu. Maintenant, je peux envelopper l'objet dans un proxy de sécurité de l'emballage zope.security
et faire les mêmes tests pour montrer l'erreur:
>>> from zope.security.checker import ProxyFactory
>>> prox = ProxyFactory(dummy)
>>> prox
{u'key2': u'Espa\xf1ol', u'key1': u'Normal ascii text'}
>>> type(prox)
<type 'zope.security._proxy._Proxy'>
>>> str(prox)
In DefaultKeyDict.__str__
In DefaultKeyDict.__unicode__
'Espa\xc3\xb1ol'
>>> unicode(prox)
In DefaultKeyDict.__str__
In DefaultKeyDict.__unicode__
*** UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 4: ordinal not in range(128)
Comme vous pouvez le voir, appeler unicode
sur l'objet approximé ne peut plus si elle contient des caractères spéciaux. Je peux voir l'objet proxy de zope.security
est principalement défini avec le code C et je ne suis pas du tout familier avec l'API C Python, mais il semble que les méthodes __str__
et __repr__
sont définies dans le code C mais pas __unicode__
. Donc, pour moi, ce qui semble se passer est que quand il essaie de créer une représentation unicode de cet objet proxy, au lieu d'appeler directement la méthode __unicode__
, il appelle la méthode __str__
(comme vous pouvez le voir sur les dernières instructions d'impression ci-dessus)), qui renvoie une chaîne de caractères codée utf-8
, mais qui est ensuite convertie en unicode (en utilisant le codage ascii par défaut). Donc, ce qui se passe semble être l'équivalent de ceci:
>>> unicode(prox.__str__())
In DefaultKeyDict.__str__
In DefaultKeyDict.__unicode__
*** UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 4: ordinal not in range(128)
cours Alors elle se traduira par une UnicodeDecodeError dans ce cas, en essayant de décoder une chaîne utf-8
avec ascii. Comme prévu, si je pouvais spécifier le codage de utf-8
il n'y aurait pas de problème.
>>> unicode(prox.__str__(), encoding='utf-8')
In DefaultKeyDict.__str__
In DefaultKeyDict.__unicode__
u'Espa\xf1ol'
Mais je ne peux pas changer cela, puisque nous parlons des zope.pagetemplate
et zope.tales
paquets qui créent la représentation unicode de tous types d'objets, et ils semblent toujours travailler avec la sécurité des objets approximé (à partir de zope.security
). De plus, il n'y a aucun problème à appeler la méthode __unicode__
directement sur l'objet.
>>> prox.__unicode__()
In DefaultKeyDict.__unicode__
u'Espa\xf1ol'
Donc, le vrai problème est que unicode(prox)
appelle la méthode __str__
. Cela fait un moment que je tourne autour de ça et je ne sais pas où aller maintenant.Toute idée serait très appréciée.
Votre analyse est correcte et l'emballage ne prend pas en charge un crochet Unicode; en partie parce que le * python 2 C-API n'a jamais défini un emplacement pour cela *. L'encapsuleur doit définir un attribut '__unicode__' sur le type et il devra gérer le cas où l'objet encapsulé n'a pas ce type de hook lui-même. Tricky, qui est probablement pourquoi il n'a pas encore été abordé. –
Ceci est certainement un bug; l'implémentation Python gère __unicode__'; seule l'implémentation C est manquante. N'hésitez pas à le signaler en tant que tel à https://bugs.launchpad.net/zope.security –
@MartijnPieters merci pour l'aperçu de l'API C-Python. Cela rend les choses plus difficiles que je ne le pensais au départ. Au moins pour l'instant, le bug est rapporté sur https://bugs.launchpad.net/zope.security/+bug/1367566 Plus tard, j'ai trouvé un bug lié déjà signalé dans le paquet 'zope.proxy', mais il semble être un implémentation C différente de la classe proxy. https://bugs.launchpad.net/zope.proxy/+bug/1262702 –