vendor/Five/1.2b-r20590

view fiveconfigure.py @ 0:3673ed425f80

Vendor import of Five 1.2b+ (r20590)
author fguillaume
date Fri, 02 Dec 2005 20:25:42 +0000
parents
children
line source
1 ##############################################################################
2 #
3 # Copyright (c) 2004, 2005 Zope Corporation and Contributors.
4 # All Rights Reserved.
5 #
6 # This software is subject to the provisions of the Zope Public License,
7 # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
8 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11 # FOR A PARTICULAR PURPOSE.
12 #
13 ##############################################################################
14 """Five-specific directive handlers
16 These directives are specific to Five and have no equivalents in Zope 3.
18 $Id: fiveconfigure.py 19219 2005-10-31 00:17:29Z yuppie $
19 """
20 import os
21 import sys
22 import glob
23 import warnings
25 import App.config
26 import Products
27 from zLOG import LOG, ERROR
29 from zope.interface import classImplements, classImplementsOnly, implementedBy
30 from zope.interface.interface import InterfaceClass
31 from zope.configuration import xmlconfig
32 from zope.configuration.exceptions import ConfigurationError
33 from zope.app import zapi
34 from zope.app.component.interface import provideInterface
35 from zope.app.component.metaconfigure import adapter
36 from zope.app.security.interfaces import IPermission
38 from viewable import Viewable
39 from traversable import Traversable
40 from bridge import fromZ2Interface
41 from browser.metaconfigure import page
43 debug_mode = App.config.getConfiguration().debug_mode
45 def findProducts():
46 import Products
47 from types import ModuleType
48 products = []
49 for name in dir(Products):
50 product = getattr(Products, name)
51 if isinstance(product, ModuleType) and hasattr(product, '__file__'):
52 products.append(product)
53 return products
55 def handleBrokenProduct(product):
56 if debug_mode:
57 # Just reraise the error and let Zope handle it.
58 raise
59 # Not debug mode. Zope should continue to load. Print a log message:
60 # XXX It would be really cool if we could make this product appear broken
61 # in the control panel. However, all attempts to do so has failed from my
62 # side. //regebro
63 exc = sys.exc_info()
64 LOG('Five', ERROR, 'Could not import Product %s' % product.__name__, error=exc)
66 def loadProducts(_context):
67 products = findProducts()
69 # first load meta.zcml files
70 for product in products:
71 zcml = os.path.join(os.path.dirname(product.__file__), 'meta.zcml')
72 if os.path.isfile(zcml):
73 try:
74 xmlconfig.include(_context, zcml, package=product)
75 except: # Yes, really, *any* kind of error.
76 handleBrokenProduct(product)
78 # now load their configure.zcml
79 for product in products:
80 zcml = os.path.join(os.path.dirname(product.__file__),
81 'configure.zcml')
82 if os.path.isfile(zcml):
83 try:
84 xmlconfig.include(_context, zcml, package=product)
85 except: # Yes, really, *any* kind of error.
86 handleBrokenProduct(product)
88 def loadProductsOverrides(_context):
89 for product in findProducts():
90 zcml = os.path.join(os.path.dirname(product.__file__),
91 'overrides.zcml')
92 if os.path.isfile(zcml):
93 try:
94 xmlconfig.includeOverrides(_context, zcml, package=product)
95 except: # Yes, really, *any* kind of error.
96 handleBrokenProduct(product)
98 def implements(_context, class_, interface):
99 for interface in interface:
100 _context.action(
101 discriminator = None,
102 callable = classImplements,
103 args = (class_, interface)
104 )
105 _context.action(
106 discriminator = None,
107 callable = provideInterface,
108 args = (interface.__module__ + '.' + interface.getName(),
109 interface)
110 )
112 def isFiveMethod(m):
113 return hasattr(m, '__five_method__')
115 _traversable_monkies = []
116 def classTraversable(class_):
117 # If a class already has this attribute, it means it is either a
118 # subclass of Traversable or was already processed with this
119 # directive; in either case, do nothing... except in the case were
120 # the class overrides __bobo_traverse__ instead of getting it from
121 # a base class. In this case, we suppose that the class probably
122 # didn't bother with the base classes __bobo_traverse__ anyway and
123 # we step __fallback_traverse__.
124 if hasattr(class_, '__five_traversable__'):
125 if (hasattr(class_, '__bobo_traverse__') and
126 isFiveMethod(class_.__bobo_traverse__)):
127 return
129 if hasattr(class_, '__bobo_traverse__'):
130 if not isFiveMethod(class_.__bobo_traverse__):
131 # if there's an existing bobo_traverse hook already, use that
132 # as the traversal fallback method
133 setattr(class_, '__fallback_traverse__', class_.__bobo_traverse__)
134 if not hasattr(class_, '__fallback_traverse__'):
135 setattr(class_, '__fallback_traverse__',
136 Traversable.__fallback_traverse__.im_func)
138 setattr(class_, '__bobo_traverse__',
139 Traversable.__bobo_traverse__.im_func)
140 setattr(class_, '__five_traversable__', True)
141 # remember class for clean up
142 _traversable_monkies.append(class_)
144 def traversable(_context, class_):
145 _context.action(
146 discriminator = None,
147 callable = classTraversable,
148 args = (class_,)
149 )
151 _defaultviewable_monkies = []
152 def classDefaultViewable(class_):
153 # If a class already has this attribute, it means it is either a
154 # subclass of DefaultViewable or was already processed with this
155 # directive; in either case, do nothing... except in the case were
156 # the class overrides the attribute instead of getting it from
157 # a base class. In this case, we suppose that the class probably
158 # didn't bother with the base classes attribute anyway.
159 if hasattr(class_, '__five_viewable__'):
160 if (hasattr(class_, '__browser_default__') and
161 isFiveMethod(class_.__browser_default__)):
162 return
164 if hasattr(class_, '__browser_default__'):
165 # if there's an existing __browser_default__ hook already, use that
166 # as the fallback
167 if not isFiveMethod(class_.__browser_default__):
168 setattr(class_, '__fallback_default__', class_.__browser_default__)
169 if not hasattr(class_, '__fallback_default__'):
170 setattr(class_, '__fallback_default__',
171 Viewable.__fallback_default__.im_func)
173 setattr(class_, '__browser_default__',
174 Viewable.__browser_default__.im_func)
175 setattr(class_, '__five_viewable__', True)
176 # remember class for clean up
177 _defaultviewable_monkies.append(class_)
179 def defaultViewable(_context, class_):
180 _context.action(
181 discriminator = None,
182 callable = classDefaultViewable,
183 args = (class_,)
184 )
186 def createZope2Bridge(zope2, package, name):
187 # Map a Zope 2 interface into a Zope3 interface, seated within 'package'
188 # as 'name'.
189 z3i = fromZ2Interface(zope2)
191 if name is not None:
192 z3i.__dict__['__name__'] = name
194 z3i.__dict__['__module__'] = package.__name__
195 setattr(package, z3i.getName(), z3i)
197 def bridge(_context, zope2, package, name=None):
198 # Directive handler for <five:bridge> directive.
200 # N.B.: We have to do the work early, or else we won't be able
201 # to use the synthesized interface in other ZCML directives.
202 createZope2Bridge(zope2, package, name)
204 # Faux action, only for conflict resolution.
205 _context.action(
206 discriminator = (zope2,),
207 )
209 def pagesFromDirectory(_context, directory, module, for_=None,
210 layer='default', permission='zope.Public'):
212 if isinstance(module, basestring):
213 module = _context.resolve(module)
215 _prefix = os.path.dirname(module.__file__)
216 directory = os.path.join(_prefix, directory)
218 if not os.path.isdir(directory):
219 raise ConfigurationError(
220 "Directory %s does not exist" % directory
221 )
223 for fname in glob.glob(os.path.join(directory, '*.pt')):
224 name = os.path.splitext(os.path.basename(fname))[0]
225 page(_context, name=name, permission=permission,
226 layer=layer, for_=for_, template=fname)
229 _register_monkies = []
230 _meta_type_regs = []
231 def _registerClass(class_, meta_type, permission, addview, icon, global_):
232 setattr(class_, 'meta_type', meta_type)
234 permission_obj = zapi.getUtility(IPermission, permission)
236 if icon:
237 setattr(class_, 'icon', '++resource++%s' % icon)
239 interfaces = tuple(implementedBy(class_))
241 info = {'name': meta_type,
242 'action': addview and ('+/%s' % addview) or '',
243 'product': 'Five',
244 'permission': str(permission_obj.title),
245 'visibility': global_ and 'Global' or None,
246 'interfaces': interfaces,
247 'instance': class_,
248 'container_filter': None}
250 Products.meta_types += (info,)
252 _register_monkies.append(class_)
253 _meta_type_regs.append(meta_type)
255 def registerClass(_context, class_, meta_type, permission, addview=None,
256 icon=None, global_=True):
257 _context.action(
258 discriminator = ('registerClass', meta_type),
259 callable = _registerClass,
260 args = (class_, meta_type, permission, addview, icon, global_)
261 )
263 # clean up code
265 def killMonkey(class_, name, fallback, attr=None):
266 """Die monkey, die!"""
267 method = getattr(class_, name, None)
268 if isFiveMethod(method):
269 original = getattr(class_, fallback, None)
270 if original is None:
271 try:
272 delattr(class_, name)
273 except AttributeError:
274 pass
275 else:
276 setattr(class_, name, original)
278 if attr is not None:
279 try:
280 delattr(class_, attr)
281 except (AttributeError, KeyError):
282 pass
284 def untraversable(class_):
285 """Restore class's initial state with respect to traversability"""
286 killMonkey(class_, '__bobo_traverse__', '__fallback_traverse__',
287 '__five_traversable__')
289 def undefaultViewable(class_):
290 """Restore class's initial state with respect to being default
291 viewable."""
292 killMonkey(class_, '__browser_default__', '__fallback_default__',
293 '__five_viewable__')
295 def unregisterClass(class_):
296 delattr(class_, 'meta_type')
297 try:
298 delattr(class_, 'icon')
299 except AttributeError:
300 pass
302 def cleanUp():
303 global _traversable_monkies
304 for class_ in _traversable_monkies:
305 untraversable(class_)
306 _traversable_monkies = []
308 global _defaultviewable_monkies
309 for class_ in _defaultviewable_monkies:
310 undefaultViewable(class_)
311 _defaultviewable_monkies = []
313 global _register_monkies
314 for class_ in _register_monkies:
315 unregisterClass(class_)
316 _register_monkies = []
318 global _meta_type_regs
319 Products.meta_types = tuple([ info for info in Products.meta_types
320 if info['name'] not in _meta_type_regs ])
321 _meta_type_regs = []
323 from zope.testing.cleanup import addCleanUp
324 addCleanUp(cleanUp)
325 del addCleanUp