Merge lp:~leonardr/lazr.restful/grok-django into lp:lazr.restful

Proposed by Leonard Richardson
Status: Merged
Merged at revision: not available
Proposed branch: lp:~leonardr/lazr.restful/grok-django
Merge into: lp:lazr.restful
Diff against target: None lines
To merge this branch: bzr merge lp:~leonardr/lazr.restful/grok-django
Reviewer Review Type Date Requested Status
Celso Providelo (community) code Approve
Review via email: mp+11142@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Leonard Richardson (leonardr) wrote :

This branch removes almost all ZCML directives from django.zcml, replacing it with grok directives. Two things are worth mentioning:

1. I added a location_interface argument to the AbsoluteURLGrokker. Django apps use IDjangoLocation instead of ILocation.

2. I renamed lazr.restful.frameworks.django to lazr.restful.frameworks.restful_django. This is because I couldn't import django.foo from within django.py: it was masking the real "django" model. If there's any way around this I'd like to know about it.

Revision history for this message
Celso Providelo (cprov) wrote :

Leonard,

Grok directives to replace ZCML work gracefully, thanks for using them.

Gary, has pointed that we could use __import__ from 2.4 for importing django, then when 2.4 support dies we could use 2.5 and higher absolute/relative import behavior [1]

If it works fine, I think it's better than renaming the file.

[1] http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports

