[IMP] new routing thing
authorXavier Morel <xmo@openerp.com>
Fri, 15 Nov 2013 10:09:01 +0000 (11:09 +0100)
committerXavier Morel <xmo@openerp.com>
Fri, 15 Nov 2013 10:09:01 +0000 (11:09 +0100)
* fix nameerror on SessionExpired exception not being imported
* remove pointless RequestUID instantiation by single placeholder object
  - may be replaceable with a LocalProxy or something along those lines?
* rename default/nodb routing map
* make better use of werkzeug API
* move lazy routing_map instantiation to property in ir_http.find_handler
  - do we have some sort of lazy_property?

bzr revid: xmo@openerp.com-20131115100901-s3skmwv9d1jgk9y0

openerp/addons/base/ir/ir_http.py
openerp/http.py

index adfc73a..f5c5f84 100644 (file)
@@ -9,12 +9,13 @@ import werkzeug.routing
 import openerp
 from openerp import http
 from openerp.http import request
-from openerp.osv import osv
+from openerp.osv import osv, orm
 
 _logger = logging.getLogger(__name__)
 
-class RequestUID(object):
-    pass
+
+# FIXME: replace by proxy on request.uid?
+_uid = object()
 
 class ModelConverter(werkzeug.routing.BaseConverter):
 
@@ -28,7 +29,7 @@ class ModelConverter(werkzeug.routing.BaseConverter):
         # TODO:
         # - raise routing.ValidationError() if no browse record can be createdm
         # - support slug 
-        return request.registry[self.model].browse(request.cr, RequestUID(), int(value), context=request.context)
+        return request.registry[self.model].browse(request.cr, _uid, int(value), context=request.context)
 
     def to_url(self, value):
         return value.id
@@ -45,10 +46,10 @@ class ModelsConverter(werkzeug.routing.BaseConverter):
         # TODO:
         # - raise routing.ValidationError() if no browse record can be createdm
         # - support slug
-        return request.registry[self.model].browse(request.cr, RequestUID(), [int(i) for i in value.split(',')], context=request.context)
+        return request.registry[self.model].browse(request.cr, _uid, [int(i) for i in value.split(',')], context=request.context)
 
     def to_url(self, value):
-        return ",".join([i.id for i in value])
+        return ",".join(i.id for i in value)
 
 class ir_http(osv.AbstractModel):
     _name = 'ir.http'
@@ -59,30 +60,16 @@ class ir_http(osv.AbstractModel):
         return {'model': ModelConverter, 'models': ModelsConverter}
 
     def _find_handler(self):
-        # TODO move to __init__(self, registry, cr)
-        if not hasattr(self, 'routing_map'):
-            _logger.info("Generating routing map")
-            cr = request.cr
-            m = request.registry.get('ir.module.module')
-            ids = m.search(cr, openerp.SUPERUSER_ID, [('state', '=', 'installed'), ('name', '!=', 'web')])
-            installed = set(x['name'] for x in m.read(cr, 1, ids, ['name']))
-            mods = ['', "web"] + sorted(installed)
-            self.routing_map = http.routing_map(mods, False, converters=self._get_converters())
-
-        # fallback to non-db handlers
-        path = request.httprequest.path
-        urls = self.routing_map.bind_to_environ(request.httprequest.environ)
-
-        return urls.match(path)
+        return self.routing_map.bind_to_environ(request.httprequest.environ).match()
 
     def _auth_method_user(self):
         request.uid = request.session.uid
         if not request.uid:
-            raise SessionExpiredException("Session expired")
+            raise http.SessionExpiredException("Session expired")
 
     def _auth_method_admin(self):
         if not request.db:
-            raise SessionExpiredException("No valid database for request %s" % request.httprequest)
+            raise http.SessionExpiredException("No valid database for request %s" % request.httprequest)
         request.uid = openerp.SUPERUSER_ID
 
     def _auth_method_none(self):
@@ -94,9 +81,12 @@ class ir_http(osv.AbstractModel):
         if request.session.uid:
             try:
                 request.session.check_security()
-            except SessionExpiredException, e:
+                # what if error in security.check()
+                #   -> res_users.check()
+                #   -> res_users.check_credentials()
+            except http.SessionExpiredException:
                 request.session.logout()
-                raise SessionExpiredException("Session expired for request %s" % request.httprequest)
+                raise http.SessionExpiredException("Session expired for request %s" % request.httprequest)
         getattr(self, "_auth_method_%s" % auth_method)()
         return auth_method
 
@@ -124,27 +114,33 @@ class ir_http(osv.AbstractModel):
 
         # post process arg to set uid on browse records
         for arg in arguments:
