Ajout de methodes pour tester l'égalité d'objets ou d'attributs,

possibilité de fournir une valeur du bon type python à un attribut
test booléen sur s'attribut propagée à sa valeur.

Le teste d'égalité sur un attribut peut se faire avec la sérialisation de
l'attribut ou le type python qui le représente.
Le teste d'égalité sur les cransLdapObjet se fait sur le dn et ses attributs.
De plus, on peut aussi le testé avec un chaine de caractère :
 "host=freebox.crans.org" == MachineCrans(...) renvoie True ssi
MachineCrans(...) a l'attribut host, qu'il est globalement unique et vaut
freebox.crans.org

vala vala
This commit is contained in:
Valentin Samir 2014-02-13 22:34:00 +01:00
parent e9d092698a
commit ca170c19f4
2 changed files with 79 additions and 28 deletions

View file

@ -125,10 +125,11 @@ def attrify(val, attr, conn, Parent=None):
if isinstance(val, Attr): if isinstance(val, Attr):
return val return val
else: else:
if not isinstance(val, unicode): attr_classe = AttributeFactory.get(attr, fallback=Attr)
if not isinstance(val, unicode) and (attr_classe.python_type and not isinstance(val, attr_classe.python_type)):
cranslib.deprecated.usage("attrify ne devrait être appelé qu'avec des unicode (%r)" % val, level=3) cranslib.deprecated.usage("attrify ne devrait être appelé qu'avec des unicode (%r)" % val, level=3)
val = val.decode('utf-8') val = val.decode('utf-8')
return AttributeFactory.get(attr, fallback=Attr)(val, conn, Parent) return attr_classe(val, conn, Parent)
class AttrsDict(dict): class AttrsDict(dict):
@ -193,6 +194,7 @@ class Attr(object):
unique = False unique = False
#: Le nom de l'attribut dans le schéma LDAP #: Le nom de l'attribut dans le schéma LDAP
ldap_name = None ldap_name = None
python_type = None
"""La liste des droits qui suffisent à avoir le droit de modifier la valeur""" """La liste des droits qui suffisent à avoir le droit de modifier la valeur"""
can_modify = [nounou] can_modify = [nounou]
@ -213,6 +215,21 @@ class Attr(object):
self.parent = Parent self.parent = Parent
self.parse_value(val) self.parse_value(val)
def __eq__(self, item):
if isinstance(item, self.__class__):
return str(self) == str(item)
elif self.python_type and isinstance(item, self.python_type):
return self.value == item
elif isinstance(item, str):
return str(self) == item
elif isinstance(item, unicode):
return unicode(self) == item
else:
return False
def __nonzero__(self):
return self.value.__nonzero__()
def parse_value(self, val): def parse_value(self, val):
"""Transforme l'attribut pour travailler avec notre validateur """Transforme l'attribut pour travailler avec notre validateur
Le ldif est en dépendance car à certains endroits, il peut servir Le ldif est en dépendance car à certains endroits, il peut servir
@ -304,22 +321,28 @@ class objectClass(Attr):
class intAttr(Attr): class intAttr(Attr):
python_type = int
def parse_value(self, val): def parse_value(self, val):
if int(val) <= 0: if self.python_type(val) <= 0:
raise ValueError("Valeur entière invalide : %r" % val) raise ValueError("Valeur entière invalide : %r" % val)
self.value = int(val) self.value = self.python_type(val)
def __unicode__(self): def __unicode__(self):
return unicode(self.value) return unicode(self.value)
class boolAttr(Attr): class boolAttr(Attr):
python_type = bool
def parse_value(self, val): def parse_value(self, val):
if val.lower() in [u'true', u'ok']: if isinstance(val, self.python_type):
self.value = val
elif val.lower() in [u'true', u'ok']:
self.value = True self.value = True
elif val.lower() == u'false': elif val.lower() == u'false':
self.value = False self.value = False
elif isinstance(val, bool):
self.value = val
else: else:
raise ValueError("%r doit être un booléen !" % val) raise ValueError("%r doit être un booléen !" % val)
@ -414,7 +437,7 @@ class yearAttr(intAttr):
optional = True optional = True
def parse_value(self, annee): def parse_value(self, annee):
annee = int(annee) annee = self.python_type(annee)
if annee < 1998: if annee < 1998:
raise ValueError("Année invalide (%r)" % annee) raise ValueError("Année invalide (%r)" % annee)
self.value = annee self.value = annee
@ -598,6 +621,7 @@ class droits(Attr):
@crans_attribute @crans_attribute
class solde(Attr): class solde(Attr):
python_type = float
singlevalue = True singlevalue = True
optional = True optional = True
legend = u"Solde d'impression" legend = u"Solde d'impression"
@ -608,7 +632,7 @@ class solde(Attr):
# on évite les dépassements, sauf si on nous dit de ne pas vérifier # on évite les dépassements, sauf si on nous dit de ne pas vérifier
#if not (float(solde) >= config.impression.decouvert and float(solde) <= 1024.): #if not (float(solde) >= config.impression.decouvert and float(solde) <= 1024.):
# raise ValueError("Solde invalide: %r" % solde) # raise ValueError("Solde invalide: %r" % solde)
self.value = float(solde) self.value = self.python_type(solde)
def __unicode__(self): def __unicode__(self):
return u"%.2f" % self.value return u"%.2f" % self.value
@ -679,12 +703,13 @@ class ipHostNumber(Attr):
category = 'base_tech' category = 'base_tech'
can_modify = [nounou] can_modify = [nounou]
ldap_name = "ipHostNumber" ldap_name = "ipHostNumber"
python_type = netaddr.IPAddress
default = u'<automatique>' default = u'<automatique>'
def parse_value(self, ip): def parse_value(self, ip):
if ip == '<automatique>': if ip == '<automatique>':
ip = ip4_of_rid(str(self.parent['rid'][0])) ip = ip4_of_rid(str(self.parent['rid'][0]))
self.value = netaddr.IPAddress(ip) self.value = self.python_type(ip)
def __unicode__(self): def __unicode__(self):
return unicode(self.value) return unicode(self.value)
@ -699,18 +724,19 @@ class ip6HostNumber(Attr):
category = 'base_tech' category = 'base_tech'
can_modify = [nounou] can_modify = [nounou]
ldap_name = "ip6HostNumber" ldap_name = "ip6HostNumber"
python_type = netaddr.IPAddress
default = u'<automatique>' default = u'<automatique>'
def parse_value(self, ip6): def parse_value(self, ip6):
if ip6 == '<automatique>': if ip6 == '<automatique>':
ip6 = ip6_of_mac(str(self.parent['macAddress'][0]), int(str(self.parent['rid'][0]))) ip6 = ip6_of_mac(str(self.parent['macAddress'][0]), int(str(self.parent['rid'][0])))
self.value = netaddr.IPAddress(ip6) self.value = self.python_type(ip6)
def __unicode__(self): def __unicode__(self):
return unicode(self.value) return unicode(self.value)
@crans_attribute @crans_attribute
class mid(Attr): class mid(intAttr):
singlevalue = True singlevalue = True
optional = False optional = False
unique = True unique = True
@ -718,14 +744,8 @@ class mid(Attr):
category = 'id' category = 'id'
ldap_name = "mid" ldap_name = "mid"
def parse_value(self, mid):
self.value = int(mid)
def __unicode__(self):
return unicode(self.value)
@crans_attribute @crans_attribute
class rid(Attr): class rid(intAttr):
singlevalue = True singlevalue = True
optional = True optional = True
unique = True unique = True
@ -735,7 +755,7 @@ class rid(Attr):
ldap_name = "rid" ldap_name = "rid"
def parse_value(self, rid): def parse_value(self, rid):
rid = int(rid) rid = self.python_type(rid)
# On veut éviter les rid qui recoupent les ipv4 finissant par # On veut éviter les rid qui recoupent les ipv4 finissant par
# .0 ou .255 # .0 ou .255
@ -989,6 +1009,7 @@ class blacklist(Attr):
category = 'info' category = 'info'
can_modify = [nounou] can_modify = [nounou]
ldap_name = "blacklist" ldap_name = "blacklist"
python_type = dict
def parse_value(self, blacklist): def parse_value(self, blacklist):
bl_debut, bl_fin, bl_type, bl_comm = blacklist.split('$') bl_debut, bl_fin, bl_type, bl_comm = blacklist.split('$')
@ -1061,7 +1082,7 @@ class homepageAlias(Attr):
ldap_name = "homepageAlias" ldap_name = "homepageAlias"
@crans_attribute @crans_attribute
class charteMA(Attr): class charteMA(boolAttr):
singlevalue = True singlevalue = True
optional = True optional = True
legend= "Signale si l'adhérent a signé la charte de membres actifs" legend= "Signale si l'adhérent a signé la charte de membres actifs"
@ -1069,11 +1090,6 @@ class charteMA(Attr):
category = 'perso' category = 'perso'
ldap_name = "charteMA" ldap_name = "charteMA"
def parse_value(self, charteSignee):
if charteSignee.upper() not in [u"TRUE", u"FALSE"]:
raise ValueError("La charte MA est soit TRUE ou FALSE, pas %r" % charteSignee)
self.value = charteSignee.upper()
@crans_attribute @crans_attribute
class homeDirectory(Attr): class homeDirectory(Attr):
singlevalue=True singlevalue=True

