--- a/src/pyams_template/__init__.py Mon Nov 25 15:46:23 2019 +0100
+++ b/src/pyams_template/__init__.py Tue Nov 26 10:01:36 2019 +0100
@@ -10,6 +10,14 @@
# FOR A PARTICULAR PURPOSE.
#
+"""PyAMS_template package
+
+This template is used to assign Chamelon templates to views or layouts. It's essentially an
+adaptation of "z3c.template" package for use with Pyramid.
+
+Templates are registered as adapters for a context and a request, and so can easily be overriden.
+You can also define view templates and layout templates, or use named adapters if needed.
+"""
from pyramid.i18n import TranslationStringFactory
_ = TranslationStringFactory('pyams_template')
@@ -19,8 +27,8 @@
"""Pyramid include"""
# define configuration settings
- from pyams_template import template
- template.configuration_settings = config.registry.settings
+ from pyams_template import template # pylint: disable=import-outside-toplevel
+ template.CONFIGURATION_SETTINGS = config.registry.settings
# load registry components
config.scan()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_template/interfaces.py Tue Nov 26 10:01:36 2019 +0100
@@ -0,0 +1,32 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+"""PyAMS_template.interfaces module
+
+Templates marker interfaces definitions
+"""
+
+from zope.interface import Interface
+
+__docformat__ = 'restructuredtext'
+
+
+class IPageTemplate(Interface):
+ """Base page template interface"""
+
+
+class ILayoutTemplate(IPageTemplate):
+ """A template used for render the layout."""
+
+
+class IContentTemplate(IPageTemplate):
+ """A template used for render the content."""
--- a/src/pyams_template/interfaces/__init__.py Mon Nov 25 15:46:23 2019 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-#
-# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-
-__docformat__ = 'restructuredtext'
-
-
-# import standard packages
-
-# import interfaces
-from zope.interface import Interface
-
-# import packages
-
-
-class IPageTemplate(Interface):
- """Base page template interface"""
-
-
-class ILayoutTemplate(IPageTemplate):
- """A template used for render the layout."""
-
-
-class IContentTemplate(IPageTemplate):
- """A template used for render the content."""
--- a/src/pyams_template/metaconfigure.py Mon Nov 25 15:46:23 2019 +0100
+++ b/src/pyams_template/metaconfigure.py Tue Nov 26 10:01:36 2019 +0100
@@ -10,36 +10,41 @@
# FOR A PARTICULAR PURPOSE.
#
-__docformat__ = 'restructuredtext'
+"""PyAMS_template.metadirectives module
+Is module allows to handle <template /> and <layout > directives in ZCML files.
-# import standard library
+"""
+
import os
-# import interfaces
-from pyams_template.interfaces import ILayoutTemplate, IContentTemplate
+from pyramid.exceptions import ConfigurationError
from pyramid.interfaces import IRequest
+from zope.component import zcml
+from zope.interface import Interface, directlyProvides
-# import packages
+from pyams_template.interfaces import IContentTemplate, ILayoutTemplate
from pyams_template.template import TemplateFactory
-from pyramid.exceptions import ConfigurationError
-from zope.component import zcml
-from zope.interface import directlyProvides, Interface
+
+
+__docformat__ = 'restructuredtext'
def template_directive(_context, template, name=u'',
for_=Interface,
layer=IRequest,
provides=IContentTemplate,
- contentType='text/html',
+ content_type='text/html',
macro=None,
context=None):
+ # pylint: disable=too-many-arguments
+ """ZCML <template /> directive handler"""
# Make sure that the template exists
template = os.path.abspath(str(_context.path(template)))
if not os.path.isfile(template):
raise ConfigurationError("No such file", template)
- factory = TemplateFactory(template, contentType, macro)
+ factory = TemplateFactory(template, content_type, macro)
directlyProvides(factory, provides)
if context is not None:
@@ -58,8 +63,10 @@
for_=Interface,
layer=IRequest,
provides=ILayoutTemplate,
- contentType='text/html',
+ content_type='text/html',
macro=None,
context=None):
+ # pylint: disable=too-many-arguments
+ """ZCML <layout /> directive handler"""
template_directive(_context, template, name, for_, layer, provides,
- contentType, macro, context)
+ content_type, macro, context)
--- a/src/pyams_template/metadirectives.py Mon Nov 25 15:46:23 2019 +0100
+++ b/src/pyams_template/metadirectives.py Tue Nov 26 10:01:36 2019 +0100
@@ -10,19 +10,20 @@
# FOR A PARTICULAR PURPOSE.
#
-__docformat__ = 'restructuredtext'
+"""PyAMS_template.metadirectives module
+
+This module provides ZCML directives interfaces
+"""
+
+from pyramid.interfaces import IRequest
+from zope.configuration.fields import GlobalInterface, GlobalObject, Path
+from zope.interface import Interface
+from zope.schema import ASCIILine, TextLine
+
+from pyams_template.interfaces import IContentTemplate, ILayoutTemplate
-# import standard library
-
-# import interfaces
-from pyramid.interfaces import IRequest
-
-# import packages
-from zope.configuration.fields import Path, GlobalObject, GlobalInterface
-from zope.interface import Interface
-from zope.schema import TextLine, ASCIILine
-from pyams_template.interfaces import IContentTemplate, ILayoutTemplate
+__docformat__ = 'restructuredtext'
class ITemplateDirective(Interface):
@@ -39,14 +40,11 @@
required=False)
macro = TextLine(title='Macro',
- description="""
- The macro to be used.
- This allows us to define different macros in one template.
- The template designer can now create a whole site, the
- ViewTemplate can then extract the macros for single viewlets
- or views.
- If no macro is given the whole template is used for rendering.
- """,
+ description="The macro to be used. This allows us to define different macros "
+ "in one template. The template designer can now create a whole "
+ "site, the ViewTemplate can then extract the macros for single "
+ "viewlets or views. If no macro is given the whole template is "
+ "used for rendering.",
default='',
required=False)
@@ -70,10 +68,10 @@
default=IContentTemplate,
required=False)
- contentType = ASCIILine(title='Content Type',
- description='The content type identifies the type of data.',
- default='text/html',
- required=False)
+ content_type = ASCIILine(title='Content Type',
+ description='The content type identifies the type of data.',
+ default='text/html',
+ required=False)
class ILayoutTemplateDirective(ITemplateDirective):
--- a/src/pyams_template/template.py Mon Nov 25 15:46:23 2019 +0100
+++ b/src/pyams_template/template.py Tue Nov 26 10:01:36 2019 +0100
@@ -10,42 +10,47 @@
# FOR A PARTICULAR PURPOSE.
#
-__docformat__ = 'restructuredtext'
+"""PyAMS_template.template module
+This module provides Pyramid decorators which can be used to register a Chameleon template for
+a given view
+"""
-# import standard library
import inspect
import os
+
import venusian
-
-# import interfaces
-from pyams_template.interfaces import IPageTemplate, IContentTemplate, ILayoutTemplate
+from pyramid.exceptions import ConfigurationError
from pyramid.interfaces import IRequest
from pyramid_chameleon.interfaces import IChameleonTranslate
-
-# import packages
-from pyramid.exceptions import ConfigurationError
from pyramid_chameleon.zpt import PyramidPageTemplateFile
from zope.component import queryUtility
from zope.component.globalregistry import getGlobalSiteManager
from zope.interface import directlyProvides
+from pyams_template.interfaces import IContentTemplate, ILayoutTemplate, IPageTemplate
-configuration_settings = {}
+
+__docformat__ = 'restructuredtext'
-class TemplateFactory(object):
- """Template factory."""
+CONFIGURATION_SETTINGS = {}
+
+
+class TemplateFactory:
+ """Base template factory"""
template = None
- def __init__(self, filename, contentType, macro=None):
- self.contentType = contentType
+ def __init__(self, filename, content_type, macro=None):
+ self.content_type = content_type
self.template = PyramidPageTemplateFile(filename,
- content_type=contentType,
+ content_type=content_type,
macro=macro,
- auto_reload=configuration_settings.get('reload_templates', False),
- debug=configuration_settings.get('debug_templates', False),
+ auto_reload=CONFIGURATION_SETTINGS.get(
+ 'reload_templates', False),
+ debug=CONFIGURATION_SETTINGS.get(
+ 'debug_templates', False),
translate=queryUtility(IChameleonTranslate))
self.macro = self.template.macro = macro
@@ -53,27 +58,44 @@
return self.template
-class BoundViewTemplate(object):
- def __init__(self, pt, ob):
- object.__setattr__(self, 'im_func', pt)
- object.__setattr__(self, 'im_self', ob)
+class BoundViewTemplate:
+ """Bound view template"""
+
+ __self__ = None
+ __func__ = None
+
+ def __init__(self, tmpl, obj):
+ object.__setattr__(self, '__func__', tmpl)
+ object.__setattr__(self, '__self__', obj)
- def __call__(self, *args, **kw):
- if self.im_self is None:
+ @property
+ def im_self(self):
+ """im_self property"""
+ return self.__self__
+
+ @property
+ def im_func(self):
+ """im_func property"""
+ return self.__func__
+
+ def __call__(self, *args, **kwargs):
+ if self.__self__ is None:
im_self, args = args[0], args[1:]
else:
- im_self = self.im_self
- return self.im_func(im_self, *args, **kw)
+ im_self = self.__self__
+ return self.__func__(im_self, *args, **kwargs) # pylint: disable=not-callable
def __setattr__(self, name, v):
raise AttributeError("Can't set attribute", name)
def __repr__(self):
- return "<BoundViewTemplate of %r>" % self.im_self
+ return "<BoundViewTemplate of %r>" % self.__self__
-class ViewTemplate(object):
- def __init__(self, provides=IPageTemplate, name=u''):
+class ViewTemplate:
+ """View template class"""
+
+ def __init__(self, provides=IPageTemplate, name=''):
self.provides = provides
self.name = name
@@ -85,37 +107,46 @@
template = registry.getMultiAdapter((instance, instance.request),
self.provides, name=self.name)
- keywords.update({'context': instance.context,
- 'request': instance.request,
- 'view': instance,
- 'translate': queryUtility(IChameleonTranslate)})
+ keywords.update({
+ 'context': instance.context,
+ 'request': instance.request,
+ 'view': instance,
+ 'translate': queryUtility(IChameleonTranslate)
+ })
return template(*args, **keywords)
- def __get__(self, instance, type):
+ def __get__(self, instance, type): # pylint: disable=redefined-builtin
return BoundViewTemplate(self, instance)
-get_view_template = ViewTemplate
+
+get_view_template = ViewTemplate # pylint: disable=invalid-name
class GetPageTemplate(ViewTemplate):
+ """Page template getter class"""
def __init__(self, name=u''):
+ # pylint: disable=super-init-not-called
self.provides = IContentTemplate
self.name = name
-get_page_template = GetPageTemplate
+
+get_page_template = GetPageTemplate # pylint: disable=invalid-name
class GetLayoutTemplate(ViewTemplate):
+ """Layout template getter class"""
def __init__(self, name=u''):
+ # pylint: disable=super-init-not-called
self.provides = ILayoutTemplate
self.name = name
-get_layout_template = GetLayoutTemplate
+
+get_layout_template = GetLayoutTemplate # pylint: disable=invalid-name
-class template_config(object):
+class template_config: # pylint: disable=invalid-name
"""Class decorator used to declare a view template"""
venusian = venusian # for testing injection
@@ -129,33 +160,34 @@
def __call__(self, wrapped):
settings = self.__dict__.copy()
- def callback(context, name, ob):
- template = os.path.join(os.path.dirname(inspect.getfile(inspect.getmodule(ob))),
+ def callback(context, name, obj):
+ template = os.path.join(os.path.dirname(inspect.getfile(inspect.getmodule(obj))),
settings.get('template'))
if not os.path.isfile(template):
raise ConfigurationError("No such file", template)
- contentType = settings.get('contentType', 'text/html')
+ content_type = settings.get('content_type', 'text/html')
macro = settings.get('macro')
- factory = TemplateFactory(template, contentType, macro)
+ factory = TemplateFactory(template, content_type, macro)
provides = settings.get('provides', IContentTemplate)
directlyProvides(factory, provides)
- config = context.config.with_package(info.module)
- config.registry.registerAdapter(factory,
- (ob, settings.get('layer', IRequest)),
- provides, settings.get('name', ''))
+ config = context.config.with_package(info.module) # pylint: disable=no-member
+ registry = settings.get('registry', config.registry)
+ registry.registerAdapter(factory,
+ (obj, settings.get('layer', IRequest)),
+ provides, settings.get('name', ''))
info = self.venusian.attach(wrapped, callback, category='pyams_template')
- if info.scope == 'class':
+ if info.scope == 'class': # pylint: disable=no-member
# if the decorator was attached to a method in a class, or
# otherwise executed at class scope, we need to set an
# 'attr' into the settings if one isn't already in there
if settings.get('attr') is None:
settings['attr'] = wrapped.__name__
- settings['_info'] = info.codeinfo # fbo "action_method"
+ settings['_info'] = info.codeinfo # pylint: disable=no-member
return wrapped
@@ -170,9 +202,9 @@
settings.get('template'))
if not os.path.isfile(template):
raise ConfigurationError("No such file", template)
- contentType = settings.get('contentType', 'text/html')
+ content_type = settings.get('content_type', 'text/html')
macro = settings.get('macro')
- factory = TemplateFactory(template, contentType, macro)
+ factory = TemplateFactory(template, content_type, macro)
provides = settings.get('provides', IContentTemplate)
directlyProvides(factory, provides)
registry = getGlobalSiteManager()
@@ -181,7 +213,7 @@
provides, settings.get('name', ''))
-class layout_config(object):
+class layout_config: # pylint: disable=invalid-name
"""Class decorator used to declare a layout template"""
venusian = venusian # for testing injection
@@ -201,27 +233,27 @@
if not os.path.isfile(template):
raise ConfigurationError("No such file", template)
- contentType = settings.get('contentType', 'text/html')
+ content_type = settings.get('content_type', 'text/html')
macro = settings.get('macro')
- factory = TemplateFactory(template, contentType, macro)
+ factory = TemplateFactory(template, content_type, macro)
provides = settings.get('provides', ILayoutTemplate)
directlyProvides(factory, provides)
- config = context.config.with_package(info.module)
+ config = context.config.with_package(info.module) # pylint: disable=no-member
config.registry.registerAdapter(factory,
(ob, settings.get('layer', IRequest)),
provides, settings.get('name', ''))
info = self.venusian.attach(wrapped, callback, category='pyams_template')
- if info.scope == 'class':
+ if info.scope == 'class': # pylint: disable=no-member
# if the decorator was attached to a method in a class, or
# otherwise executed at class scope, we need to set an
# 'attr' into the settings if one isn't already in there
if settings.get('attr') is None:
settings['attr'] = wrapped.__name__
- settings['_info'] = info.codeinfo # fbo "action_method"
+ settings['_info'] = info.codeinfo # pylint: disable=no-member
return wrapped
@@ -236,9 +268,9 @@
settings.get('template'))
if not os.path.isfile(template):
raise ConfigurationError("No such file", template)
- contentType = settings.get('contentType', 'text/html')
+ content_type = settings.get('content_type', 'text/html')
macro = settings.get('macro')
- factory = TemplateFactory(template, contentType, macro)
+ factory = TemplateFactory(template, content_type, macro)
provides = settings.get('provides', ILayoutTemplate)
directlyProvides(factory, provides)
registry = getGlobalSiteManager()