Other than that it's great, let's see it in action. Great job!

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/lazr/restful/directives/__init__.py'
2--- src/lazr/restful/directives/__init__.py 2009-09-03 14:10:38 +0000
3+++ src/lazr/restful/directives/__init__.py 2009-09-03 17:31:27 +0000
4@@ -104,6 +104,16 @@
5 return True
6
7
8+class location_interface(martian.Directive):
9+ """Directive to specify the location interface.
10+
11+ The default is zope.location.interfaces.ILocation
12+ """
13+ scope = martian.CLASS
14+ store = martian.ONCE
15+ default = ILocation
16+
17+
18 class AbsoluteURLGrokker(martian.ClassGrokker):
19 """Registers a strategy for generating an object's URL.
20
21@@ -111,7 +121,8 @@
22 AbsoluteURL.
23 """
24 martian.component(AbsoluteURL)
25- def execute(self, cls, config, *kw):
26+ martian.directive(location_interface)
27+ def execute(self, cls, config, location_interface, *kw):
28 getSiteManager().registerAdapter(
29- cls, (ILocation, IWebServiceLayer), IAbsoluteURL)
30+ cls, (location_interface, IWebServiceLayer), IAbsoluteURL)
31 return True
32
33=== modified file 'src/lazr/restful/docs/django.txt'
34--- src/lazr/restful/docs/django.txt 2009-08-19 17:03:30 +0000
35+++ src/lazr/restful/docs/django.txt 2009-09-03 17:31:27 +0000
36@@ -97,7 +97,7 @@
37 Now here's a subordinate resource that just implements IDjangoLocatino.
38
39 >>> from zope.interface import implements
40- >>> from lazr.restful.frameworks.django import IDjangoLocation
41+ >>> from lazr.restful.frameworks.restful_django import IDjangoLocation
42 >>> class SubordinateResource:
43 ... implements(IDjangoLocation)
44 ...
45@@ -179,7 +179,7 @@
46 The adapter class is ManagerSequencer.
47
48 >>> sequence
49- <lazr.restful.frameworks.django.ManagerSequencer...>
50+ <lazr.restful.frameworks.restful_django.ManagerSequencer...>
51
52 A ManagerSequencer object makes a Manager object act like a Python
53 list, which is what IFiniteSequence needs.
54
55=== modified file 'src/lazr/restful/frameworks/django.zcml'
56--- src/lazr/restful/frameworks/django.zcml 2009-08-19 13:52:39 +0000
57+++ src/lazr/restful/frameworks/django.zcml 2009-09-03 17:31:27 +0000
58@@ -1,45 +1,4 @@
59 <!-- -*- xml -*- -->
60-<configure xmlns="http://namespaces.zope.org/zope">
61-
62- <!--A Django model object can't implement ILocation, because its
63- metaclass prohibits us from defining the property __name__. We
64- suggest implementing IDjangoLocation (which uses __url_path__
65- instead of __name__), and define this adapter from
66- IDjangoLocation to ILocation.-->
67- <adapter
68- for="lazr.restful.frameworks.django.IDjangoLocation"
69- provides="zope.location.interfaces.ILocation"
70- factory="lazr.restful.frameworks.django.DjangoLocation" />
71-
72- <!--A class that implements IDjangoLocation can have a URL generated
73- for it with Zope's standard AbsoluteURL class.-->
74- <adapter
75- for="lazr.restful.frameworks.django.IDjangoLocation
76- lazr.restful.interfaces.IWebServiceClientRequest"
77- provides="zope.traversing.browser.interfaces.IAbsoluteURL"
78- factory="zope.traversing.browser.absoluteurl.AbsoluteURL"
79- />
80-
81- <!--We want a raised django.core.exceptions.ObjectDoesNotExist
82- object to result in a 404 status code. But we don't
83- control that class definition, so we can't annotate it.
84- Instead, we define an adapter from that exception class to the
85- NotFoundView.-->
86- <adapter
87- for="django.core.exceptions.ObjectDoesNotExist
88- lazr.restful.interfaces.IWebServiceClientRequest"
89- provides="zope.interface.Interface"
90- factory="lazr.restful.error.NotFoundView"
91- name="index.html"
92- />
93-
94- <!--What lazr.restful calls scoped collections (collections that are
95- fetched relative to a particular entry, such as a cookbook's
96- recipes) are handled in Django by Manager objects. By adapting
97- Managers to Zope's IFiniteSequence interface, we can batch their
98- data without having to change the Django side of things. -->
99- <adapter for="django.db.models.manager.Manager"
100- provides="zope.interface.common.sequence.IFiniteSequence"
101- factory="lazr.restful.frameworks.django.ManagerSequencer" />
102-
103+<configure xmlns:grok="http://namespaces.zope.org/grok">
104+ <grok:grok package="lazr.restful.frameworks.restful_django" />
105 </configure>
106
107=== renamed file 'src/lazr/restful/frameworks/django.py' => 'src/lazr/restful/frameworks/restful_django.py'
108--- src/lazr/restful/frameworks/django.py 2009-08-19 17:03:30 +0000
109+++ src/lazr/restful/frameworks/restful_django.py 2009-09-03 17:31:27 +0000
110@@ -12,6 +12,17 @@
111 from zope.interface import Interface, implements
112 from zope.interface.common.sequence import IFiniteSequence
113 from zope.location.interfaces import ILocation
114+from zope.traversing.browser.interfaces import IAbsoluteURL
115+from zope.traversing.browser.absoluteurl import AbsoluteURL
116+
117+import grokcore.component
118+from django.core.exceptions import ObjectDoesNotExist
119+from django.db.models.manager import Manager
120+
121+from lazr.restful import directives
122+from lazr.restful.interfaces import (
123+ IWebServiceLayer, IWebServiceClientRequest)
124+from lazr.restful.error import NotFoundView
125
126
127 class IDjangoLocation(Interface):
128@@ -28,6 +39,20 @@
129 def __parent__(self):
130 """This object's parent in the object tree."""
131
132+# We want a raised django.core.exceptions.ObjectDoesNotExist
133+# object to result in a 404 status code. But we don't
134+# control that class definition, so we can't annotate it.
135+# Instead, we define an adapter from that exception class to the
136+# NotFoundView
137+grokcore.component.global_adapter(
138+ NotFoundView, (ObjectDoesNotExist, IWebServiceClientRequest),
139+ Interface, name="index.html")
140+
141+
142+class DjangoAbsoluteURL(AbsoluteURL):
143+ """An AbsoluteURL implementation for Django."""
144+ directives.location_interface(IDjangoLocation)
145+
146
147 class DjangoLocation(object):
148 """Adapts Django model objects to ILocation.
149@@ -47,6 +72,7 @@
150 @property
151 def __name__(self):
152 return self.context.__url_path__
153+grokcore.component.global_adapter(DjangoLocation, IDjangoLocation, ILocation)
154
155
156 class ManagerSequencer(object):
157@@ -72,3 +98,4 @@
158 def __len__(self):
159 """Return the length of the dataset."""
160 return self.manager.count()
161+grokcore.component.global_adapter(ManagerSequencer, Manager, IFiniteSequence)

Subscribers

People subscribed via source and target branches