View file

@ -162,6 +162,41 @@ class CransLdapObject(object):
nvals = [nldif[attr][vals.index(v)] for v in vals ] nvals = [nldif[attr][vals.index(v)] for v in vals ]
raise EnvironmentError("λv. str(Attr(v)) n'est peut-être pas une projection (ie non idempotente):", attr, nvals, vals) raise EnvironmentError("λv. str(Attr(v)) n'est peut-être pas une projection (ie non idempotente):", attr, nvals, vals)
def __eq__(self, obj):
if isinstance(obj, self.__class__):
if self.mode in ['w', 'rw']:
return self.dn == obj.dn and self._modifs == obj._modifs and self.attrs == obj.attrs
else:
return self.dn == obj.dn and self.attrs == obj.attrs
elif (isinstance(obj, str) or isinstance(obj, unicode)) and '=' in obj:
attr, val = obj.split('=', 1)
return attr in self.attrs.keys() and val in self[attr]
else:
return False
def __iter__(self):
if self.mode in [ 'w', 'rw' ]:
return self._modifs.__iter__()
else:
return self.attrs.__iter__()
def keys(self):
if self.mode in [ 'w', 'rw' ]:
return self._modifs.keys()
else:
return self.attrs.keys()
def values(self):
if self.mode in [ 'w', 'rw' ]:
return self._modifs.values()
else:
return self.attrs.values()
def items(self):
if self.mode in [ 'w', 'rw' ]:
return self._modifs.items()
else:
return self.attrs.items()
def display(self): def display(self):
print printing.sprint(self) print printing.sprint(self)
@ -543,7 +578,7 @@ class proprio(CransLdapObject):
super(proprio, self).__init__(conn, dn, mode, ldif) super(proprio, self).__init__(conn, dn, mode, ldif)
self._machines = None self._machines = None
self._factures = None self._factures = None
if u'cransAccount' in [ unicode(o) for o in self['objectClass']]: if u'cransAccount' in self['objectClass']:
self.attribs = self.attribs + crans_account_attribs self.attribs = self.attribs + crans_account_attribs
self.full = True self.full = True
@ -837,7 +872,7 @@ class adherent(proprio):
u"""Renvoie le nom du compte crans. S'il n'existe pas, et que uid u"""Renvoie le nom du compte crans. S'il n'existe pas, et que uid
est précisé, le crée.""" est précisé, le crée."""
if u'posixAccount' in [str(o) for o in self.attrs['objectClass']]: if u'posixAccount' in self['objectClass']:
return self.attrs['uid'][0] return self.attrs['uid'][0]
elif login: elif login: