108 lines
3.3 KiB
Python
108 lines
3.3 KiB
Python
|
# -*- coding: utf-8 mode: python -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||
|
|
||
|
__all__ = (
|
||
|
'ANY', 'ALL', 'NONE', 'EXISTS',
|
||
|
)
|
||
|
|
||
|
from .utils import *
|
||
|
|
||
|
class Expr(object):
|
||
|
_terms, terms = None, property(lambda self: self._terms)
|
||
|
|
||
|
def __init__(self, *terms):
|
||
|
self._terms = listof(terms or None, None)
|
||
|
|
||
|
@staticmethod
|
||
|
def match_dict(dict, object):
|
||
|
for name, value in dict.items():
|
||
|
one_match = False
|
||
|
attr_values = object.get(name, ())
|
||
|
for value in listof(value):
|
||
|
if value in attr_values:
|
||
|
one_match = True
|
||
|
break
|
||
|
if not one_match: return False
|
||
|
return True
|
||
|
|
||
|
@staticmethod
|
||
|
def match_term(term, object):
|
||
|
"""tester le terme par rapport à l'objet.
|
||
|
* si c'est None, retourner vrai
|
||
|
* si c'est un dictionnaire, tous les attributs cités doivent avoir au
|
||
|
moins une des valeurs fournies
|
||
|
* si c'est une fonction (plus exactement un objet appelable), elle doit
|
||
|
prendre l'unique argument (object) et retourner True si l'objet
|
||
|
correspond
|
||
|
* si c'est une liste, la traiter comme ANY(*term)
|
||
|
* si c'est une instance de Expr, déléguer le traitement à sa méthode
|
||
|
match()
|
||
|
* sinon, lancer une exception.
|
||
|
"""
|
||
|
if term is None:
|
||
|
return True
|
||
|
elif isinstance(term, dict):
|
||
|
return Expr.match_dict(term, object)
|
||
|
elif callable(term):
|
||
|
return term(object)
|
||
|
elif isseq(term):
|
||
|
term = ANY(*term)
|
||
|
if isinstance(term, Expr):
|
||
|
return term.match(object)
|
||
|
else:
|
||
|
raise ValueError("Argument invalide %r" % term)
|
||
|
|
||
|
def match(self, object):
|
||
|
return False
|
||
|
|
||
|
class ANY(Expr):
|
||
|
"""construire l'objet avec une liste de termes. au moins un des termes doit
|
||
|
correspondre
|
||
|
"""
|
||
|
def match(self, object, lazy=True):
|
||
|
result = False
|
||
|
if self.terms is None: return result
|
||
|
for term in self.terms:
|
||
|
if self.match_term(term, object):
|
||
|
result = True
|
||
|
if lazy: break
|
||
|
return result
|
||
|
|
||
|
class ALL(Expr):
|
||
|
"""construire l'objet avec une liste de termes. tous les termes doivent
|
||
|
correspondrent
|
||
|
"""
|
||
|
def match(self, object, lazy=True):
|
||
|
result = True
|
||
|
if self.terms is None: return result
|
||
|
for term in self.terms:
|
||
|
if not self.match_term(term, object):
|
||
|
result = False
|
||
|
if lazy: break
|
||
|
return result
|
||
|
|
||
|
class NONE(Expr):
|
||
|
"""construire l'objet avec une liste de termes. aucun des termes ne doit
|
||
|
correspondre
|
||
|
"""
|
||
|
def match(self, object, lazy=False):
|
||
|
result = True
|
||
|
if self.terms is None: return result
|
||
|
for term in self.terms:
|
||
|
if self.match_term(term, object):
|
||
|
result = False
|
||
|
if lazy: break
|
||
|
return result
|
||
|
|
||
|
class EXISTS(Expr):
|
||
|
"""construire l'objet avec une liste d'attributs. tous les attributs doivent
|
||
|
exister
|
||
|
"""
|
||
|
def match(self, object, lazy=True):
|
||
|
result = True
|
||
|
if self.terms is None: return result
|
||
|
for term in self.terms:
|
||
|
if not object.has_key(term):
|
||
|
result = False
|
||
|
if lazy: break
|
||
|
return result
|