cubicweb/req.py
changeset 11348 70337ad23145
parent 11057 0b59724cb3f2
child 11699 b48020a80dc3
equal deleted inserted replaced
11347:b4dcfd734686 11348:70337ad23145
     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: