common/selectors.py
branchtls-sprint
changeset 631 99f5852f8604
parent 593 6f6549780096
child 633 087e3f1e87c8
--- a/common/selectors.py	Mon Feb 16 16:24:24 2009 +0100
+++ b/common/selectors.py	Mon Feb 16 18:26:13 2009 +0100
@@ -43,10 +43,13 @@
 
 from logilab.common.compat import all
 from logilab.common.deprecation import deprecated_function
+from logilab.common.interface import implements as implements_iface
+
+from yams import BASE_TYPES
 
 from cubicweb import Unauthorized, NoSelectableObject, role
+from cubicweb.vregistry import NoSelectableObject, Selector, chainall, chainfirst
 from cubicweb.cwvreg import DummyCursorError
-from cubicweb.vregistry import chainall, chainfirst, NoSelectableObject
 from cubicweb.cwconfig import CubicWebConfiguration
 from cubicweb.schema import split_expression
 
@@ -59,9 +62,15 @@
     if CubicWebConfiguration.mode == 'installed':
         return selector
     def traced(cls, *args, **kwargs):
+        if isinstance(cls, Selector):
+            selname = cls.__class__.__name__
+            oid = args[0].id
+        else:
+            selname = selector.__name__
+            oid = cls.id
         ret = selector(cls, *args, **kwargs)
-        if TRACED_OIDS == 'all' or cls.id in TRACED_OIDS:
-            SELECTOR_LOGGER.warning('selector %s returned %s for %s', selector.__name__, ret, cls)
+        if TRACED_OIDS == 'all' or oid in TRACED_OIDS:
+            SELECTOR_LOGGER.warning('selector %s returned %s for %s', selname, ret, cls)
         return ret
     traced.__name__ = selector.__name__
     return traced
@@ -174,7 +183,7 @@
 largerset_selector = deprecated_function(paginated_rset)
 
 @lltrace
-def sorted_rset(cls, req, rset, row=None, col=None, **kwargs):
+def sorted_rset(cls, req, rset, row=None, col=0, **kwargs):
     """accept sorted result set"""
     rqlst = rset.syntax_tree()
     if len(rqlst.children) > 1 or not rqlst.children[0].orderby:
@@ -202,21 +211,24 @@
     return 0
 multitype_selector = deprecated_function(two_etypes_rset)
 
-@lltrace
-def match_search_state(cls, req, rset, row=None, col=None, **kwargs):
-    """checks if the current search state is in a .search_states attribute of
-    the wrapped class
+
+class match_search_state(Selector):
+    def __init__(self, *expected_states):
+        self.expected_states = expected_states
+        
+    def __call__(self, cls, req, rset, row=None, col=0, **kwargs):
+        """checks if the current request search state is in one of the expected states
+        the wrapped class
 
-    search state should be either 'normal' or 'linksearch' (eg searching for an
-    object to create a relation with another)
-    """
-    try:
-        if not req.search_state[0] in cls.search_states:
-            return 0
-    except AttributeError:
-        return 1 # class doesn't care about search state, accept it
-    return 1
-searchstate_selector = deprecated_function(match_search_state)
+        search state should be either 'normal' or 'linksearch' (eg searching for an
+        object to create a relation with another)
+        """
+        try:
+            if not req.search_state[0] in cls.search_states:
+                return 0
+        except AttributeError:
+            return 1 # class doesn't care about search state, accept it
+        return 1
 
 @lltrace
 def anonymous_user(cls, req, *args, **kwargs):
@@ -258,46 +270,331 @@
     return 1
 kwargs_selector = deprecated_function(match_kwargs)
 
+# abstract selectors ##########################################################
+
+class EClassSelector(Selector):
+    """abstract class for selectors working on the entity classes of the result
+    set
+    """
+    once_is_enough = False
+    
+    @lltrace
+    def __call__(self, cls, req, rset, row=None, col=0, **kwargs):
+        if not rset:
+            return 0
+        score = 0
+        if row is None:
+            for etype in rset.column_types(col):
+                if etype is None: # outer join
+                    continue
+                if etype in BASE_TYPES:
+                    return 0
+                escore = self.score_class(cls.vreg.etype_class(etype), req)
+                if not escore:
+                    return 0
+                elif self.once_is_enough:
+                    return escore
+                score += escore
+        else:
+            etype = rset.description[row][col]
+            if etype is not None and not etype in BASE_TYPES:
+                score = self.score_class(cls.vreg.etype_class(etype), req)
+        return score and (score + 1)
+
+    def score_class(self, eclass, req):
+        raise NotImplementedError()
+
+
+class EntitySelector(Selector):
+    """abstract class for selectors working on the entity instances of the
+    result set
+    """
+    @lltrace
+    def __call__(self, cls, req, rset, row=None, col=0, **kwargs):
+        if not rset:
+            return 0
+        score = 0
+        if row is None:
+            for row, rowvalue in enumerate(rset.rows):
+                if rowvalue[col] is None: # outer join
+                    continue
+                try:
+                    escore = self.score_entity(rset.get_entity(row, col))
+                except NotAnEntity:
+                    return 0
+                if not escore:
+                    return 0
+                score += escore
+        else:
+            etype = rset.description[row][col]
+            if etype is not None: # outer join
+                try:
+                    score = self.score_entity(rset.get_entity(row, col))
+                except NotAnEntity:
+                    return 0
+        return score and (score + 1)
+
+    def score_entity(self, entity):
+        raise NotImplementedError()
 
 # not so basic selectors ######################################################
 
+class implements(EClassSelector):
+    """initializer takes a list of interfaces or entity types as argument
+    
+    * if row is None, return the number of implemented interfaces for each
+      entity's class in the result set at the specified column (or column 0).
+      If any class has no matching interface, return 0.
+    * if row is specified, return number of implemented interfaces by the
+      entity's class at this row (and column)
+
+    if some interface is an entity class, the score will reflect class
+    proximity so the most specific object'll be selected
+    """
+
+    def __init__(self, *expected_ifaces):
+        self.expected_ifaces = expected_ifaces
+
+    def score_class(self, eclass, req):
+        score = 0
+        for iface in self.expected_ifaces:
+            if isinstance(iface, basestring):
+                # entity type
+                iface = eclass.vreg.etype_class(iface)
+            if implements_iface(eclass, iface):
+                score += 1
+                if getattr(iface, '__registry__', None) == 'etypes':
+                    # adjust score if the interface is an entity class
+                    if iface is eclass:
+                        score += len(eclass.e_schema.ancestors()) + 1
+                    else:
+                        parents = [e.type for e in eclass.e_schema.ancestors()]
+                        for index, etype in enumerate(reversed(parents)):
+                            basecls = eclass.vreg.etype_class(etype)
+                            if iface is basecls:
+                                score += index + 1
+                                break
+        return score
+
+
+class relation_possible(EClassSelector):
+    """initializer takes relation name as argument and an optional role (default
+      as subject) and target type (default to unspecified)
+      
+    * if row is None, return 1 if every entity's class in the result set at the
+      specified column (or column 0) may have this relation (as role). If target
+      type is specified, check the relation's end may be of this target type.
+      
+    * if row is specified, check relation is supported by the entity's class at
+      this row (and column)
+    """
+    def __init__(self, rtype, role='subject', target_etype=None,
+                 permission='read', once_is_enough=False):
+        self.rtype = rtype
+        self.role = role
+        self.target_etype = target_etype
+        self.permission = permission
+        self.once_is_enough = once_is_enough
+
+    @lltrace
+    def __call__(self, cls, *args, **kwargs):
+        rschema = cls.schema.rschema(self.rtype)
+        if not (rschema.has_perm(req, self.permission)
+                or rschema.has_local_role(self.permission)):
+            return 0
+        return super(relation_possible, self)(cls, *args, **kwargs)
+        
+    def score_class(self, eclass, req):
+        eschema = eclass.e_schema
+        try:
+            if self.role == 'object':
+                rschema = eschema.object_relation(self.rtype)
+            else:
+                rschema = eschema.subject_relation(self.rtype)
+        except KeyError:
+            return 0
+        if self.target_etype is not None:
+            try:
+                if self.role == 'object':
+                    return self.target_etype in rschema.objects(eschema)
+                else:
+                    return self.target_etype in rschema.subjects(eschema)
+            except KeyError, ex:
+                return 0
+        return 1
+
+
+class non_final_entity(EClassSelector):
+    """initializer takes no argument
+
+    * if row is None, return 1 if there are only non final entity's class in the
+      result set at the specified column (or column 0)
+    * if row is specified, return 1 if entity's class at this row (and column)
+      isn't final
+    """
+    def score_class(self, eclass, req):
+        return int(not eclass.e_schema.is_final())
+
+
+class match_user_groups(Selector):
+    """initializer takes users group as argument
+
+    * check logged user is in one of the given groups. If special 'owners' group
+      given:
+      - if row is specified check the entity at the given row/col is owned by
+        the logged user
+      - if row is not specified check all entities in col are owned by the
+        logged user
+    """
+    
+    def __init__(self, *required_groups):
+        self.required_groups = required_groups
+    
+    @lltrace
+    def __call__(self, cls, req, rset=None, row=None, col=0, **kwargs):
+        user = req.user
+        if user is None:
+            return int('guests' in self.require_groups)
+        score = user.matching_groups(self.require_groups)
+        if not score and 'owners' in self.require_groups and rset:
+            nbowned = 0
+            if row is not None:
+                if not user.owns(rset[row][col]):
+                    return 0
+                score = 1
+            else:
+                score = all(user.owns(r[col or 0]) for r in rset)
+        return 0
+
+
+class has_editable_relation(EntitySelector):
+    """initializer takes no argument
+
+    * if row is specified check the entity at the given row/col has some
+      relation editable by the logged user
+    * if row is not specified check all entities in col are owned have some
+      relation editable by the logged userlogged user
+    """
+        
+    def score_entity(self, entity):
+        # if user has no update right but it can modify some relation,
+        # display action anyway
+        for dummy in entity.srelations_by_category(('generic', 'metadata'),
+                                                   'add'):
+            return 1
+        for rschema, targetschemas, role in entity.relations_by_category(
+            ('primary', 'secondary'), 'add'):
+            if not rschema.is_final():
+                return 1
+        return 0
+
+
+class may_add_relation(EntitySelector):
+    """initializer a relation type and optional role (default to 'subject') as
+    argument
+
+    if row is specified check the relation may be added to the entity at the
+    given row/col (if row specified) or to every entities in the given col (if
+    row is not specified)
+    """
+    
+    def __init__(self, rtype, role='subject'):
+        self.rtype = rtype
+        self.role = role
+        
+    def score_entity(self, entity):
+        rschema = entity.schema.rschema(self.rtype)
+        if self.role == 'subject':
+            if not rschema.has_perm(req, 'add', fromeid=entity.eid):
+                return False
+        elif not rschema.has_perm(req, 'add', toeid=entity.eid):
+            return False
+        return True
+
+        
+class has_permission(EntitySelector):
+    """initializer takes a schema action (eg 'read'/'add'/'delete'/'update') as
+    argument
+
+    * if row is specified check user has permission to do the requested action
+      on the entity at the given row/col
+    * if row is specified check user has permission to do the requested action
+      on all entities in the given col
+    """
+    def __init__(self, schema_action):
+        self.schema_action = schema_action
+        
+    @lltrace
+    def __call__(self, cls, req, rset, row=None, col=0, **kwargs):
+        user = req.user
+        action = self.schema_action
+        if row is None:
+            score = 0
+            need_local_check = [] 
+            geteschema = cls.schema.eschema
+            for etype in rset.column_types(0):
+                if etype in BASE_TYPES:
+                    return 0
+                eschema = geteschema(etype)
+                if not user.matching_groups(eschema.get_groups(action)):
+                    if eschema.has_local_role(action):
+                        # have to ckeck local roles
+                        need_local_check.append(eschema)
+                        continue
+                    else:
+                        # even a local role won't be enough
+                        return 0
+                score += accepted
+            if need_local_check:
+                # check local role for entities of necessary types
+                for i, row in enumerate(rset):
+                    if not rset.description[i][0] in need_local_check:
+                        continue
+                    if not self.score_entity(rset.get_entity(i, col)):
+                        return 0
+                    score += 1
+            return score
+        if rset.description[row][col] in BASE_TYPES:
+            return 0
+        return self.score_entity(rset.get_entity(row, col))
+    
+    def score_entity(self, entity):
+        if entity.has_perm(self.schema_action):
+            return 1
+        return 0
+
+
+class has_add_permission(EClassSelector):
+    
+    def score_class(self, eclass, req):
+        eschema = eclass.e_schema
+        if not (eschema.is_final() or eschema.is_subobject(strict=True)) \
+               and eschema.has_perm(req, 'add'):
+            return 1
+        return 0
+
+        
+class score_entity(EntitySelector):
+    def __init__(self, scorefunc):
+        self.score_entity = scorefunc
+
+# XXX not so basic selectors ######################################################
+
 @lltrace
 def accept_etype(cls, req, *args, **kwargs):
     """check etype presence in request form *and* accepts conformance"""
-    if 'etype' not in req.form and 'etype' not in kwargs:
-        return 0
     try:
         etype = req.form['etype']
     except KeyError:
-        etype = kwargs['etype']
-    # value is a list or a tuple if web request form received several
-    # values for etype parameter
-    assert isinstance(etype, basestring), "got multiple etype parameters in req.form"
-    if 'Any' in cls.accepts:
-        return 1
-    # no Any found, we *need* exact match
-    if etype not in cls.accepts:
-        return 0
-    # exact match must return a greater value than 'Any'-match
-    return 2
+        try:
+            etype = kwargs['etype']
+        except KeyError:
+            return 0
+    return implements(*cls.accepts).score_class(cls.vreg.etype_class(etype), req)
 etype_form_selector = deprecated_function(accept_etype)
 
 @lltrace
-def _non_final_entity(cls, req, rset, row=None, col=None, **kwargs):
-    """accept non final entities
-    if row is not specified, use the first one
-    if col is not specified, use the first one
-    """
-    etype = rset.description[row or 0][col or 0]
-    if etype is None: # outer join
-        return 0
-    if cls.schema.eschema(etype).is_final():
-        return 0
-    return 1
-_nfentity_selector = deprecated_function(_non_final_entity)
-
-@lltrace
-def _rql_condition(cls, req, rset, row=None, col=None, **kwargs):
+def _rql_condition(cls, req, rset, row=None, col=0, **kwargs):
     """accept single entity result set if the entity match an rql condition
     """
     if cls.condition:
@@ -313,89 +610,9 @@
         
     return 1
 _rqlcondition_selector = deprecated_function(_rql_condition)
-
+        
 @lltrace
-def _implement_interface(cls, req, rset, row=None, col=None, **kwargs):
-    """accept uniform result sets, and apply the following rules:
-
-    * wrapped class must have a accepts_interfaces attribute listing the
-      accepted ORed interfaces
-    * if row is None, return the sum of values returned by the method
-      for each entity's class in the result set. If any score is 0,
-      return 0.
-    * if row is specified, return the value returned by the method with
-      the entity's class of this row
-    """
-    # XXX this selector can be refactored : extract the code testing
-    #     for entity schema / interface compliance
-    score = 0
-    # check 'accepts' to give priority to more specific classes
-    if row is None:
-        for etype in rset.column_types(col or 0):
-            eclass = cls.vreg.etype_class(etype)
-            escore = 0
-            for iface in cls.accepts_interfaces:
-                escore += iface.is_implemented_by(eclass)
-            if not escore:
-                return 0
-            score += escore
-            accepts = set(getattr(cls, 'accepts', ()))
-            # if accepts is defined on the vobject, eclass must match
-            if accepts:
-                eschema = eclass.e_schema
-                etypes = set([eschema] + eschema.ancestors())
-                if accepts & etypes:
-                    score += 2
-                elif 'Any' not in accepts:
-                    return 0
-        return score + 1
-    etype = rset.description[row][col or 0]
-    if etype is None: # outer join
-        return 0
-    eclass = cls.vreg.etype_class(etype)
-    for iface in cls.accepts_interfaces:
-        score += iface.is_implemented_by(eclass)
-    if score:
-        accepts = set(getattr(cls, 'accepts', ()))
-        # if accepts is defined on the vobject, eclass must match
-        if accepts:
-            eschema = eclass.e_schema
-            etypes = set([eschema] + eschema.ancestors())
-            if accepts & etypes:
-                score += 1
-            elif 'Any' not in accepts:
-                return 0
-        score += 1
-    return score
-_interface_selector = deprecated_function(_implement_interface)
-
-@lltrace
-def score_entity_selector(cls, req, rset, row=None, col=None, **kwargs):
-    if row is None:
-        rows = xrange(rset.rowcount)
-    else:
-        rows = (row,)
-    for row in rows:
-        try:
-            score = cls.score_entity(rset.get_entity(row, col or 0))
-        except DummyCursorError:
-            # get a dummy cursor error, that means we are currently
-            # using a dummy rset to list possible views for an entity
-            # type, not for an actual result set. In that case, we
-            # don't care of the value, consider the object as selectable
-            return 1
-        if not score:
-            return 0
-    return 1
-
-@lltrace
-def accept_rset(cls, req, rset, row=None, col=None, **kwargs):
-    """simply delegate to cls.accept_rset method"""
-    return cls.accept_rset(req, rset, row=row, col=col)
-accept_rset_selector = deprecated_function(accept_rset)
-
-@lltrace
-def but_etype(cls, req, rset, row=None, col=None, **kwargs):
+def but_etype(cls, req, rset, row=None, col=0, **kwargs):
     """restrict the searchstate_accept_one_selector to exclude entity's type
     refered by the .etype attribute
     """
