import os, sys from zope.interface import implements, classImplements, Interface from zope.configuration.exceptions import ConfigurationError from zope.publisher.interfaces.browser import IDefaultBrowserLayer from zope.publisher.interfaces.browser import IBrowserPublisher from zope.publisher.interfaces.browser import IBrowserRequest from zope.security.checker import defineChecker from zope.app.publisher.browser.viewmeta import \ _handle_menu, _handle_permission, _handle_allowed_interface, \ _handle_allowed_attributes, _handle_for from zope.app.publisher.browser import BrowserView from zope.security.checker import CheckerPublic, Checker from zope.app.component.metaconfigure import handler import neo_cgi # must be loaded before loading neo_util or neo_cs.. import neo_util import neo_cs def cspage(_context, name, permission, for_, layer=IDefaultBrowserLayer, template=None, class_=None, allowed_interface=None, allowed_attributes=None, attribute='__call__', menu=None, title=None, ): _handle_menu(_context, menu, title, [for_], name, permission, layer) required = {} permission = _handle_permission(_context, permission) if not (class_ or template): raise ConfigurationError("Must specify a class or template") if attribute != '__call__': if template: raise ConfigurationError( "Attribute and template cannot be used together.") if not class_: raise ConfigurationError( "A class must be provided if attribute is used") if template: template = os.path.abspath(str(_context.path(template))) if not os.path.isfile(template): raise ConfigurationError("No such file", template) required['__getitem__'] = permission # XXX: new __name__ attribute must be tested if class_: if attribute != '__call__': if not hasattr(class_, attribute): raise ConfigurationError( "The provided class doesn't have the specified attribute " ) if template: # class and template new_class = SimpleViewClass(template, bases=(class_, ), name=name) else: if not hasattr(class_, 'browserDefault'): cdict = { 'browserDefault': lambda self, request: (getattr(self, attribute), ()) } else: cdict = {} cdict['__name__'] = name cdict['__page_attribute__'] = attribute new_class = type(class_.__name__, (class_, simple,), cdict) if hasattr(class_, '__implements__'): classImplements(new_class, IBrowserPublisher) else: # template new_class = SimpleViewClass(template, name=name) for n in (attribute, 'browserDefault', '__call__', 'publishTraverse'): required[n] = permission _handle_allowed_interface(_context, allowed_interface, permission, required) _handle_allowed_attributes(_context, allowed_interface, permission, required) _handle_for(_context, for_) defineChecker(new_class, Checker(required)) _context.action( discriminator = ('view', for_, name, IBrowserRequest, layer), callable = handler, args = ('provideAdapter', (for_, layer), Interface, name, new_class, _context.info), ) class simple(BrowserView): implements(IBrowserPublisher) def browserDefault(self, request): return self, () def publishTraverse(self, request, name): if name == 'index.html': return self.index raise NotFound(self, name, request) def createHDF(self): return neo_util.HDF() def hdf(self): return self.createHDF() def __call__(self, *args, **kw): return self.index(*args, **kw) def SimpleViewClass(src, offering=None, bases=(), name=u''): if offering is None: offering = sys._getframe(1).f_globals bases += (simple,) class_ = type("SimpleViewClass from %s" % src, bases, {'index': ClearSilverFile(src, offering), '__name__': name}) return class_ class ClearSilverFile(object): content_type = 'text/html' def __init__(self, filename, _prefix=None, content_type=None): path = self.get_path_from_prefix(_prefix) self.filename = os.path.join(path, filename) if not os.path.isfile(self.filename): raise ValueError("No such file", self.filename) if content_type is not None: self.content_type = content_type def get_path_from_prefix(self, _prefix): if isinstance(_prefix, str): path = _prefix else: if _prefix is None: _prefix = sys._getframe(2).f_globals path = package_home(_prefix) return path def __call__(self, instance, *args, **keywords): # for some reason it is not that easy to actually cache # parsed clearsilver templates -- the HDF structure needs # to be known during creation. Some testing showed that # ClearSilver with parsing is still blazingly fast, however, # so we won't worry about this for now. hdf = instance.hdf() cs = neo_cs.CS(hdf) cs.parseFile(self.filename) s = cs.render() response = instance.request.response if not response.getHeader("Content-Type"): response.setHeader("Content-Type", self.content_type) return s def __get__(self, instance, type): return BoundClearSilver(self, instance) class BoundClearSilver(object): def __init__(self, cs, ob): object.__setattr__(self, 'im_func', cs) object.__setattr__(self, 'im_self', ob) filename = property(lambda self: self.im_func.filename) def __call__(self, *args, **kw): if self.im_self is None: im_self, args = args[0], args[1:] else: im_self = self.im_self return self.im_func(im_self, *args, **kw) def __setattr__(self, name, v): raise AttributeError("Can't set attribute", name) def __repr__(self): return "" % self.im_self def package_home(gdict): filename = gdict["__file__"] return os.path.dirname(filename)