-            if isinstance(arg, openerp.osv.orm.browse_record) and isinstance(arg._uid, RequestUID):
+            if isinstance(arg, orm.browse_record) and arg._uid is _uid:
                 arg._uid = request.uid
 
         # set and execute handler
         try:
             request.set_handler(func, arguments, auth_method)
             result = request.dispatch()
-        except werkzeug.exceptions.HTTPException, e:
-            fn = getattr(self, '_handle_%s' % (e.code,), None)
-            if not fn:
-                fn = self._handle_500
-            return fn(e)
+            if isinstance(result, Exception):
+                raise result
         except Exception, e:
-            return self._handle_500(e)
-
-        if isinstance(result, werkzeug.exceptions.HTTPException):
-            fn = getattr(self, '_handle_%s' % (result.code,), None)
-            if not fn:
-                fn = self._handle_500
-            return fn(result)
+            fn = getattr(self, '_handle_%s' % getattr(e, 'code', 500),
+                         self._handle_500)
+            return fn(e)
 
         return result
 
+    @property
+    def routing_map(self):
+        if not hasattr(self, '_routing_map'):
+            _logger.info("Generating routing map")
+            cr = request.cr
+            m = request.registry.get('ir.module.module')
+            ids = m.search(cr, openerp.SUPERUSER_ID, [('state', '=', 'installed'), ('name', '!=', 'web')], context=request.context)
+            installed = set(x['name'] for x in m.read(cr, 1, ids, ['name'], context=request.context))
+            mods = ['', "web"] + sorted(installed)
+            self._routing_map = http.routing_map(mods, False, converters=self._get_converters())
+
+        return self._routing_map
+
 # vim:et:
index a7964be..126360e 100644 (file)
@@ -4,6 +4,7 @@
 #----------------------------------------------------------
 import ast
 import cgi
+import collections
 import contextlib
 import errno
 import functools
@@ -467,7 +468,7 @@ def set_request(req):
 #----------------------------------------------------------
 addons_module = {}
 addons_manifest = {}
-controllers_per_module = {}
+controllers_per_module = collections.defaultdict(list)
 
 class ControllerType(type):
     def __init__(cls, name, bases, attrs):
@@ -492,7 +493,7 @@ class ControllerType(type):
         # but we only store controllers directly inheriting from Controller
         if not "Controller" in globals() or not Controller in bases:
             return
-        controllers_per_module.setdefault(module, []).append(name_class)
+        controllers_per_module[module].append(name_class)
 
 class Controller(object):
     __metaclass__ = ControllerType
@@ -502,9 +503,8 @@ def routing_map(modules, nodb_only, converters=None):
     for module in modules:
         if module not in controllers_per_module:
             continue
-        for v in controllers_per_module[module]:
-            cls = v[1]
 
+        for _, cls in controllers_per_module[module]:
             subclasses = cls.__subclasses__()
             subclasses = [c for c in subclasses if c.__module__.startswith('openerp.addons.') and c.__module__.split(".")[2] in modules]
             if subclasses:
@@ -867,7 +867,7 @@ class Root(object):
         self.load_addons()
 
         _logger.info("Generating nondb routing")
-        self.routing_map = routing_map(['', "web"], True)
+        self.nodb_routing_map = routing_map(['', "web"], True)
 
     def __call__(self, environ, start_response):
         """ Handle a WSGI request
@@ -938,8 +938,7 @@ class Root(object):
 
     def get_response(self, httprequest, result, explicit_session):
         if isinstance(result, basestring):
-            headers=[('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', len(result))]
-            response = werkzeug.wrappers.Response(result, headers=headers)
+            response = werkzeug.wrappers.Response(result, mimetype='text/html')
         else:
             response = result
 
@@ -979,8 +978,7 @@ class Root(object):
                     openerp.modules.registry.RegistryManager.signal_caches_change(db)
                 else:
                     # fallback to non-db handlers
-                    urls = self.routing_map.bind_to_environ(request.httprequest.environ)
-                    func, arguments = urls.match(request.httprequest.path)
+                    func, arguments = self.nodb_routing_map.bind_to_environ(request.httprequest.environ).match()
                     request.set_handler(func, arguments, "none")
                     result = request.dispatch()
             response =  self.get_response(httprequest, result, explicit_session)
@@ -1027,7 +1025,7 @@ def db_monodb(httprequest=None):
     return None
 
 #----------------------------------------------------------
-# RPC controlller
+# RPC controller
 #----------------------------------------------------------
 class CommonController(Controller):