@@ -405,7 +622,7 @@
 but_etype_selector = deprecated_function(but_etype)
 
 @lltrace
-def etype_rtype_selector(cls, req, rset, row=None, col=None, **kwargs):
+def etype_rtype_selector(cls, req, rset, row=None, col=0, **kwargs):
     """only check if the user has read access on the entity's type refered
     by the .etype attribute and on the relations's type refered by the
     .rtype attribute if set.
@@ -423,75 +640,11 @@
     return 1
 
 @lltrace
-def has_relation(cls, req, rset, row=None, col=None, **kwargs):
-    """check if the user has read access on the relations's type refered by the
-    .rtype attribute of the class, and if all entities types in the
-    result set has this relation.
-    """
-    if hasattr(cls, 'rtype'):
-        rschema = cls.schema.rschema(cls.rtype)
-        perm = getattr(cls, 'require_permission', 'read')
-        if not (rschema.has_perm(req, perm) or rschema.has_local_role(perm)):
-            return 0
-        if row is None:
-            for etype in rset.column_types(col or 0):
-                if not cls.relation_possible(etype):
-                    return 0
-        elif not cls.relation_possible(rset.description[row][col or 0]):
-            return 0
-    return 1
-accept_rtype_selector = deprecated_function(has_relation)
+def has_related_entities(cls, req, rset, row=None, col=0, **kwargs):
+    return bool(rset.get_entity(row or 0, col or 0).related(cls.rtype, role(cls)))
 
 @lltrace
-def one_has_relation(cls, req, rset, row=None, col=None, **kwargs):
-    """check if the user has read access on the relations's type refered by the
-    .rtype attribute of the class, and if at least one entity type in the
-    result set has this relation.
-    """
-    rschema = cls.schema.rschema(cls.rtype)
-    perm = getattr(cls, 'require_permission', 'read')
-    if not (rschema.has_perm(req, perm) or rschema.has_local_role(perm)):
-        return 0
-    if row is None:
-        for etype in rset.column_types(col or 0):
-            if cls.relation_possible(etype):
-                return 1
-    elif cls.relation_possible(rset.description[row][col or 0]):
-        return 1
-    return 0
-one_has_relation_selector = deprecated_function(one_has_relation)
-
-@lltrace
-def has_related_entities(cls, req, rset, row=None, col=None, **kwargs):
-    return bool(rset.get_entity(row or 0, col or 0).related(cls.rtype, role(cls)))
-
-
-@lltrace
-def match_user_group(cls, req, rset=None, row=None, col=None, **kwargs):
-    """select according to user's groups"""
-    if not cls.require_groups:
-        return 1
-    user = req.user
-    if user is None:
-        return int('guests' in cls.require_groups)
-    score = 0
-    if 'owners' in cls.require_groups and rset:
-        if row is not None:
-            eid = rset[row][col or 0]
-            if user.owns(eid):
-                score = 1
-        else:
-            score = all(user.owns(r[col or 0]) for r in rset)
-    score += user.matching_groups(cls.require_groups)
-    if score:
-        # add 1 so that an object with one matching group take priority
-        # on an object without require_groups
-        return score + 1 
-    return 0
-in_group_selector = deprecated_function(match_user_group)
-
-@lltrace
-def user_can_add_etype(cls, req, rset, row=None, col=None, **kwargs):
+def user_can_add_etype(cls, req, rset, row=None, col=0, **kwargs):
     """only check if the user has add access on the entity's type refered
     by the .etype attribute.
     """
@@ -501,7 +654,7 @@
 add_etype_selector = deprecated_function(user_can_add_etype)
 
 @lltrace
