diff --git a/attributs.py b/attributs.py index 8546f2c..050c3fb 100644 --- a/attributs.py +++ b/attributs.py @@ -125,10 +125,11 @@ def attrify(val, attr, conn, Parent=None): if isinstance(val, Attr): return val 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) val = val.decode('utf-8') - return AttributeFactory.get(attr, fallback=Attr)(val, conn, Parent) + return attr_classe(val, conn, Parent) class AttrsDict(dict): @@ -193,6 +194,7 @@ class Attr(object): unique = False #: Le nom de l'attribut dans le schéma LDAP ldap_name = None + python_type = None """La liste des droits qui suffisent à avoir le droit de modifier la valeur""" can_modify = [nounou] @@ -213,6 +215,21 @@ class Attr(object): self.parent = Parent 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): """Transforme l'attribut pour travailler avec notre validateur Le ldif est en dépendance car à certains endroits, il peut servir @@ -304,22 +321,28 @@ class objectClass(Attr): class intAttr(Attr): + + python_type = int + def parse_value(self, val): - if int(val) <= 0: + if self.python_type(val) <= 0: raise ValueError("Valeur entière invalide : %r" % val) - self.value = int(val) + self.value = self.python_type(val) def __unicode__(self): return unicode(self.value) class boolAttr(Attr): + + python_type = bool + 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 elif val.lower() == u'false': self.value = False - elif isinstance(val, bool): - self.value = val else: raise ValueError("%r doit être un booléen !" % val) @@ -414,7 +437,7 @@ class yearAttr(intAttr): optional = True def parse_value(self, annee): - annee = int(annee) + annee = self.python_type(annee) if annee < 1998: raise ValueError("Année invalide (%r)" % annee) self.value = annee @@ -598,6 +621,7 @@ class droits(Attr): @crans_attribute class solde(Attr): + python_type = float singlevalue = True optional = True 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 #if not (float(solde) >= config.impression.decouvert and float(solde) <= 1024.): # raise ValueError("Solde invalide: %r" % solde) - self.value = float(solde) + self.value = self.python_type(solde) def __unicode__(self): return u"%.2f" % self.value @@ -679,12 +703,13 @@ class ipHostNumber(Attr): category = 'base_tech' can_modify = [nounou] ldap_name = "ipHostNumber" + python_type = netaddr.IPAddress default = u'' def parse_value(self, ip): if ip == '': ip = ip4_of_rid(str(self.parent['rid'][0])) - self.value = netaddr.IPAddress(ip) + self.value = self.python_type(ip) def __unicode__(self): return unicode(self.value) @@ -699,18 +724,19 @@ class ip6HostNumber(Attr): category = 'base_tech' can_modify = [nounou] ldap_name = "ip6HostNumber" + python_type = netaddr.IPAddress default = u'' def parse_value(self, ip6): if ip6 == '': 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): return unicode(self.value) @crans_attribute -class mid(Attr): +class mid(intAttr): singlevalue = True optional = False unique = True @@ -718,14 +744,8 @@ class mid(Attr): category = 'id' ldap_name = "mid" - def parse_value(self, mid): - self.value = int(mid) - - def __unicode__(self): - return unicode(self.value) - @crans_attribute -class rid(Attr): +class rid(intAttr): singlevalue = True optional = True unique = True @@ -735,7 +755,7 @@ class rid(Attr): ldap_name = "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 # .0 ou .255 @@ -989,6 +1009,7 @@ class blacklist(Attr): category = 'info' can_modify = [nounou] ldap_name = "blacklist" + python_type = dict def parse_value(self, blacklist): bl_debut, bl_fin, bl_type, bl_comm = blacklist.split('$') @@ -1061,7 +1082,7 @@ class homepageAlias(Attr): ldap_name = "homepageAlias" @crans_attribute -class charteMA(Attr): +class charteMA(boolAttr): singlevalue = True optional = True legend= "Signale si l'adhérent a signé la charte de membres actifs" @@ -1069,11 +1090,6 @@ class charteMA(Attr): category = 'perso' 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 class homeDirectory(Attr): singlevalue=True diff --git a/objets.py b/objets.py index 6f97ada..d3fa275 100644 --- a/objets.py +++ b/objets.py @@ -162,6 +162,41 @@ class CransLdapObject(object): 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) + 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): print printing.sprint(self) @@ -543,7 +578,7 @@ class proprio(CransLdapObject): super(proprio, self).__init__(conn, dn, mode, ldif) self._machines = 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.full = True @@ -837,7 +872,7 @@ class adherent(proprio): u"""Renvoie le nom du compte crans. S'il n'existe pas, et que uid 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] elif login: