Skip to content

Commit

Permalink
Backport fix for not registering methods with names that
Browse files Browse the repository at this point in the history
start with an '_' as views on REST, XMLRPC and JSON components.
  • Loading branch information
janwijbrand committed Jan 7, 2008
1 parent e5152a8 commit c3998e6
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 11 deletions.
6 changes: 6 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ Grok changes
Bug fixes
---------

* Do not register the publishTraverse and browserDefault methods of the
JSON component as views.

* Methods with names that start with an '_' are not registered as views
for XMLRPC, REST and JSON components.

* Use a configuration action for the registration of the static directory.

* Fix https://bugs.launchpad.net/grok/+bug/161948: grok.testing.grok()
Expand Down
22 changes: 14 additions & 8 deletions src/grok/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
import grok
from grok import components, formlib, templatereg
from grok.util import check_adapts, get_default_permission, make_checker
from grok.util import determine_class_directive
from grok.util import determine_class_directive, public_methods_from_class
from grok.rest import RestPublisher
from grok.interfaces import IRESTSkinType

Expand Down Expand Up @@ -130,9 +130,8 @@ class XMLRPCGrokker(martian.ClassGrokker):
def grok(self, name, factory, module_info, config, **kw):
context = module_info.getAnnotation('grok.context', None)
view_context = util.determine_class_context(factory, context)
# XXX We should really not make __FOO__ methods available to
# the outside -- need to discuss how to restrict such things.
methods = util.methods_from_class(factory)

methods = public_methods_from_class(factory)

default_permission = get_default_permission(factory)

Expand Down Expand Up @@ -174,9 +173,8 @@ class RESTGrokker(martian.ClassGrokker):
def grok(self, name, factory, module_info, config, **kw):
context = module_info.getAnnotation('grok.context', None)
view_context = util.determine_class_context(factory, context)
# XXX We should really not make __FOO__ methods available to
# the outside -- need to discuss how to restrict such things.
methods = util.methods_from_class(factory)

methods = public_methods_from_class(factory)

default_permission = get_default_permission(factory)

Expand Down Expand Up @@ -294,11 +292,19 @@ class JSONGrokker(martian.ClassGrokker):
def grok(self, name, factory, module_info, config, **kw):
context = module_info.getAnnotation('grok.context', None)
view_context = util.determine_class_context(factory, context)
methods = util.methods_from_class(factory)

methods = public_methods_from_class(factory)

default_permission = get_default_permission(factory)

for method in methods:
# The grok.JSON component inherits methods from its baseclass
# (being zope.publisher.browser.BrowserPage) with names that
# do not start with an underscore, but should still not
# be registered as views. Ignore these methods:
if method.__name__ in ['browserDefault', 'publishTraverse']:
continue

# Create a new class with a __view_name__ attribute so the
# JSON class knows what method to call.
method_view = type(
Expand Down
46 changes: 44 additions & 2 deletions src/grok/tests/json/view_lookup.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,44 @@
>>> view = getMultiAdapter((mammoth, request), name='another')
>>> view()
'{"another": "grok"}'
Although principally all methods of the JSON class are registered as views,
methods with names that start with an underscore are not::
>>> view = getMultiAdapter((mammoth, request), name='_private')
Traceback (most recent call last):
...
ComponentLookupError: ((<grok.tests.json.view_lookup.Mammoth object at ...>,
<zope.publisher.browser.TestRequest instance URL=http://127.0.0.1>),
<InterfaceClass zope.interface.Interface>, '_private')
Even more important, special methods like __call__ are not registered as viewws
too. This test is here to make sure a previous bug has been fixed::
>>> view = getMultiAdapter((mammoth, request), name='__call__')
Traceback (most recent call last):
...
ComponentLookupError: ((<grok.tests.json.view_lookup.Mammoth object at ...>,
<zope.publisher.browser.TestRequest instance URL=http://127.0.0.1>),
<InterfaceClass zope.interface.Interface>, '__call__')
For JSON views we also need to confirm some methods that are defined on the
baseclass (BrowserPage) are not registered as views::
>>> view = getMultiAdapter((mammoth, request), name='browserDefault')
Traceback (most recent call last):
...
ComponentLookupError: ((<grok.tests.json.view_lookup.Mammoth object at ...>,
<zope.publisher.browser.TestRequest instance URL=http://127.0.0.1>),
<InterfaceClass zope.interface.Interface>, 'browserDefault')
>>> view = getMultiAdapter((mammoth, request), name='publishTraverse')
Traceback (most recent call last):
...
ComponentLookupError: ((<grok.tests.json.view_lookup.Mammoth object at ...>,
<zope.publisher.browser.TestRequest instance URL=http://127.0.0.1>),
<InterfaceClass zope.interface.Interface>, 'publishTraverse')
"""
import grok

Expand All @@ -35,4 +72,9 @@ def run(self):

def another(self):
return { 'another': 'grok'}


class SecondMammothView(grok.JSON):
grok.context(Mammoth)

def _private(self):
return {'should': 'not be registered'}
28 changes: 28 additions & 0 deletions src/grok/tests/util/public_methods_from_class.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""
>>> methods = grok.util.public_methods_from_class(A)
>>> sorted([m.__name__ for m in methods])
['should_also_be_public', 'should_be_public']
"""
import grok
import grok.util

class A(object):

def __init__(self):
pass # this method is ignored

def __call__(self):
pass # this method is ignored

def __double_underscored(self):
pass # this method is ignored

def _single_underscored(self):
pass # this method is ignored

def should_be_public(self):
pass # this method is found

def should_also_be_public(self):
pass # this method is found
6 changes: 5 additions & 1 deletion src/grok/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from zope.security.interfaces import IPermission

from martian.error import GrokError, GrokImportError
from martian.util import class_annotation
from martian.util import class_annotation, methods_from_class

def check_adapts(class_):
if component.adaptedBy(class_) is None:
Expand Down Expand Up @@ -105,3 +105,7 @@ def determine_class_directive(directive_name, factory, module_info,
if directive is not None:
return directive
return default

def public_methods_from_class(factory):
return [m for m in methods_from_class(factory) if \
not m.__name__.startswith('_')]

0 comments on commit c3998e6

Please sign in to comment.