Commit adaa17d6 authored by sylvain.thenault@logilab.fr's avatar sylvain.thenault@logilab.fr
Browse files

more selectors update

--HG--
branch : tls-sprint
parent 3a394a90b702
......@@ -70,7 +70,8 @@ def lltrace(selector):
oid = cls.id
ret = selector(cls, *args, **kwargs)
if TRACED_OIDS == 'all' or oid in TRACED_OIDS:
SELECTOR_LOGGER.warning('selector %s returned %s for %s', selname, ret, cls)
#SELECTOR_LOGGER.warning('selector %s returned %s for %s', selname, ret, cls)
print 'selector %s returned %s for %s' % (selname, ret, cls)
return ret
traced.__name__ = selector.__name__
return traced
......@@ -213,9 +214,10 @@ multitype_selector = deprecated_function(two_etypes_rset)
class match_search_state(Selector):
def __init__(self, *expected_states):
self.expected_states = expected_states
def __init__(self, *expected):
self.expected = expected
@lltrace
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
......@@ -224,12 +226,40 @@ class match_search_state(Selector):
object to create a relation with another)
"""
try:
if not req.search_state[0] in cls.search_states:
if not req.search_state[0] in self.expected:
return 0
except AttributeError:
return 1 # class doesn't care about search state, accept it
return 1
class match_form_params(match_search_state):
"""check if parameters specified as initializer arguments are specified
in request form parameters
"""
@lltrace
def __call__(self, cls, req, *args, **kwargs):
score = 0
for param in self.expected:
val = req.form.get(param)
if not val:
return 0
score += 1
return len(self.expected)
class match_kwargs(match_search_state):
"""check if parameters specified as initializer arguments are specified
in named parameters
"""
@lltrace
def __call__(self, cls, req, *args, **kwargs):
for arg in self.expected:
if not arg in kwargs:
return 0
return len(self.expected)
@lltrace
def anonymous_user(cls, req, *args, **kwargs):
"""accept if user is anonymous"""
......@@ -244,32 +274,6 @@ def authenticated_user(cls, req, *args, **kwargs):
return not anonymous_user(cls, req, *args, **kwargs)
not_anonymous_selector = deprecated_function(authenticated_user)
@lltrace
def match_form_params(cls, req, *args, **kwargs):
"""check if parameters specified by the form_params attribute on
the wrapped class are specified in request form parameters
"""
score = 0
for param in cls.form_params:
val = req.form.get(param)
if not val:
return 0
score += 1
return score + 1
req_form_params_selector = deprecated_function(match_form_params)
@lltrace
def match_kwargs(cls, req, *args, **kwargs):
"""check if arguments specified by the expected_kwargs attribute on
the wrapped class are specified in given named parameters
"""
values = []
for arg in cls.expected_kwargs:
if not arg in kwargs:
return 0
return 1
kwargs_selector = deprecated_function(match_kwargs)
# abstract selectors ##########################################################
class EClassSelector(Selector):
......@@ -364,19 +368,39 @@ class implements(EClassSelector):
if implements_iface(eclass, iface):
score += 1
if getattr(iface, '__registry__', None) == 'etypes':
score += 1
# adjust score if the interface is an entity class
if iface is eclass:
score += len(eclass.e_schema.ancestors()) + 1
score += len(eclass.e_schema.ancestors())
print 'is majoration', len(eclass.e_schema.ancestors())
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
score += index
print 'etype majoration', index
break
return score
class specified_etype_implements(implements):
"""return the "interface score" for class associated to 'etype' (expected in
request form or arguments)
"""
@lltrace
def __call__(cls, req, *args, **kwargs):
try:
etype = req.form['etype']
except KeyError:
try:
etype = kwargs['etype']
except KeyError:
return 0
return self.score_class(cls.vreg.etype_class(etype), req)
class relation_possible(EClassSelector):
"""initializer takes relation name as argument and an optional role (default
as subject) and target type (default to unspecified)
......@@ -490,8 +514,8 @@ class has_editable_relation(EntitySelector):
class may_add_relation(EntitySelector):
"""initializer a relation type and optional role (default to 'subject') as
argument
"""initializer takes 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
......@@ -565,7 +589,9 @@ class has_permission(EntitySelector):
class has_add_permission(EClassSelector):
"""return 1 if the user may add some entity of the types found in the
result set (0 else)
"""
def score_class(self, eclass, req):
eschema = eclass.e_schema
if not (eschema.is_final() or eschema.is_subobject(strict=True)) \
......@@ -575,24 +601,19 @@ class has_add_permission(EClassSelector):
class score_entity(EntitySelector):
"""initializer takes a function as argument (which is expected to take an
entity as argument)
return the score returned by the function on the entity at the given row/col
(if row specified) or the sum of the score for every entities in the given
col (if row is not specified). Return 0 at the first entity scoring to zero.
"""
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"""
try:
etype = req.form['etype']
except KeyError:
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 _rql_condition(cls, req, rset, row=None, col=0, **kwargs):
"""accept single entity result set if the entity match an rql condition
......@@ -697,14 +718,20 @@ 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)
implement_interface = deprecated_function(implement_interface, 'use implements')
def accept_etype(cls, req, *args, **kwargs):
"""check etype presence in request form *and* accepts conformance"""
return specified_etype_implements(*cls.accepts)(cls, req, *args)
etype_form_selector = deprecated_function(accept_etype)
accept_etype = deprecated_function(accept_etype, 'use specified_etype_implements')
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)
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)
......@@ -753,3 +780,6 @@ 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)
#req_form_params_selector = deprecated_function(match_form_params) # form_params
#kwargs_selector = deprecated_function(match_kwargs) # expected_kwargs
......@@ -8,18 +8,41 @@
__docformat__ = "restructuredtext en"
from cStringIO import StringIO
from warnings import warn
from logilab.mtconverter import html_escape
from cubicweb import NotAnEntity, NoSelectableObject
from cubicweb.common.registerers import accepts_registerer, priority_registerer
from cubicweb.common.selectors import (chainfirst, match_user_group, accept,
nonempty_rset, empty_rset, none_rset)
from cubicweb.common.selectors import (yes, match_user_groups, implements,
nonempty_rset, none_rset)
from cubicweb.common.appobject import AppRsetObject, ComponentMixIn
from cubicweb.common.utils import UStringIO, HTMLStream
_ = unicode
def require_group_compat(registered):
def plug_selector(cls, vreg):
cls = registered(cls, vreg)
if getattr(cls, 'require_groups', None):
warn('use "use match_user_groups(group1, group2)" instead of using require_groups',
DeprecationWarning)
cls.__selectors__ += (match_user_groups(cls.require_groups),)
return cls
return classmethod(plug_selector)
def accepts_compat(registered):
def plug_selector(cls, vreg):
cls = registered(cls, vreg)
if getattr(cls, 'accepts', None):
warn('use "use match_user_groups(group1, group2)" instead of using require_groups',
DeprecationWarning)
cls.__selectors__ += (implements(*cls.accepts),)
return cls
return classmethod(plug_selector)
# robots control
NOINDEX = u'<meta name="ROBOTS" content="NOINDEX" />'
NOFOLLOW = u'<meta name="ROBOTS" content="NOFOLLOW" />'
......@@ -302,9 +325,11 @@ class EntityView(View):
"""base class for views applying on an entity (i.e. uniform result set)
"""
__registerer__ = accepts_registerer
__selectors__ = (accept,)
category = 'entityview'
__selectors__ = (implements('Any'),)
registered = accepts_compat(View.registered.im_func)
category = 'entityview'
def field(self, label, value, row=True, show_label=True, w=None, tr=True):
""" read-only field """
if w is None:
......@@ -325,10 +350,11 @@ class StartupView(View):
to be displayed (so they can always be displayed !)
"""
__registerer__ = priority_registerer
__selectors__ = (match_user_group, none_rset)
require_groups = ()
__selectors__ = (none_rset,)
registered = require_group_compat(View.registered.im_func)
category = 'startupview'
def url(self):
"""return the url associated with this view. We can omit rql here"""
return self.build_url('view', vid=self.id)
......@@ -347,7 +373,7 @@ class EntityStartupView(EntityView):
result set (usually a default rql is provided by the view class)
"""
__registerer__ = accepts_registerer
__selectors__ = (chainfirst(none_rset, accept),)
__selectors__ = ((none_rset | implements('Any')),)
default_rql = None
......@@ -404,7 +430,7 @@ class AnyRsetView(View):
labels.append(label)
return labels
# concrete template base classes ##############################################
class Template(View):
......@@ -413,9 +439,9 @@ class Template(View):
"""
__registry__ = 'templates'
__registerer__ = priority_registerer
__selectors__ = (match_user_group,)
__selectors__ = (yes,)
require_groups = ()
registered = require_group_compat(View.registered.im_func)
def template(self, oid, **kwargs):
"""shortcut to self.registry.render method on the templates registry"""
......
"""some hooks and views to handle notification on entity's changes
:organization: Logilab
:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
__docformat__ = "restructuredtext en"
......@@ -21,7 +21,7 @@ from cubicweb import RegistryException
from cubicweb.common.view import EntityView
from cubicweb.common.appobject import Component
from cubicweb.common.registerers import accepts_registerer
from cubicweb.common.selectors import accept
from cubicweb.common.selectors import implements
from cubicweb.common.mail import format_mail
from cubicweb.server.pool import PreCommitOperation
......@@ -38,8 +38,7 @@ class RecipientsFinder(Component):
"""
id = 'recipients_finder'
__registerer__ = accepts_registerer
__selectors__ = (accept,)
accepts = ('Any',)
__selectors__ = (implements('Any'),)
user_rql = ('Any X,E,A WHERE X is EUser, X in_state S, S name "activated",'
'X primary_email E, E address A')
......@@ -299,7 +298,7 @@ class NormalizedTextView(ContentAddedMixIn, NotificationView):
class CardAddedView(NormalizedTextView):
"""get notified from new cards"""
accepts = ('Card',)
__selectors__ = (implements('Card'),)
content_attr = 'synopsis'
......@@ -227,7 +227,8 @@ class ResultSetTC(EnvBasedTC):
self.assertEquals(e.col, 0)
self.assertEquals(e['title'], 'zou')
self.assertRaises(KeyError, e.__getitem__, 'path')
self.assertEquals(e.view('text'), 'zou')
with traced_selection():
self.assertEquals(e.view('text'), 'zou')
self.assertEquals(pprelcachedict(e._related_cache), [])
e = rset.get_entity(0, 1)
......
......@@ -22,7 +22,7 @@ class VRegistryTC(TestCase):
self.vreg.load_file(join(BASE, 'web', 'views'), 'euser.py')
self.vreg.load_file(join(BASE, 'web', 'views'), 'baseviews.py')
fpvc = [v for v in self.vreg.registry_objects('views', 'primary')
i f v.__module__ == 'cubicweb.web.views.euser'][0]
if v.__module__ == 'cubicweb.web.views.euser'][0]
fpv = fpvc(None, None)
# don't want a TypeError due to super call
self.assertRaises(AttributeError, fpv.render_entity_attributes, None, None)
......
......@@ -17,9 +17,9 @@ from logilab.common.decorators import cached
from cubicweb.interfaces import IWorkflowable
from cubicweb.common.utils import make_uid
from cubicweb.common.uilib import cut
from cubicweb.common.selectors import (accept_etype, match_kwargs,
one_line_rset, implement_interface,
match_form_params, accept)
from cubicweb.common.selectors import (specified_etype_implements,
match_kwargs, match_form_params,
one_line_rset, implements)
from cubicweb.common.view import EntityView
from cubicweb.web import INTERNAL_FIELD_VALUE, stdmsgs, eid_param
from cubicweb.web.controller import NAV_FORM_PARAMETERS
......@@ -90,9 +90,7 @@ class ChangeStateForm(EntityForm):
id = 'statuschange'
title = _('status change')
__selectors__ = (implement_interface, match_form_params)
accepts_interfaces = (IWorkflowable,)
form_params = ('treid',)
__selectors__ = (implements(IWorkflowable), match_form_params('treid'))
def cell_call(self, row, col, vid='secondary'):
entity = self.entity(row, col)
......@@ -153,8 +151,7 @@ class ChangeStateForm(EntityForm):
class ClickAndEditForm(EntityForm):
id = 'reledit'
__selectors__ = (match_kwargs, )
expected_kwargs = ('rtype',)
__selectors__ = (match_kwargs('rtype'), )
#FIXME editableField class could be toggleable from userprefs
......@@ -219,7 +216,7 @@ class EditionForm(EntityForm):
dynamic default values such as the 'tomorrow' date or the user's login
being connected
"""
__selectors__ = (one_line_rset, accept)
__selectors__ = (one_line_rset, implements('Any'))
id = 'edition'
title = _('edition')
......@@ -526,7 +523,7 @@ class EditionForm(EntityForm):
class CreationForm(EditionForm):
__selectors__ = (accept_etype, )
__selectors__ = (specified_etype_implements('Any'), )
id = 'creation'
title = _('creation')
......@@ -639,8 +636,8 @@ class InlineFormMixIn(object):
class InlineEntityCreationForm(InlineFormMixIn, CreationForm):
id = 'inline-creation'
__selectors__ = (match_kwargs, accept_etype)
expected_kwargs = ('ptype', 'peid', 'rtype')
__selectors__ = (match_kwargs('ptype', 'peid', 'rtype'), specified_etype_implements('Any'))
EDITION_BODY = u'''\
<div id="div-%(parenteid)s-%(rtype)s-%(eid)s" class="inlinedform">
......@@ -678,8 +675,7 @@ class InlineEntityCreationForm(InlineFormMixIn, CreationForm):
class InlineEntityEditionForm(InlineFormMixIn, EditionForm):
id = 'inline-edition'
__selectors__ = (accept, match_kwargs)
expected_kwargs = ('ptype', 'peid', 'rtype')
__selectors__ = (implements('Any'), match_kwargs('ptype', 'peid', 'rtype'))
EDITION_BODY = u'''\
<div onclick="restoreInlinedEntity('%(parenteid)s', '%(rtype)s', '%(eid)s')" id="div-%(parenteid)s-%(rtype)s-%(eid)s" class="inlinedform">
......@@ -881,8 +877,7 @@ class TableEditForm(EntityForm):
class UnrelatedDivs(EntityView):
id = 'unrelateddivs'
__selectors__ = (match_form_params,)
form_params = ('relation',)
__selectors__ = (match_form_params('relation',),)
@property
def limit(self):
......@@ -993,7 +988,6 @@ class ComboboxView(EntityView):
THIS IS A TEXT VIEW. DO NOT HTML_ESCAPE
"""
id = 'combobox'
accepts = ('Any',)
title = None
def cell_call(self, row, col):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment