1 # copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
1 # copyright 2003-2016 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
3 # |
3 # |
4 # This file is part of CubicWeb. |
4 # This file is part of CubicWeb. |
5 # |
5 # |
6 # CubicWeb is free software: you can redistribute it and/or modify it under the |
6 # CubicWeb is free software: you can redistribute it and/or modify it under the |
21 |
21 |
22 from warnings import warn |
22 from warnings import warn |
23 from datetime import time, datetime, timedelta |
23 from datetime import time, datetime, timedelta |
24 |
24 |
25 from six import PY2, PY3, text_type |
25 from six import PY2, PY3, text_type |
26 from six.moves.urllib.parse import parse_qs, parse_qsl, quote as urlquote, unquote as urlunquote, urlsplit, urlunsplit |
26 from six.moves.urllib.parse import (parse_qs, parse_qsl, |
|
27 quote as urlquote, unquote as urlunquote, |
|
28 urlsplit, urlunsplit) |
27 |
29 |
28 from logilab.common.decorators import cached |
30 from logilab.common.decorators import cached |
29 from logilab.common.deprecation import deprecated |
31 from logilab.common.deprecation import deprecated |
30 from logilab.common.date import ustrftime, strptime, todate, todatetime |
32 from logilab.common.date import ustrftime, strptime, todate, todatetime |
31 |
33 |
36 from cubicweb.rset import ResultSet |
38 from cubicweb.rset import ResultSet |
37 |
39 |
38 ONESECOND = timedelta(0, 1, 0) |
40 ONESECOND = timedelta(0, 1, 0) |
39 CACHE_REGISTRY = {} |
41 CACHE_REGISTRY = {} |
40 |
42 |
|
43 |
41 class FindEntityError(Exception): |
44 class FindEntityError(Exception): |
42 """raised when find_one_entity() can not return one and only one entity""" |
45 """raised when find_one_entity() can not return one and only one entity""" |
|
46 |
43 |
47 |
44 class Cache(dict): |
48 class Cache(dict): |
45 def __init__(self): |
49 def __init__(self): |
46 super(Cache, self).__init__() |
50 super(Cache, self).__init__() |
47 _now = datetime.now() |
51 _now = datetime.now() |
57 |
61 |
58 :attribute vreg: the instance's registry |
62 :attribute vreg: the instance's registry |
59 :attribute vreg.schema: the instance's schema |
63 :attribute vreg.schema: the instance's schema |
60 :attribute vreg.config: the instance's configuration |
64 :attribute vreg.config: the instance's configuration |
61 """ |
65 """ |
62 is_request = True # False for repository session |
66 is_request = True # False for repository session |
63 |
67 |
64 def __init__(self, vreg): |
68 def __init__(self, vreg): |
65 self.vreg = vreg |
69 self.vreg = vreg |
66 try: |
70 try: |
67 encoding = vreg.property_value('ui.encoding') |
71 encoding = vreg.property_value('ui.encoding') |
68 except Exception: # no vreg or property not registered |
72 except Exception: # no vreg or property not registered |
69 encoding = 'utf-8' |
73 encoding = 'utf-8' |
70 self.encoding = encoding |
74 self.encoding = encoding |
71 # cache result of execution for (rql expr / eids), |
75 # cache result of execution for (rql expr / eids), |
72 # should be emptied on commit/rollback of the server session / web |
76 # should be emptied on commit/rollback of the server session / web |
73 # connection |
77 # connection |
115 return val |
119 return val |
116 return self.vreg.property_value(key) |
120 return self.vreg.property_value(key) |
117 |
121 |
118 def etype_rset(self, etype, size=1): |
122 def etype_rset(self, etype, size=1): |
119 """return a fake result set for a particular entity type""" |
123 """return a fake result set for a particular entity type""" |
120 rset = ResultSet([('A',)]*size, '%s X' % etype, |
124 rset = ResultSet([('A',)] * size, '%s X' % etype, |
121 description=[(etype,)]*size) |
125 description=[(etype,)] * size) |
|
126 |
122 def get_entity(row, col=0, etype=etype, req=self, rset=rset): |
127 def get_entity(row, col=0, etype=etype, req=self, rset=rset): |
123 return req.vreg['etypes'].etype_class(etype)(req, rset, row, col) |
128 return req.vreg['etypes'].etype_class(etype)(req, rset, row, col) |
|
129 |
124 rset.get_entity = get_entity |
130 rset.get_entity = get_entity |
125 rset.req = self |
131 rset.req = self |
126 return rset |
132 return rset |
127 |
133 |
128 def eid_rset(self, eid, etype=None): |
134 def eid_rset(self, eid, etype=None): |
253 cache = CACHE_REGISTRY[cachename] = Cache() |
259 cache = CACHE_REGISTRY[cachename] = Cache() |
254 _now = datetime.now() |
260 _now = datetime.now() |
255 if _now > cache.latest_cache_lookup + ONESECOND: |
261 if _now > cache.latest_cache_lookup + ONESECOND: |
256 ecache = self.execute( |
262 ecache = self.execute( |
257 'Any C,T WHERE C is CWCache, C name %(name)s, C timestamp T', |
263 'Any C,T WHERE C is CWCache, C name %(name)s, C timestamp T', |
258 {'name':cachename}).get_entity(0,0) |
264 {'name': cachename}).get_entity(0, 0) |
259 cache.latest_cache_lookup = _now |
265 cache.latest_cache_lookup = _now |
260 if not ecache.valid(cache.cache_creation_date): |
266 if not ecache.valid(cache.cache_creation_date): |
261 cache.clear() |
267 cache.clear() |
262 cache.cache_creation_date = _now |
268 cache.cache_creation_date = _now |
263 return cache |
269 return cache |
328 return urlunquote(quoted) |
334 return urlunquote(quoted) |
329 if isinstance(quoted, unicode): |
335 if isinstance(quoted, unicode): |
330 quoted = quoted.encode(self.encoding) |
336 quoted = quoted.encode(self.encoding) |
331 try: |
337 try: |
332 return unicode(urlunquote(quoted), self.encoding) |
338 return unicode(urlunquote(quoted), self.encoding) |
333 except UnicodeDecodeError: # might occurs on manually typed URLs |
339 except UnicodeDecodeError: # might occurs on manually typed URLs |
334 return unicode(urlunquote(quoted), 'iso-8859-1') |
340 return unicode(urlunquote(quoted), 'iso-8859-1') |
335 |
341 |
336 def url_parse_qsl(self, querystring): |
342 def url_parse_qsl(self, querystring): |
337 """return a list of (key, val) found in the url quoted query string""" |
343 """return a list of (key, val) found in the url quoted query string""" |
338 if PY3: |
344 if PY3: |
342 if isinstance(querystring, unicode): |
348 if isinstance(querystring, unicode): |
343 querystring = querystring.encode(self.encoding) |
349 querystring = querystring.encode(self.encoding) |
344 for key, val in parse_qsl(querystring): |
350 for key, val in parse_qsl(querystring): |
345 try: |
351 try: |
346 yield unicode(key, self.encoding), unicode(val, self.encoding) |
352 yield unicode(key, self.encoding), unicode(val, self.encoding) |
347 except UnicodeDecodeError: # might occurs on manually typed URLs |
353 except UnicodeDecodeError: # might occurs on manually typed URLs |
348 yield unicode(key, 'iso-8859-1'), unicode(val, 'iso-8859-1') |
354 yield unicode(key, 'iso-8859-1'), unicode(val, 'iso-8859-1') |
349 |
|
350 |
355 |
351 def rebuild_url(self, url, **newparams): |
356 def rebuild_url(self, url, **newparams): |
352 """return the given url with newparams inserted. If any new params |
357 """return the given url with newparams inserted. If any new params |
353 is already specified in the url, it's overriden by the new value |
358 is already specified in the url, it's overriden by the new value |
354 |
359 |
408 if initargs is None: |
413 if initargs is None: |
409 initargs = kwargs |
414 initargs = kwargs |
410 else: |
415 else: |
411 initargs.update(kwargs) |
416 initargs.update(kwargs) |
412 try: |
417 try: |
413 view = self.vreg[__registry].select(__vid, self, rset=rset, **initargs) |
418 view = self.vreg[__registry].select(__vid, self, rset=rset, **initargs) |
414 except NoSelectableObject: |
419 except NoSelectableObject: |
415 if __fallback_oid is None: |
420 if __fallback_oid is None: |
416 raise |
421 raise |
417 view = self.vreg[__registry].select(__fallback_oid, self, |
422 view = self.vreg[__registry].select(__fallback_oid, self, rset=rset, **initargs) |
418 rset=rset, **initargs) |
|
419 return view.render(w=w, **kwargs) |
423 return view.render(w=w, **kwargs) |
420 |
424 |
421 def printable_value(self, attrtype, value, props=None, displaytime=True, |
425 def printable_value(self, attrtype, value, props=None, displaytime=True, |
422 formatters=uilib.PRINTERS): |
426 formatters=uilib.PRINTERS): |
423 """return a displayablye value (i.e. unicode string)""" |
427 """return a displayablye value (i.e. unicode string)""" |
472 except ValueError: |
476 except ValueError: |
473 pass |
477 pass |
474 elif etype == 'Time': |
478 elif etype == 'Time': |
475 format = self.property_value('ui.time-format') |
479 format = self.property_value('ui.time-format') |
476 try: |
480 try: |
477 # (adim) I can't find a way to parse a Time with a custom format |
481 # (adim) I can't find a way to parse a time with a custom format |
478 date = strptime(value, format) # this returns a DateTime |
482 date = strptime(value, format) # this returns a datetime |
479 return time(date.hour, date.minute, date.second) |
483 return time(date.hour, date.minute, date.second) |
480 except ValueError: |
484 except ValueError: |
481 raise ValueError(self._('can\'t parse %(value)r (expected %(format)s)') |
485 raise ValueError(self._('can\'t parse %(value)r (expected %(format)s)') |
482 % {'value': value, 'format': format}) |
486 % {'value': value, 'format': format}) |
483 try: |
487 try: |