37 |
37 |
38 from logilab.common.deprecation import deprecated |
38 from logilab.common.deprecation import deprecated |
39 from logilab.common.decorators import classproperty |
39 from logilab.common.decorators import classproperty |
40 from logilab.common.logging_ext import set_log_methods |
40 from logilab.common.logging_ext import set_log_methods |
41 |
41 |
|
42 from cubicweb.cwconfig import CubicWebConfiguration |
|
43 |
|
44 def class_regid(cls): |
|
45 """returns a unique identifier for an appobject class""" |
|
46 if 'id' in cls.__dict__: |
|
47 warn('[3.6] %s.%s: id is deprecated, use __regid__' |
|
48 % (cls.__module__, cls.__name__), DeprecationWarning) |
|
49 cls.__regid__ = cls.id |
|
50 if hasattr(cls, 'id') and not isinstance(cls.id, property): |
|
51 return cls.id |
|
52 return cls.__regid__ |
|
53 |
|
54 # helpers for debugging selectors |
|
55 TRACED_OIDS = None |
|
56 |
|
57 def _trace_selector(cls, selector, args, ret): |
|
58 # /!\ lltrace decorates pure function or __call__ method, this |
|
59 # means argument order may be different |
|
60 if isinstance(cls, Selector): |
|
61 selname = str(cls) |
|
62 vobj = args[0] |
|
63 else: |
|
64 selname = selector.__name__ |
|
65 vobj = cls |
|
66 if TRACED_OIDS == 'all' or class_regid(vobj) in TRACED_OIDS: |
|
67 #SELECTOR_LOGGER.warning('selector %s returned %s for %s', selname, ret, cls) |
|
68 print '%s -> %s for %s(%s)' % (selname, ret, vobj, vobj.__regid__) |
|
69 |
|
70 def lltrace(selector): |
|
71 """use this decorator on your selectors so the becomes traceable with |
|
72 :class:`traced_selection` |
|
73 """ |
|
74 # don't wrap selectors if not in development mode |
|
75 if CubicWebConfiguration.mode == 'system': # XXX config.debug |
|
76 return selector |
|
77 def traced(cls, *args, **kwargs): |
|
78 ret = selector(cls, *args, **kwargs) |
|
79 if TRACED_OIDS is not None: |
|
80 _trace_selector(cls, selector, args, ret) |
|
81 return ret |
|
82 traced.__name__ = selector.__name__ |
|
83 traced.__doc__ = selector.__doc__ |
|
84 return traced |
|
85 |
|
86 class traced_selection(object): |
|
87 """ |
|
88 Typical usage is : |
|
89 |
|
90 .. sourcecode:: python |
|
91 |
|
92 >>> from cubicweb.selectors import traced_selection |
|
93 >>> with traced_selection(): |
|
94 ... # some code in which you want to debug selectors |
|
95 ... # for all objects |
|
96 |
|
97 Don't forget the 'from __future__ import with_statement' at the module top-level |
|
98 if you're using python prior to 2.6. |
|
99 |
|
100 This will yield lines like this in the logs:: |
|
101 |
|
102 selector one_line_rset returned 0 for <class 'cubicweb.web.views.basecomponents.WFHistoryVComponent'> |
|
103 |
|
104 You can also give to :class:`traced_selection` the identifiers of objects on |
|
105 which you want to debug selection ('oid1' and 'oid2' in the example above). |
|
106 |
|
107 .. sourcecode:: python |
|
108 |
|
109 >>> with traced_selection( ('regid1', 'regid2') ): |
|
110 ... # some code in which you want to debug selectors |
|
111 ... # for objects with __regid__ 'regid1' and 'regid2' |
|
112 |
|
113 A potentially usefull point to set up such a tracing function is |
|
114 the `cubicweb.vregistry.Registry.select` method body. |
|
115 """ |
|
116 |
|
117 def __init__(self, traced='all'): |
|
118 self.traced = traced |
|
119 |
|
120 def __enter__(self): |
|
121 global TRACED_OIDS |
|
122 TRACED_OIDS = self.traced |
|
123 |
|
124 def __exit__(self, exctype, exc, traceback): |
|
125 global TRACED_OIDS |
|
126 TRACED_OIDS = None |
|
127 return traceback is None |
42 |
128 |
43 # selector base classes and operations ######################################## |
129 # selector base classes and operations ######################################## |
44 |
130 |
45 def objectify_selector(selector_func): |
131 def objectify_selector(selector_func): |
46 """Most of the time, a simple score function is enough to build a selector. |
132 """Most of the time, a simple score function is enough to build a selector. |
197 class NotSelector(Selector): |
285 class NotSelector(Selector): |
198 """negation selector""" |
286 """negation selector""" |
199 def __init__(self, selector): |
287 def __init__(self, selector): |
200 self.selector = selector |
288 self.selector = selector |
201 |
289 |
|
290 @lltrace |
202 def __call__(self, cls, *args, **kwargs): |
291 def __call__(self, cls, *args, **kwargs): |
203 score = self.selector(cls, *args, **kwargs) |
292 score = self.selector(cls, *args, **kwargs) |
204 return int(not score) |
293 return int(not score) |
205 |
294 |
206 def __str__(self): |
295 def __str__(self): |