[Checkins] SVN: grok/trunk/ Change grok.traverse decorator to
simply looking for 'traverse' method
Martijn Faassen
faassen at infrae.com
Tue Oct 31 13:22:02 EST 2006
Log message for revision 71015:
Change grok.traverse decorator to simply looking for 'traverse' method
on the model. Make 'traverse' method work for containers so that
it's not necessary anymore to always define a traverse method on it,
simplifying grokwiki.
Changed:
U grok/trunk/grokwiki/src/grokwiki/wiki.py
U grok/trunk/src/grok/__init__.py
U grok/trunk/src/grok/_grok.py
U grok/trunk/src/grok/components.py
A grok/trunk/src/grok/ftests/traversal/containertraverse.py
U grok/trunk/src/grok/ftests/traversal/modeltraverse.py
U grok/trunk/src/grok/ftests/traversal/traverser.py
D grok/trunk/src/grok/tests/traversal/bogustraverse.py
-=-
Modified: grok/trunk/grokwiki/src/grokwiki/wiki.py
===================================================================
--- grok/trunk/grokwiki/src/grokwiki/wiki.py 2006-10-31 17:26:07 UTC (rev 71014)
+++ grok/trunk/grokwiki/src/grokwiki/wiki.py 2006-10-31 18:22:01 UTC (rev 71015)
@@ -20,11 +20,6 @@
class Wiki(grok.Container):
"""This is our wiki application wich contains all wiki pages."""
- @grok.traverse
- def getWikiPage(self, name):
- # XXX This should be the default of grok.Container
- return self[name]
-
class WikiIndex(grok.View):
grok.name('index')
Modified: grok/trunk/src/grok/__init__.py
===================================================================
--- grok/trunk/src/grok/__init__.py 2006-10-31 17:26:07 UTC (rev 71014)
+++ grok/trunk/src/grok/__init__.py 2006-10-31 18:22:01 UTC (rev 71015)
@@ -35,7 +35,6 @@
from grok.directive import context, name, template, templatedir
from grok._grok import do_grok as grok # Avoid name clash within _grok
from grok._grok import SubscribeDecorator as subscribe
-from grok._grok import traverseDecorator as traverse
from grok.error import GrokError, GrokImportError
# Our __init__ provides the grok API directly so using 'import grok' is enough.
Modified: grok/trunk/src/grok/_grok.py
===================================================================
--- grok/trunk/src/grok/_grok.py 2006-10-31 17:26:07 UTC (rev 71014)
+++ grok/trunk/src/grok/_grok.py 2006-10-31 18:22:01 UTC (rev 71015)
@@ -43,6 +43,8 @@
_bootstrapped = False
def bootstrap():
component.provideAdapter(components.ModelTraverser)
+ component.provideAdapter(components.ContainerTraverser)
+
# register the name 'index' as the default view name
component.provideAdapter('index',
adapts=(grok.Model, IBrowserRequest),
@@ -369,14 +371,3 @@
if subscribers is None:
frame.f_locals['__grok_subscribers__'] = subscribers = []
subscribers.append((function, self.subscribed))
-
-def traverseDecorator(function):
- frame = sys._getframe(1)
- if not frame_is_class(frame):
- raise GrokImportError("@grok.traverse can only be used on class "
- "level.")
-
- if '__grok_traverse__' in frame.f_locals:
- raise GrokImportError("@grok.traverse can only be used once per class.")
-
- frame.f_locals['__grok_traverse__'] = function
Modified: grok/trunk/src/grok/components.py
===================================================================
--- grok/trunk/src/grok/components.py 2006-10-31 17:26:07 UTC (rev 71014)
+++ grok/trunk/src/grok/components.py 2006-10-31 18:22:01 UTC (rev 71015)
@@ -228,11 +228,22 @@
component.adapts(Model, IBrowserRequest)
def traverse(self, name):
- traverser = util.class_annotation(self.context, 'grok.traverse', None)
- if traverser:
- return traverser(name)
+ traverse = getattr(self.context, 'traverse', None)
+ if traverse:
+ return traverse(name)
+class ContainerTraverser(Traverser):
+ component.adapts(Container, IBrowserRequest)
+ def traverse(self, name):
+ traverse = getattr(self.context, 'traverse', None)
+ if traverse:
+ result = traverse(name)
+ if result is not None:
+ return result
+ # try to get the item from the container
+ return self.context.get(name)
+
class Form(View):
def _init(self):
fields = schema_fields(self.context)
Added: grok/trunk/src/grok/ftests/traversal/containertraverse.py
===================================================================
--- grok/trunk/src/grok/ftests/traversal/containertraverse.py 2006-10-31 17:26:07 UTC (rev 71014)
+++ grok/trunk/src/grok/ftests/traversal/containertraverse.py 2006-10-31 18:22:01 UTC (rev 71015)
@@ -0,0 +1,86 @@
+"""
+Containers can determine how they want to be traversed by
+implementing a 'traverse' method, but the behavior falls back to
+basic container traversal if the 'traverse' method returns None:
+
+ >>> import grok
+ >>> from grok.ftests.traversal.containertraverse import Herd, Mammoth
+ >>> grok.grok('grok.ftests.traversal.containertraverse')
+ >>> getRootFolder()["herd"] = herd = Herd()
+ >>> herd['manfred'] = Mammoth('Manfred')
+ >>> herd['ellie'] = Mammoth('Ellie')
+
+Let's first try to look up the special traversed item:
+
+ >>> from zope.testbrowser.testing import Browser
+ >>> browser = Browser()
+ >>> browser.handleErrors = False
+ >>> browser.open("http://localhost/herd/special")
+ >>> print browser.contents
+ special view
+ >>> browser.open("http://localhost/herd/special/index")
+ >>> print browser.contents
+ special view
+
+Even if we have a container item called 'special', we should still
+get our special object:
+
+ >>> herd['special'] = Mammoth('Special invisible mammoth')
+ >>> browser.open("http://localhost/herd/special")
+ >>> print browser.contents
+ special view
+ >>> browser.open("http://localhost/herd/special/index")
+ >>> print browser.contents
+ special view
+
+The fall-back behavior should work for items that aren't traversed:
+
+ >>> browser.open("http://localhost/herd/manfred")
+ >>> print browser.contents
+ <html>
+ <body>
+ <h1>Hello, Manfred!</h1>
+ </body>
+ </html>
+
+ >>> browser.open("http://localhost/herd/ellie")
+ >>> print browser.contents
+ <html>
+ <body>
+ <h1>Hello, Ellie!</h1>
+ </body>
+ </html>
+
+"""
+import grok
+
+class Herd(grok.Container):
+
+ def traverse(self, name):
+ if name == 'special':
+ return Special()
+ return None
+
+class Mammoth(grok.Model):
+
+ def __init__(self, name):
+ self.name = name
+
+class Special(grok.Model):
+ pass
+
+class SpecialIndex(grok.View):
+ grok.context(Special)
+ grok.name('index')
+
+ def render(self):
+ return "special view"
+
+grok.context(Mammoth)
+index = grok.PageTemplate("""\
+<html>
+<body>
+<h1>Hello, <span tal:replace="context/name/title" />!</h1>
+</body>
+</html>
+""")
Modified: grok/trunk/src/grok/ftests/traversal/modeltraverse.py
===================================================================
--- grok/trunk/src/grok/ftests/traversal/modeltraverse.py 2006-10-31 17:26:07 UTC (rev 71014)
+++ grok/trunk/src/grok/ftests/traversal/modeltraverse.py 2006-10-31 18:22:01 UTC (rev 71015)
@@ -1,6 +1,6 @@
"""
-Models can determine how they want to be traversed by using the
-``@grok.traverse`` decorator:
+Models can determine how they want to be traversed by
+implementing a 'traverse' method:
>>> import grok
>>> from grok.ftests.traversal.modeltraverse import Herd
@@ -31,10 +31,12 @@
class Herd(grok.Model):
- @grok.traverse
def getMammoth(self, name):
return Mammoth(name)
+ def traverse(self, name):
+ return self.getMammoth(name)
+
class Mammoth(grok.Model):
def __init__(self, name):
Modified: grok/trunk/src/grok/ftests/traversal/traverser.py
===================================================================
--- grok/trunk/src/grok/ftests/traversal/traverser.py 2006-10-31 17:26:07 UTC (rev 71014)
+++ grok/trunk/src/grok/ftests/traversal/traverser.py 2006-10-31 18:22:01 UTC (rev 71015)
@@ -1,5 +1,5 @@
"""
-Apart from using the ``@grok.traverse`` decorator on a model, you can
+Apart from using the ``traverse`` method on a model, you can
also create a separate traverser component:
>>> import grok
Deleted: grok/trunk/src/grok/tests/traversal/bogustraverse.py
===================================================================
--- grok/trunk/src/grok/tests/traversal/bogustraverse.py 2006-10-31 17:26:07 UTC (rev 71014)
+++ grok/trunk/src/grok/tests/traversal/bogustraverse.py 2006-10-31 18:22:01 UTC (rev 71015)
@@ -1,35 +0,0 @@
-"""
-You can't use @grok.traverse more than once on a class:
-
- >>> using_traverse_twice()
- Traceback (most recent call last):
- ...
- GrokImportError: @grok.traverse can only be used once per class.
-
-You can't use @grok.traverse outside a class definition:
-
- >>> outside_class()
- Traceback (most recent call last):
- ...
- GrokImportError: @grok.traverse can only be used on class level.
-
-
-"""
-import grok
-
-def using_traverse_twice():
- class Herd(grok.Model):
-
- @grok.traverse
- def getMammoth(self, name):
- pass
-
- @grok.traverse
- def getAntilope(self, name):
- pass
-
-def outside_class():
-
- @grok.traverse
- def getMammoth(self, name):
- pass
More information about the Checkins
mailing list