# HG changeset patch # User Aurelien Campeas # Date 1339166827 -7200 # Node ID c9ab72f0645dece3ece6d2a59d38783e77dc5b24 # Parent 150191e45ee5e783d94361d35638ecbcf3520da7 [registry|ajaxcontroller] the @ajaxcontroller decorator ought to return a compatible object (closes #2385155) diff -r 150191e45ee5 -r c9ab72f0645d cwvreg.py --- a/cwvreg.py Thu Jun 07 18:33:53 2012 +0200 +++ b/cwvreg.py Fri Jun 08 16:47:07 2012 +0200 @@ -256,6 +256,12 @@ key=lambda x: x.cw_propval('order')) +def related_appobject(obj, appobjectattr='__appobject__'): + """ adapts any object to a potential appobject bound to it + through the __appobject__ attribute + """ + return getattr(obj, appobjectattr, obj) + class ETypeRegistry(CWRegistry): @@ -272,6 +278,7 @@ self.clear_caches() def register(self, obj, **kwargs): + obj = related_appobject(obj) oid = kwargs.get('oid') or obj.__regid__ if oid != 'Any' and not oid in self.schema: self.error('don\'t register %s, %s type not defined in the ' @@ -537,6 +544,20 @@ def itervalues(self): return (value for key, value in self.items()) + def load_module(self, module): + """ variation from the base implementation: + apply related_appobject to the automatically registered objects + """ + self.info('loading %s from %s', module.__name__, module.__file__) + if hasattr(module, 'registration_callback'): + module.registration_callback(self) + return + for objname, obj in vars(module).iteritems(): + if objname.startswith('_'): + continue + self._load_ancestors_then_object(module.__name__, + related_appobject(obj)) + def reset(self): CW_EVENT_MANAGER.emit('before-registry-reset', self) super(CWRegistryStore, self).reset() @@ -552,6 +573,17 @@ self.register_property(key, **propdef) CW_EVENT_MANAGER.emit('after-registry-reset', self) + def register_all(self, objects, modname, butclasses=()): + butclasses = set(related_appobject(obj) + for obj in butclasses) + objects = [related_appobject(obj) for obj in objects] + super(CWRegistryStore, self).register_all(objects, modname, butclasses) + + def register_and_replace(self, obj, replaced): + obj = related_appobject(obj) + replaced = related_appobject(replaced) + super(CWRegistryStore, self).register_and_replace(obj, replaced) + def set_schema(self, schema): """set instance'schema and load application objects""" self._set_schema(schema) @@ -624,6 +656,7 @@ If `clear` is true, all objects with the same identifier will be previously unregistered. """ + obj = related_appobject(obj) super(CWRegistryStore, self).register(obj, *args, **kwargs) # XXX bw compat ifaces = use_interfaces(obj) diff -r 150191e45ee5 -r c9ab72f0645d web/test/unittest_views_basecontrollers.py --- a/web/test/unittest_views_basecontrollers.py Thu Jun 07 18:33:53 2012 +0200 +++ b/web/test/unittest_views_basecontrollers.py Fri Jun 08 16:47:07 2012 +0200 @@ -695,38 +695,44 @@ @ajaxfunc def foo(self, x, y): return 'hello' - self.assertTrue(issubclass(foo, AjaxFunction)) - self.assertEqual(foo.__regid__, 'foo') - self.assertEqual(foo.check_pageid, False) - self.assertEqual(foo.output_type, None) + self.assertEqual(foo(object, 1, 2), 'hello') + appobject = foo.__appobject__ + self.assertTrue(issubclass(appobject, AjaxFunction)) + self.assertEqual(appobject.__regid__, 'foo') + self.assertEqual(appobject.check_pageid, False) + self.assertEqual(appobject.output_type, None) req = self.request() - f = foo(req) + f = appobject(req) self.assertEqual(f(12, 13), 'hello') def test_ajaxfunc_checkpageid(self): - @ajaxfunc( check_pageid=True) + @ajaxfunc(check_pageid=True) def foo(self, x, y): - pass - self.assertTrue(issubclass(foo, AjaxFunction)) - self.assertEqual(foo.__regid__, 'foo') - self.assertEqual(foo.check_pageid, True) - self.assertEqual(foo.output_type, None) + return 'hello' + self.assertEqual(foo(object, 1, 2), 'hello') + appobject = foo.__appobject__ + self.assertTrue(issubclass(appobject, AjaxFunction)) + self.assertEqual(appobject.__regid__, 'foo') + self.assertEqual(appobject.check_pageid, True) + self.assertEqual(appobject.output_type, None) # no pageid req = self.request() - f = foo(req) + f = appobject(req) self.assertRaises(RemoteCallFailed, f, 12, 13) def test_ajaxfunc_json(self): @ajaxfunc(output_type='json') def foo(self, x, y): return x + y - self.assertTrue(issubclass(foo, AjaxFunction)) - self.assertEqual(foo.__regid__, 'foo') - self.assertEqual(foo.check_pageid, False) - self.assertEqual(foo.output_type, 'json') + self.assertEqual(foo(object, 1, 2), 3) + appobject = foo.__appobject__ + self.assertTrue(issubclass(appobject, AjaxFunction)) + self.assertEqual(appobject.__regid__, 'foo') + self.assertEqual(appobject.check_pageid, False) + self.assertEqual(appobject.output_type, 'json') # no pageid req = self.request() - f = foo(req) + f = appobject(req) self.assertEqual(f(12, 13), '25') diff -r 150191e45ee5 -r c9ab72f0645d web/views/ajaxcontroller.py --- a/web/views/ajaxcontroller.py Thu Jun 07 18:33:53 2012 +0200 +++ b/web/views/ajaxcontroller.py Fri Jun 08 16:47:07 2012 +0200 @@ -283,11 +283,21 @@ if data is None: raise RemoteCallFailed(self._cw._('pageid-not-found')) return self.serialize(implementation(self, *args, **kwargs)) + AnAjaxFunc.__name__ = implementation.__name__ # make sure __module__ refers to the original module otherwise # vreg.register(obj) will ignore ``obj``. AnAjaxFunc.__module__ = implementation.__module__ - return AnAjaxFunc + # relate the ``implementation`` object to its wrapper appobject + # will be used by e.g.: + # import base_module + # @ajaxfunc + # def foo(self): + # return 42 + # assert foo(object) == 42 + # vreg.register_and_replace(foo, base_module.older_foo) + implementation.__appobject__ = AnAjaxFunc + return implementation def ajaxfunc(implementation=None, selector=yes(), output_type=None,