-def match_context_prop(cls, req, rset, row=None, col=None, context=None,
+def match_context_prop(cls, req, rset, row=None, col=0, context=None,
                        **kwargs):
     propval = req.property_value('%s.%s.context' % (cls.__registry__, cls.id))
     if not propval:
@@ -512,7 +665,7 @@
 contextprop_selector = deprecated_function(match_context_prop)
 
 @lltrace
-def primary_view(cls, req, rset, row=None, col=None, view=None,
+def primary_view(cls, req, rset, row=None, col=0, view=None,
                           **kwargs):
     if view is not None and not view.is_primary():
         return 0
@@ -533,39 +686,70 @@
     return selector
 
 
+
+# XXX DEPRECATED ##############################################################
+
+def nfentity_selector(cls, req, rset, row=None, col=0, **kwargs):
+    return non_final_entity()(cls, req, rset, row, col)
+nfentity_selector = deprecated_function(nfentity_selector)
+
+def implement_interface(cls, req, rset, row=None, col=0, **kwargs):
+    return implements(*cls.accepts_interfaces)(cls, req, rset, row, col)
+_interface_selector = deprecated_function(implement_interface)
+interface_selector = deprecated_function(implement_interface)
+implement_interface = deprecated_function(implement_interface)
+
+def searchstate_selector(cls, req, rset, row=None, col=0, **kwargs):
+    return match_search_state(cls.search_states)(cls, req, rset, row, col)
+searchstate_selector = deprecated_function(searchstate_selector)
+
+def match_user_group(cls, req, rset=None, row=None, col=0, **kwargs):
+    return match_user_groups(cls.require_groups)(cls, req, rset, row, col, **kwargs)
+in_group_selector = deprecated_function(match_user_group)
+match_user_group = deprecated_function(match_user_group)
+
+def has_relation(cls, req, rset, row=None, col=0, **kwargs):
+    return relation_possible(cls.rtype, role(cls), cls.etype,
+                             getattr(cls, 'require_permission', 'read'))(cls, req, rset, row, col, **kwargs)
+has_relation = deprecated_function(has_relation)
+
+def one_has_relation(cls, req, rset, row=None, col=0, **kwargs):
+    return relation_possible(cls.rtype, role(cls), cls.etype,
+                             getattr(cls, 'require_permission', 'read',
+                                     once_is_enough=True))(cls, req, rset, row, col, **kwargs)
+one_has_relation = deprecated_function(one_has_relation, 'use relation_possible selector')
+
+def accept_rset(cls, req, rset, row=None, col=0, **kwargs):
+    """simply delegate to cls.accept_rset method"""
+    return implements(*cls.accepts)(cls, req, rset, row=row, col=col)
+accept_rset_selector = deprecated_function(accept_rset)
+accept_rset = deprecated_function(accept_rset, 'use implements selector')
+
+accept = chainall(non_final_entity(), accept_rset, name='accept')
+accept_selector = deprecated_function(accept)
+accept = deprecated_function(accept, 'use implements selector')
+
 # compound selectors ##########################################################
 
-non_final_entity = chainall(nonempty_rset, _non_final_entity)
-non_final_entity.__name__ = 'non_final_entity'
-nfentity_selector = deprecated_function(non_final_entity)
-
-implement_interface = chainall(non_final_entity, _implement_interface)
-implement_interface.__name__ = 'implement_interface'
-interface_selector = deprecated_function(implement_interface)
-
-accept = chainall(non_final_entity, accept_rset)
-accept.__name__ = 'accept'
-accept_selector = deprecated_function(accept)
-
-accept_one = chainall(one_line_rset, accept)
-accept_one.__name__ = 'accept_one'
+accept_one = deprecated_function(chainall(one_line_rset, accept,
+                                          name='accept_one'))
 accept_one_selector = deprecated_function(accept_one)
 
-rql_condition = chainall(non_final_entity, one_line_rset, _rql_condition)
-rql_condition.__name__ = 'rql_condition'
+rql_condition = chainall(non_final_entity(), one_line_rset, _rql_condition,
+                         name='rql_condition')
 rqlcondition_selector = deprecated_function(rql_condition)
 
 
-searchstate_accept = chainall(nonempty_rset, match_search_state, accept)
-searchstate_accept.__name__ = 'searchstate_accept'
+searchstate_accept = chainall(nonempty_rset, match_search_state, accept,
+                              name='searchstate_accept')
 searchstate_accept_selector = deprecated_function(searchstate_accept)
 
 searchstate_accept_one = chainall(one_line_rset, match_search_state,
-                                  accept, _rql_condition)
-searchstate_accept_one.__name__ = 'searchstate_accept_one'
+                                  accept, _rql_condition,
+                                  name='searchstate_accept_one')
 searchstate_accept_one_selector = deprecated_function(searchstate_accept_one)
 
-searchstate_accept_one_but_etype = chainall(searchstate_accept_one, but_etype)
-searchstate_accept_one_but_etype.__name__ = 'searchstate_accept_one_but_etype'
+searchstate_accept_one_but_etype = chainall(searchstate_accept_one, but_etype,
+                                            name='searchstate_accept_one_but_etype')
 searchstate_accept_one_but_etype_selector = deprecated_function(
     searchstate_accept_one_but_etype)