--- a/.installed.cfg Fri Jan 18 15:32:56 2019 +0100
+++ b/.installed.cfg Wed Nov 27 15:57:21 2019 +0100
@@ -1,91 +1,88 @@
[buildout]
installed_develop_eggs = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs/pyams-template.egg-link
- /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs/pyams-form.egg-link
/home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs/lingua.egg-link
- /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs/pyams-pagelet.egg-link
- /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs/pyams-catalog.egg-link
/home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs/pyams-viewlet.egg-link
/home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs/pyams-utils.egg-link
- /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs/pyams-file.egg-link
- /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs/pyams-zmi.egg-link
- /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs/pyams-skin.egg-link
- /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs/pyams-i18n.egg-link
-parts = package i18n pyflakes test
+parts = package i18n pyflakes pylint test
[package]
-__buildout_installed__ = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/pyams_upgrade
- /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/pcreate
- /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/pserve
- /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/pdistreport
- /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/pviews
- /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/ptweens
- /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/pshell
- /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/proutes
- /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/prequest
-__buildout_signature__ = zc.recipe.egg-25289128786a29bd5395ec7b9e3ceb3a zc.buildout-25289128786a29bd5395ec7b9e3ceb3a setuptools-25289128786a29bd5395ec7b9e3ceb3a
+__buildout_installed__ = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/python
+__buildout_signature__ = zc.recipe.egg-fc68d03e7c9074dcb88f8edb384c0f13 zc.buildout-fc68d03e7c9074dcb88f8edb384c0f13 setuptools-fc68d03e7c9074dcb88f8edb384c0f13
_b = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin
_d = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs
-_e = /var/local/env/pyams/eggs
+_e = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/eggs
bin-directory = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin
develop-eggs-directory = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs
-eggs = chameleon
- pyams_utils
- pyams_viewlet
- pyramid
- zope.component
- zope.configuration
- zope.contentprovider
- zope.interface
- zope.location
- zope.schema
-eggs-directory = /var/local/env/pyams/eggs
+eggs = pyams_viewlet
+eggs-directory = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/eggs
find-links = http://download.ztfy.org/eggs
+interpreter = python
recipe = zc.recipe.egg
[i18n]
__buildout_installed__ = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/pybabel
+ /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/pot-create
/home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/polint
- /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/pot-create
-__buildout_signature__ = zc.recipe.egg-25289128786a29bd5395ec7b9e3ceb3a zc.buildout-25289128786a29bd5395ec7b9e3ceb3a setuptools-25289128786a29bd5395ec7b9e3ceb3a
+__buildout_signature__ = zc.recipe.egg-fc68d03e7c9074dcb88f8edb384c0f13 zc.buildout-fc68d03e7c9074dcb88f8edb384c0f13 setuptools-fc68d03e7c9074dcb88f8edb384c0f13
_b = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin
_d = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs
-_e = /var/local/env/pyams/eggs
+_e = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/eggs
bin-directory = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin
develop-eggs-directory = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs
eggs = babel
lingua
-eggs-directory = /var/local/env/pyams/eggs
+eggs-directory = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/eggs
find-links = http://download.ztfy.org/eggs
recipe = zc.recipe.egg
[pyflakes]
__buildout_installed__ = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/pyflakes
/home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/pyflakes
-__buildout_signature__ = zc.recipe.egg-25289128786a29bd5395ec7b9e3ceb3a zc.buildout-25289128786a29bd5395ec7b9e3ceb3a setuptools-25289128786a29bd5395ec7b9e3ceb3a
+__buildout_signature__ = zc.recipe.egg-fc68d03e7c9074dcb88f8edb384c0f13 zc.buildout-fc68d03e7c9074dcb88f8edb384c0f13 setuptools-fc68d03e7c9074dcb88f8edb384c0f13
_b = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin
_d = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs
-_e = /var/local/env/pyams/eggs
+_e = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/eggs
bin-directory = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin
develop-eggs-directory = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs
eggs = pyflakes
-eggs-directory = /var/local/env/pyams/eggs
+eggs-directory = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/eggs
entry-points = pyflakes=pyflakes.scripts.pyflakes:main
find-links = http://download.ztfy.org/eggs
initialization = if not sys.argv[1:]: sys.argv[1:] = ["src"]
recipe = zc.recipe.egg
scripts = pyflakes
+[pylint]
+__buildout_installed__ = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/epylint
+ /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/pylint
+ /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/symilar
+ /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/pyreverse
+ /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/pylint
+__buildout_signature__ = zc.recipe.egg-fc68d03e7c9074dcb88f8edb384c0f13 zc.buildout-fc68d03e7c9074dcb88f8edb384c0f13 setuptools-fc68d03e7c9074dcb88f8edb384c0f13
+_b = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin
+_d = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs
+_e = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/eggs
+arguments = sys.argv[1:]
+bin-directory = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin
+develop-eggs-directory = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs
+eggs = pyams_viewlet
+ pylint
+eggs-directory = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/eggs
+entry-points = pylint=pylint.lint:Run
+find-links = http://download.ztfy.org/eggs
+recipe = zc.recipe.egg
+
[test]
__buildout_installed__ = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/parts/test
/home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin/test
-__buildout_signature__ = six-25289128786a29bd5395ec7b9e3ceb3a zc.recipe.testrunner-25289128786a29bd5395ec7b9e3ceb3a zc.recipe.egg-25289128786a29bd5395ec7b9e3ceb3a zc.buildout-25289128786a29bd5395ec7b9e3ceb3a zope.exceptions-25289128786a29bd5395ec7b9e3ceb3a zope.interface-25289128786a29bd5395ec7b9e3ceb3a zope.testrunner-25289128786a29bd5395ec7b9e3ceb3a setuptools-25289128786a29bd5395ec7b9e3ceb3a
+__buildout_signature__ = six-fc68d03e7c9074dcb88f8edb384c0f13 zc.recipe.egg-fc68d03e7c9074dcb88f8edb384c0f13 zc.recipe.testrunner-fc68d03e7c9074dcb88f8edb384c0f13 zc.buildout-fc68d03e7c9074dcb88f8edb384c0f13 zope.exceptions-fc68d03e7c9074dcb88f8edb384c0f13 zope.interface-fc68d03e7c9074dcb88f8edb384c0f13 zope.testrunner-fc68d03e7c9074dcb88f8edb384c0f13 setuptools-fc68d03e7c9074dcb88f8edb384c0f13
_b = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin
_d = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs
-_e = /var/local/env/pyams/eggs
+_e = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/eggs
bin-directory = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/bin
develop-eggs-directory = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/develop-eggs
eggs = pyams_viewlet [test]
-eggs-directory = /var/local/env/pyams/eggs
+eggs-directory = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/eggs
find-links = http://download.ztfy.org/eggs
location = /home/tflorac/Dropbox/src/PyAMS/pyams_viewlet/parts/test
recipe = zc.recipe.testrunner
--- a/buildout.cfg Fri Jan 18 15:32:56 2019 +0100
+++ b/buildout.cfg Wed Nov 27 15:57:21 2019 +0100
@@ -1,56 +1,32 @@
[buildout]
-eggs-directory = /var/local/env/pyams/eggs
+eggs-directory = eggs
extends = http://download.ztfy.org/pyams/pyams-dev.cfg
find-links = http://download.ztfy.org/eggs
-
socket-timeout = 3
-#allow-picked-versions = false
+versions = versions
+allow-picked-versions = false
show-picked-versions = true
newest = false
-allow-hosts =
- bitbucket.org
- *.python.org
- *.sourceforge.net
- github.com
-
-versions = versions
-
src = src
develop =
.
../ext/lingua
- ../pyams_catalog
- ../pyams_file
- ../pyams_form
- ../pyams_i18n
- ../pyams_pagelet
- ../pyams_skin
../pyams_template
../pyams_utils
- ../pyams_viewlet
- ../pyams_zmi
parts =
package
i18n
pyflakes
+ pylint
test
[package]
recipe = zc.recipe.egg
-eggs =
- chameleon
- pyams_utils
- pyams_viewlet
- pyramid
- zope.component
- zope.configuration
- zope.contentprovider
- zope.interface
- zope.location
- zope.schema
+eggs = pyams_viewlet
+interpreter = python
[i18n]
recipe = zc.recipe.egg
@@ -70,9 +46,17 @@
on_install = true
cmds = ${buildout:develop}/bin/${pyflakes:scripts}
+[pylint]
+recipe = zc.recipe.egg
+eggs =
+ ${package:eggs}
+ pylint
+entry-points = pylint=pylint.lint:Run
+arguments = sys.argv[1:]
+
[test]
recipe = zc.recipe.testrunner
eggs = pyams_viewlet [test]
[versions]
-pyams_viewlet = 0.1.7
+pyams_viewlet = 0.1.8
--- a/docs/HISTORY.txt Fri Jan 18 15:32:56 2019 +0100
+++ b/docs/HISTORY.txt Wed Nov 27 15:57:21 2019 +0100
@@ -1,6 +1,11 @@
Changelog
=========
+0.1.8
+-----
+ - code cleanup
+ - Gitlab-CI integration
+
0.1.7
-----
- updated "provider" TALES expression to be able to provide arguments
--- a/docs/README.txt Fri Jan 18 15:32:56 2019 +0100
+++ b/docs/README.txt Wed Nov 27 15:57:21 2019 +0100
@@ -0,0 +1,31 @@
+=====================
+PyAMS_viewlet package
+=====================
+
+.. contents::
+
+
+What is PyAMS
+=============
+
+PyAMS (Pyramid Application Management Suite) is a small suite of packages written for applications
+and content management with the Pyramid framework.
+
+**PyAMS** is actually mainly used to manage web sites through content management applications (CMS,
+see PyAMS_content package), but many features are generic and can be used inside any kind of web
+application.
+
+
+What is PyAMS_viewlet?
+======================
+
+PyAMS_viewlet is a package which defines components called "content providers"; these content
+providers are named adapters which can be used inside Chameleon templates.
+
+PyAMS_viewlet is an adaptation of zope.viewlet package to be used inside Pyramid.
+
+
+How to use pyams_viewlet?
+=========================
+
+A whole set of PyAMS documentation is available on `ReadTheDocs <https://pyams.readthedocs.io>`_
--- a/setup.py Fri Jan 18 15:32:56 2019 +0100
+++ b/setup.py Wed Nov 27 15:57:21 2019 +0100
@@ -25,14 +25,14 @@
README = os.path.join(DOCS, 'README.txt')
HISTORY = os.path.join(DOCS, 'HISTORY.txt')
-version = '0.1.7'
+version = '0.1.8'
long_description = open(README).read() + '\n\n' + open(HISTORY).read()
tests_require = []
setup(name='pyams_viewlet',
version=version,
- description="PyAMS base viewlet interfaces and classes; z3c.viewlet package adapted to Pyramid",
+ description="PyAMS viewlet interfaces and classes; z3c.viewlet package adapted to Pyramid",
long_description=long_description,
classifiers=[
"License :: OSI Approved :: Zope Public License",
@@ -60,8 +60,11 @@
'setuptools',
# -*- Extra requirements: -*-
'chameleon',
+ 'pyams_template',
'pyams_utils',
'pyramid',
+ 'pyramid_zope_request',
+ 'venusian',
'zope.component',
'zope.configuration',
'zope.contentprovider',
--- a/src/pyams_viewlet.egg-info/PKG-INFO Fri Jan 18 15:32:56 2019 +0100
+++ b/src/pyams_viewlet.egg-info/PKG-INFO Wed Nov 27 15:57:21 2019 +0100
@@ -1,16 +1,52 @@
Metadata-Version: 2.1
Name: pyams-viewlet
-Version: 0.1.7
-Summary: PyAMS base viewlet interfaces and classes; z3c.viewlet package adapted to Pyramid
+Version: 0.1.8
+Summary: PyAMS viewlet interfaces and classes; z3c.viewlet package adapted to Pyramid
Home-page: http://hg.ztfy.org/pyams/pyams_viewlet
Author: Thierry Florac
Author-email: tflorac@ulthar.net
License: ZPL
-Description:
+Description: =====================
+ PyAMS_viewlet package
+ =====================
+
+ .. contents::
+
+
+ What is PyAMS
+ =============
+
+ PyAMS (Pyramid Application Management Suite) is a small suite of packages written for applications
+ and content management with the Pyramid framework.
+
+ **PyAMS** is actually mainly used to manage web sites through content management applications (CMS,
+ see PyAMS_content package), but many features are generic and can be used inside any kind of web
+ application.
+
+
+ What is PyAMS_viewlet?
+ ======================
+
+ PyAMS_viewlet is a package which defines components called "content providers"; these content
+ providers are named adapters which can be used inside Chameleon templates.
+
+ PyAMS_viewlet is an adaptation of zope.viewlet package to be used inside Pyramid.
+
+
+ How to use pyams_viewlet?
+ =========================
+
+ A whole set of PyAMS documentation is available on `ReadTheDocs <https://pyams.readthedocs.io>`_
+
Changelog
=========
+ 0.1.8
+ -----
+ - code cleanup
+ - Gitlab-CI integration
+
0.1.7
-----
- updated "provider" TALES expression to be able to provide arguments
--- a/src/pyams_viewlet.egg-info/SOURCES.txt Fri Jan 18 15:32:56 2019 +0100
+++ b/src/pyams_viewlet.egg-info/SOURCES.txt Wed Nov 27 15:57:21 2019 +0100
@@ -4,6 +4,7 @@
docs/README.txt
src/pyams_viewlet/__init__.py
src/pyams_viewlet/configure.zcml
+src/pyams_viewlet/interfaces.py
src/pyams_viewlet/manager.py
src/pyams_viewlet/meta.zcml
src/pyams_viewlet/metaconfigure.py
@@ -18,8 +19,7 @@
src/pyams_viewlet.egg-info/not-zip-safe
src/pyams_viewlet.egg-info/requires.txt
src/pyams_viewlet.egg-info/top_level.txt
-src/pyams_viewlet/doctests/README.txt
-src/pyams_viewlet/interfaces/__init__.py
+src/pyams_viewlet/doctests/README.rst
src/pyams_viewlet/tests/__init__.py
src/pyams_viewlet/tests/test_utilsdocs.py
src/pyams_viewlet/tests/test_utilsdocstrings.py
\ No newline at end of file
--- a/src/pyams_viewlet.egg-info/requires.txt Fri Jan 18 15:32:56 2019 +0100
+++ b/src/pyams_viewlet.egg-info/requires.txt Wed Nov 27 15:57:21 2019 +0100
@@ -1,7 +1,10 @@
setuptools
chameleon
+pyams_template
pyams_utils
pyramid
+pyramid_zope_request
+venusian
zope.component
zope.configuration
zope.contentprovider
--- a/src/pyams_viewlet/__init__.py Fri Jan 18 15:32:56 2019 +0100
+++ b/src/pyams_viewlet/__init__.py Wed Nov 27 15:57:21 2019 +0100
@@ -10,18 +10,26 @@
# FOR A PARTICULAR PURPOSE.
#
-__docformat__ = 'restructuredtext'
+"""PyAMS_viewlet package
+
+Viewlets provide a generic framework for building pluggable user interfaces.
+
+Generally speaking, viewlets managers are a special type of content providers, which are used
+inside a page layout to define "regions" into which other content providers called "viewlets"
+can be plugged.
+
+By using this approach, developers can extend PyAMS features by registering new components
+which will integrate easilly into default PyAMS layout; these viewlets are registered to be
+plugged into a specific viewlet manager, which "owns" its viewlets and is defined by a
+specific interface.
+"""
+
+from chameleon import PageTemplateFile
+from pyramid.i18n import TranslationStringFactory
+
+from pyams_viewlet.provider import ProviderExpr
-# import standard library
-
-# import interfaces
-
-# import packages
-from chameleon import PageTemplateFile
-from pyams_viewlet.provider import ProviderExpr
-
-from pyramid.i18n import TranslationStringFactory
_ = TranslationStringFactory('pyams_viewlet')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_viewlet/doctests/README.rst Wed Nov 27 15:57:21 2019 +0100
@@ -0,0 +1,76 @@
+=====================
+pyams_viewlet package
+=====================
+
+These doctests are based on zope.viewlet doctests.
+
+In this implementation of viewlets, we first have to define *viewlet managers*, which are special
+content providers which manage a special type of content providers called *viewlets*. Every
+viewlets manager handles the viewlets registered for it:
+
+ >>> from pyramid.testing import setUp, tearDown
+ >>> config = setUp()
+
+ >>> from pyams_viewlet.interfaces import IViewletManager
+
+ >>> class ILeftColumn(IViewletManager):
+ ... """Left column viewlet manager"""
+
+We can then create a viewlet manager factory using this interface:
+
+ >>> from pyams_viewlet.manager import ViewletManagerFactory
+ >>> LeftColumn = ViewletManagerFactory('left-column', ILeftColumn)
+
+Having the factory, we can instantiate it:
+
+ >>> from zope.interface import implementer, Interface
+ >>> @implementer(Interface)
+ ... class Content:
+ ... """Content class"""
+ >>> content = Content()
+
+ >>> from pyramid.interfaces import IView, IRequest
+ >>> from pyramid.testing import DummyRequest
+ >>> request = DummyRequest()
+
+ >>> @implementer(IView)
+ ... class View:
+ ... def __init__(self, context, request):
+ ... self.context = context
+ ... self.request = request
+ >>> view = View(content, request)
+
+ >>> left_column = LeftColumn(content, request, view)
+
+Actually, viewlet manager doesn't render anything:
+
+ >>> left_column.update()
+ >>> left_column.render()
+ ''
+
+We have to create and register viewlets for the manager:
+
+ >>> from pyams_viewlet.interfaces import IViewlet
+ >>> from pyams_viewlet.viewlet import EmptyViewlet
+ >>> class TextBox(EmptyViewlet):
+ ... def render(self):
+ ... return '<div class="text">Text box!</div>'
+ ... def __repr__(self):
+ ... return '<TextBox object at %x>' % id(self)
+
+ >>> config.registry.registerAdapter(TextBox,
+ ... (Interface, IRequest, IView, ILeftColumn),
+ ... IViewlet, name='text-box')
+
+ >>> left_column.render()
+ ''
+
+Viewlet managers are memoized on rendering, so we have to reset it's state if we want to
+render it another time:
+
+ >>> left_column.reset()
+ >>> left_column.update()
+ >>> left_column.render()
+ '<div class="text">Text box!</div>'
+
+ >>> tearDown()
--- a/src/pyams_viewlet/doctests/README.txt Fri Jan 18 15:32:56 2019 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,133 +0,0 @@
-==================
-ZTFY.utils package
-==================
-
-Introduction
-------------
-
-This package is composed of a set of utility functions, which in complement with zope.app.zapi
-package can make Zope management easier.
-
-
-Unicode functions
------------------
-
-While working with extended characters sets containing accentuated characters, it's necessary to
-conversing strings to UTF8 so that they can be used without any conversion problem.
-
- >>> from ztfy.utils import unicode
-
-'translateString' is a utility function which can be used, for example, to generate an object's id
-without space and with accentuated characters converted to their unaccentuated version:
-
- >>> sample = 'Mon titre accentué'
- >>> unicode.translateString(sample)
- u'mon titre accentue'
-
-Results are lower-cased by default ; this can be avoided be setting the 'forceLower' parameter
-to False:
-
- >>> unicode.translateString(sample, forceLower=False)
- u'Mon titre accentue'
-
-If input string can contain 'slashes' (/) or 'backslashes' (\), they are normally removed ;
-by using the 'escapeSlashes' parameter, the input string is splitted and only the last element is
-returned ; this is handy to handle filenames on Windows platform:
-
- >>> sample = 'Autre / chaîne / accentuée'
- >>> unicode.translateString(sample)
- u'autre chaine accentuee'
- >>> unicode.translateString(sample, escapeSlashes=True)
- u'accentuee'
- >>> sample = 'C:\\Program Files\\My Application\\test.txt'
- >>> unicode.translateString(sample)
- u'cprogram filesmy applicationtest.txt'
- >>> unicode.translateString(sample, escapeSlashes=True)
- u'test.txt'
-
-To remove remaining spaces or convert them to another character, you can use the "spaces" parameter
-which can contain any string to be used instead of initial spaces:
-
- >>> sample = 'C:\\Program Files\\My Application\\test.txt'
- >>> unicode.translateString(sample, spaces=' ')
- u'cprogram filesmy applicationtest.txt'
- >>> unicode.translateString(sample, spaces='-')
- u'cprogram-filesmy-applicationtest.txt'
-
-Spaces replacement is made in the last step, so using it with "escapeSlashes" parameter only affects
-the final result:
-
- >>> unicode.translateString(sample, escapeSlashes=True, spaces='-')
- u'test.txt'
-
-Unicode module also provides encoding and decoding functions:
-
- >>> var = 'Chaîne accentuée'
- >>> unicode.decode(var)
- u'Cha\xeene accentu\xe9e'
- >>> unicode.encode(unicode.decode(var)) == var
- True
-
- >>> utf = u'Cha\xeene accentu\xe9e'
- >>> unicode.encode(utf)
- 'Cha\xc3\xaene accentu\xc3\xa9e'
- >>> unicode.decode(unicode.encode(utf)) == utf
- True
-
-
-Dates functions
----------------
-
-Dates functions are used to convert dates from/to string representation:
-
- >>> from datetime import datetime
- >>> from ztfy.utils import date
- >>> now = datetime.fromtimestamp(1205000000)
- >>> now
- datetime.datetime(2008, 3, 8, 19, 13, 20)
-
-You can get an unicode representation of a date in ASCII format using 'unidate' fonction ; date is
-converted to GMT:
-
- >>> udate = date.unidate(now)
- >>> udate
- u'2008-03-08T19:13:20+00:00'
-
-'parsedate' can be used to convert ASCII format into datetime:
-
- >>> ddate = date.parsedate(udate)
- >>> ddate
- datetime.datetime(2008, 3, 8, 19, 13, 20, tzinfo=<StaticTzInfo 'GMT'>)
-
-'datetodatetime' can be used to convert a 'date' type to a 'datetime' value ; if a 'datetime' value
-is used as argument, it is returned 'as is':
-
- >>> ddate.date()
- datetime.date(2008, 3, 8)
- >>> date.datetodatetime(ddate)
- datetime.datetime(2008, 3, 8, 19, 13, 20, tzinfo=<StaticTzInfo 'GMT'>)
- >>> date.datetodatetime(ddate.date())
- datetime.datetime(2008, 3, 8, 0, 0)
-
-
-Timezones handling
-------------------
-
-Timezones handling game me headaches at first. I finally concluded that the best way (for me !) to handle
-TZ data was to store every datetime value in GMT timezone.
-As far as I know, there is no easy way to know the user's timezone from his request settings. So you can:
-- store this timezone in user's profile,
-- define a static server's timezone
-- create and register a ServerTimezoneUtility to handle server default timezone.
-
-My current default user's timezone is set to 'Europe/Paris' ; you should probably update this setting in
-'timezone.py' if you are located elsewhere.
-
- >>> from ztfy.utils import timezone
- >>> timezone.tztime(ddate)
- datetime.datetime(2008, 3, 8, 19, 13, 20, tzinfo=<StaticTzInfo 'GMT'>)
-
-'gmtime' function can be used to convert a datetime to GMT:
-
- >>> timezone.gmtime(now)
- datetime.datetime(2008, 3, 8, 19, 13, 20, tzinfo=<StaticTzInfo 'GMT'>)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_viewlet/interfaces.py Wed Nov 27 15:57:21 2019 +0100
@@ -0,0 +1,66 @@
+#
+# 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_viewlet.interfaces module
+
+The module defines viewlet and viewlets manager interfaces.
+"""
+
+from zope.contentprovider.interfaces import IContentProvider
+from zope.interface import Attribute
+from zope.interface.common.mapping import IReadMapping
+
+
+__docformat__ = 'restructuredtext'
+
+
+class IViewlet(IContentProvider):
+ """A content provider that is managed by another content provider, known
+ as viewlet manager.
+
+ Note that you *cannot* call viewlets directly as a provider, i.e. through
+ the TALES ``provider`` expression, since it always has to know its manager.
+ """
+
+ manager = Attribute("""The Viewlet Manager
+
+ The viewlet manager for which the viewlet is registered. The viewlet
+ manager will contain any additional data that was provided by the
+ view.
+ """)
+
+
+class IViewletManager(IContentProvider, IReadMapping):
+ """A component that provides access to the content providers.
+
+ The viewlet manager's responsibilities are:
+
+ (1) Aggregation of all viewlets registered for the manager.
+
+ (2) Apply a set of filters to determine the availability of the
+ viewlets.
+
+ (3) Sort the viewlets based on some implemented policy.
+
+ (4) Provide an environment in which the viewlets are rendered.
+
+ (5) Render itself by rendering the HTML content of the viewlets.
+ """
+
+ def filter(self, viewlets):
+ """Filter manager viewlets"""
+
+ def sort(self, viewlets):
+ """Sort manager viewlets"""
+
+ def reset(self):
+ """Reset manager status; this can be required if the manager between renderings"""
--- a/src/pyams_viewlet/interfaces/__init__.py Fri Jan 18 15:32:56 2019 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +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 library
-
-# import interfaces
-from zope.contentprovider.interfaces import IContentProvider
-from zope.interface.common.mapping import IReadMapping
-
-# import packages
-from zope.interface import Attribute
-
-
-class IViewlet(IContentProvider):
- """A content provider that is managed by another content provider, known
- as viewlet manager.
-
- Note that you *cannot* call viewlets directly as a provider, i.e. through
- the TALES ``provider`` expression, since it always has to know its manager.
- """
-
- manager = Attribute("""The Viewlet Manager
-
- The viewlet manager for which the viewlet is registered. The viewlet
- manager will contain any additional data that was provided by the
- view, for example the TAL namespace attributes.
- """)
-
-
-class IViewletManager(IContentProvider, IReadMapping):
- """A component that provides access to the content providers.
-
- The viewlet manager's responsibilities are:
-
- (1) Aggregation of all viewlets registered for the manager.
-
- (2) Apply a set of filters to determine the availability of the
- viewlets.
-
- (3) Sort the viewlets based on some implemented policy.
-
- (4) Provide an environment in which the viewlets are rendered.
-
- (5) Render itself containing the HTML content of the viewlets.
- """
--- a/src/pyams_viewlet/manager.py Fri Jan 18 15:32:56 2019 +0100
+++ b/src/pyams_viewlet/manager.py Wed Nov 27 15:57:21 2019 +0100
@@ -10,7 +10,11 @@
# FOR A PARTICULAR PURPOSE.
#
-__docformat__ = 'restructuredtext'
+"""PyAMS_viewlet.manager module
+
+This module defines the viewlet manager, as weel as a "viewletmanager_config" decorator
+which can be used instead of ZCML to declare a viewlets manager.
+"""
import logging
@@ -19,9 +23,9 @@
from pyramid.httpexceptions import HTTPUnauthorized
from pyramid.interfaces import IRequest, IView
from pyramid.threadlocal import get_current_registry
-from zope.component.interfaces import ComponentLookupError
from zope.contentprovider.interfaces import BeforeUpdateEvent
from zope.interface import Interface, classImplements, implementer
+from zope.interface.interfaces import ComponentLookupError
from zope.location.interfaces import ILocation
from pyams_template.template import get_view_template
@@ -29,19 +33,26 @@
from pyams_viewlet.interfaces import IViewlet, IViewletManager
-logger = logging.getLogger('PyAMS (viewlet)')
+__docformat__ = 'restructuredtext'
+
+
+LOGGER = logging.getLogger('PyAMS (viewlet)')
@implementer(IViewletManager)
-class ViewletManager(object):
+class ViewletManager:
"""The Viewlet Manager base
- A generic manager class which can be instantiated
+ A generic manager class which can be instantiated.
+
+ A viewlet manager can be used as mapping and can get to a given viewlet by it's name.
"""
permission = None
template = None
+ viewlets = None
+
def __init__(self, context, request, view):
self.__updated = False
self.__parent__ = view
@@ -61,8 +72,10 @@
# If the viewlet cannot be accessed, then raise an
# unauthorized error
- if viewlet.permission and not self.request.has_permission(viewlet.permission, context=self.context):
- raise HTTPUnauthorized('You are not authorized to access the provider called `%s`.' % name)
+ if viewlet.permission and not self.request.has_permission(viewlet.permission,
+ context=self.context):
+ raise HTTPUnauthorized('You are not authorized to access the '
+ 'provider called `%s`.' % name)
# Return the viewlet.
return viewlet
@@ -79,38 +92,31 @@
return bool(self.get(name, False))
def filter(self, viewlets):
- """Sort out all content providers
+ """Filter out all content providers
- ``viewlets`` is a list of tuples of the form (name, viewlet).
+ :param viewlets: list of viewlets, each element being a tuple of (name, viewlet) form
+
+ Default implementation is filtering out viewlets for which a permission which is not
+ granted to the current principal is defined.
"""
- # Only return viewlets accessible to the principal
request = self.request
- return [(name, viewlet) for name, viewlet in viewlets
- if (not viewlet.permission) or request.has_permission(viewlet.permission, context=self.context)]
- def sort(self, viewlets):
+ def _filter(viewlet):
+ """Filter viewlet based on permission"""
+ _, viewlet = viewlet
+ return (not viewlet.permission) or request.has_permission(viewlet.permission,
+ context=self.context)
+
+ return filter(_filter, viewlets)
+
+ def sort(self, viewlets): # pylint: disable=no-self-use
"""Sort the viewlets.
- ``viewlets`` is a list of tuples of the form (name, viewlet).
- """
- # By default, we are not sorting by viewlet name.
- return sorted(viewlets, key=lambda x: x[0])
+ :param viewlets: list of viewlets, each element being a tuple of (name, viewlet) form
- def update(self):
- """See zope.contentprovider.interfaces.IContentProvider"""
- # check permission
- if self.permission and not self.request.has_permission(self.permission, context=self.context):
- return
- # get the viewlets from now on
- self.viewlets = []
- append = self.viewlets.append
- for name, viewlet in self._get_viewlets():
- if ILocation.providedBy(viewlet):
- viewlet.__name__ = name
- append(viewlet)
- # and update them...
- self._update_viewlets()
- self.__updated = True
+ Default implementation is sorting viewlets by name
+ """
+ return sorted(viewlets, key=lambda x: x[0])
def _get_viewlets(self):
"""Find all content providers for the region"""
@@ -128,19 +134,40 @@
registry.notify(BeforeUpdateEvent(viewlet, self.request))
viewlet.update()
+ def update(self):
+ """See :py:class:`zope.contentprovider.interfaces.IContentProvider`"""
+ # check permission
+ if self.permission and not self.request.has_permission(self.permission,
+ context=self.context):
+ return
+ # get the viewlets from now on
+ self.viewlets = []
+ append = self.viewlets.append
+ for name, viewlet in self._get_viewlets():
+ if ILocation.providedBy(viewlet):
+ viewlet.__name__ = name
+ append(viewlet)
+ # and update them...
+ self._update_viewlets()
+ self.__updated = True
+
def render(self):
- """See zope.contentprovider.interfaces.IContentProvider"""
+ """See :py:class:`zope.contentprovider.interfaces.IContentProvider`"""
# Check for previous update
if not (self.__updated and self.viewlets):
return ''
# Now render the view
if self.template:
- return self.template(viewlets=self.viewlets)
- else:
- return '\n'.join([viewlet.render() for viewlet in self.viewlets])
+ return self.template(viewlets=self.viewlets) # pylint: disable=not-callable
+ return '\n'.join([viewlet.render() for viewlet in self.viewlets])
+
+ def reset(self):
+ """Reset viewlet manager status"""
+ self.viewlets = None
+ self.__updated = False
-def ViewletManagerFactory(name, interface, bases=(), cdict=None):
+def ViewletManagerFactory(name, interface, bases=(), cdict=None): # pylint: disable=invalid-name
"""Viewlet manager factory"""
attr_dict = {'__name__': name}
@@ -149,17 +176,19 @@
if ViewletManager not in bases:
# Make sure that we do not get a default viewlet manager mixin, if the
# provided base is already a full viewlet manager implementation.
+ # pylint: disable=no-value-for-parameter
if not (len(bases) == 1 and IViewletManager.implementedBy(bases[0])):
bases = bases + (ViewletManager,)
- viewlet_manager_class = type('<ViewletManager providing %s>' % interface.getName(), bases, attr_dict)
+ viewlet_manager_class = type('<ViewletManager providing %s>' % interface.getName(),
+ bases, attr_dict)
classImplements(viewlet_manager_class, interface)
return viewlet_manager_class
def get_weight(item):
"""Get sort weight of a given viewlet"""
- name, viewlet = item
+ _, viewlet = item
try:
return int(viewlet.weight)
except (TypeError, AttributeError):
@@ -168,7 +197,7 @@
def get_label(item, request=None):
"""Get sort label of a given viewlet"""
- name, viewlet = item
+ _, viewlet = item
try:
if request is None:
request = check_request()
@@ -192,48 +221,51 @@
return sorted(viewlets, key=lambda x: get_weight_and_label(x, request=self.request))
-def is_available(viewlet):
- try:
- return ((not viewlet.permission) or
- viewlet.request.has_permission(viewlet.permission, context=viewlet.context)) and \
- viewlet.available
- except AttributeError:
- return True
-
-
class ConditionalViewletManager(WeightOrderedViewletManager):
"""Conditional weight ordered viewlet managers"""
def filter(self, viewlets):
- """Sort out all viewlets which are explicit not available
+ """Sort out all viewlets which are explicitly not available
+
+ Viewlets shoud have a boolean "available" attribute to specify if they are available
+ or not.
+ """
- ``viewlets`` is a list of tuples of the form (name, viewlet).
- """
- return [(name, viewlet) for name, viewlet in viewlets if is_available(viewlet)]
+ def is_available(viewlet):
+ _, viewlet = viewlet
+ try:
+ return ((not viewlet.permission) or
+ viewlet.request.has_permission(viewlet.permission,
+ context=viewlet.context)) and \
+ viewlet.available
+ except AttributeError:
+ return True
+
+ return filter(is_available, viewlets)
-class TemplateBasedViewletManager(object):
+class TemplateBasedViewletManager:
"""Template based viewlet manager mixin class"""
template = get_view_template()
-class viewletmanager_config(object):
+class viewletmanager_config: # pylint: disable=invalid-name
"""Class or interface decorator used to declare a viewlet manager
You can provide same arguments as in 'viewletManager' ZCML directive:
- @name = name of the viewlet; may be unique for a given viewlet manager
- @view = the view class or interface for which viewlet is displayed
- @for_ = the context class or interface for which viewlet is displayed
- @permission = name of a permission required to display the viewlet
- @layer = request interface required to display the viewlet
- @class_ = the class handling the viewlet manager; if the decorator is applied
- on an interface and if this argument is not provided, the viewlet manager
- will be handled by a default ViewletManager class
- @provides = an interface the viewlet manager provides; if the decorator is
- applied on an Interface, this will be the decorated interface; if the
- decorated is applied on a class and if this argument is not specified,
- the manager will provide IViewletManager interface.
+ :param name: name of the viewlet; may be unique for a given viewlet manager
+ :param view: the view class or interface for which viewlet is displayed
+ :param for_: the context class or interface for which viewlet is displayed
+ :param permission: name of a permission required to display the viewlet
+ :param layer: request interface required to display the viewlet
+ :param class_: the class handling the viewlet manager; if the decorator is applied
+ on an interface and if this argument is not provided, the viewlet manager
+ will be handled by a default ViewletManager class
+ :param provides: an interface the viewlet manager provides; if the decorator is
+ applied on an Interface, this will be the decorated interface; if the
+ decorated is applied on a class and if this argument is not specified,
+ the manager will provide IViewletManager interface.
"""
venusian = venusian # for testing injection
@@ -249,22 +281,22 @@
def __call__(self, wrapped):
settings = self.__dict__.copy()
- def callback(context, name, ob):
+ def callback(context, name, obj): # pylint: disable=unused-argument
cdict = {'__name__': settings.get('name')}
if 'permission' in settings:
cdict['permission'] = settings.get('permission')
- if issubclass(ob, Interface):
+ if issubclass(obj, Interface):
class_ = settings.get('class_', ViewletManager)
- provides = ob
+ provides = obj
else:
- class_ = ob
+ class_ = obj
provides = settings.get('provides', IViewletManager)
new_class = ViewletManagerFactory(settings.get('name'), provides, (class_,), cdict)
- logger.debug("Registering viewlet manager {0} ({1})".format(settings.get('name'),
+ LOGGER.debug("Registering viewlet manager {0} ({1})".format(settings.get('name'),
str(new_class)))
- config = context.config.with_package(info.module)
+ config = context.config.with_package(info.module) # pylint: disable=no-member
config.registry.registerAdapter(new_class,
(settings.get('context', Interface),
settings.get('layer', IRequest),
@@ -273,12 +305,12 @@
info = self.venusian.attach(wrapped, callback, category='pyams_viewlet')
- 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
--- a/src/pyams_viewlet/metaconfigure.py Fri Jan 18 15:32:56 2019 +0100
+++ b/src/pyams_viewlet/metaconfigure.py Wed Nov 27 15:57:21 2019 +0100
@@ -10,22 +10,23 @@
# FOR A PARTICULAR PURPOSE.
#
-__docformat__ = 'restructuredtext'
-
-
-# import standard library
+"""PyAMS_viewlet.metaconfigure module
-# import interfaces
-from pyams_viewlet.interfaces import IViewletManager, IViewlet
-from pyramid.interfaces import IRequest, IView
+This module provides ZCML directives handlers.
+"""
-# import packages
-from pyams_viewlet.manager import ViewletManager, ViewletManagerFactory
from pyramid.exceptions import ConfigurationError
+from pyramid.interfaces import IRequest, IView
from zope.component import zcml
from zope.component.interface import provideInterface
from zope.interface import Interface, classImplements
+from pyams_viewlet.interfaces import IViewlet, IViewletManager
+from pyams_viewlet.manager import ViewletManager, ViewletManagerFactory
+
+
+__docformat__ = 'restructuredtext'
+
def ViewletManagerDirective(_context, name,
context=Interface,
@@ -34,6 +35,8 @@
provides=IViewletManager,
class_=None,
permission=None):
+ # pylint: disable=invalid-name,too-many-arguments
+ """Viewlet manager ZCML directive"""
# If class is not given we use the basic viewlet manager.
if class_ is None:
@@ -66,16 +69,19 @@
attribute='render',
permission=None,
**kwargs):
+ # pylint: disable=invalid-name,too-many-arguments
+ """Viewlet ZCML directive"""
# Make sure the has the right form, if specified.
if attribute != 'render':
if not hasattr(class_, attribute):
raise ConfigurationError("The provided class doesn't have the specified attribute")
- cdict = {}
- cdict['__name__'] = name
- cdict['__page_attribute__'] = attribute
- cdict['permission'] = permission
+ cdict = {
+ '__name__': name,
+ '__page_attribute__': attribute,
+ 'permission': permission
+ }
cdict.update(kwargs)
new_class = type(class_.__name__, (class_,), cdict)
--- a/src/pyams_viewlet/metadirectives.py Fri Jan 18 15:32:56 2019 +0100
+++ b/src/pyams_viewlet/metadirectives.py Wed Nov 27 15:57:21 2019 +0100
@@ -10,19 +10,20 @@
# FOR A PARTICULAR PURPOSE.
#
-__docformat__ = 'restructuredtext'
-
-
-# import standard library
+"""PyAMS_viewlet.metadirectives module
-# import interfaces
-from pyams_viewlet.interfaces import IViewletManager
+This template provides definition of ZCML directives.
+"""
-# import packages
from zope.configuration.fields import GlobalInterface, GlobalObject
from zope.interface import Interface
from zope.schema import TextLine
+from pyams_viewlet.interfaces import IViewletManager
+
+
+__docformat__ = 'restructuredtext'
+
class IContentProvider(Interface):
"""A directive to register a simple content provider.
@@ -59,9 +60,12 @@
required=False)
layer = GlobalInterface(title="The layer the view is in",
- description="""A skin is composed of layers. It is common to put skin
- specific views in a layer named after the skin. If the 'layer'
- attribute is not supplied, it defaults to 'default'.""",
+ description="A skin is composed of layers; layers are defined as "
+ "interfaces, which are provided to the request when the "
+ "skin is applied. It is common to put skin "
+ "specific views in a layer named after the skin. If the "
+ "'layer' attribute is not supplied, it defaults to "
+ "IRequest, which is the base interface of any request.",
required=False)
@@ -101,4 +105,5 @@
# Arbitrary keys and values are allowed to be passed to the viewlet.
+# pylint: disable=no-value-for-parameter
IViewletDirective.setTaggedValue('keyword_arguments', True)
--- a/src/pyams_viewlet/provider.py Fri Jan 18 15:32:56 2019 +0100
+++ b/src/pyams_viewlet/provider.py Wed Nov 27 15:57:21 2019 +0100
@@ -10,24 +10,32 @@
# FOR A PARTICULAR PURPOSE.
#
-__docformat__ = 'restructuredtext'
+"""PyAMS_viewlet.provider module
+
+This module provides the "provider:" TALES expression, which allows inclusion of any registered
+content provider into a Chameleon or ZPT template.
+"""
import re
from chameleon.astutil import Symbol
from chameleon.tales import StringExpr
from pyramid_zope_request import PyramidPublisherRequest
-from zope.contentprovider.interfaces import BeforeUpdateEvent, ContentProviderLookupError, IContentProvider
+from zope.contentprovider.interfaces import BeforeUpdateEvent, ContentProviderLookupError, \
+ IContentProvider
from zope.contentprovider.tales import addTALNamespaceData
from zope.location.interfaces import ILocation
from pyams_utils.tales import ContextExprMixin
-FUNCTION_EXPRESSION = re.compile('(.+)\((.+)\)', re.MULTILINE | re.DOTALL)
-ARGUMENTS_EXPRESSION = re.compile('[^(,)]+')
+__docformat__ = 'restructuredtext'
+
-CONTENT_PROVIDER_NAME = re.compile('([A-Za-z0-9_\-\.]+)')
+FUNCTION_EXPRESSION = re.compile(r'(.+)\((.+)\)', re.MULTILINE | re.DOTALL)
+ARGUMENTS_EXPRESSION = re.compile(r'[^(,)]+')
+
+CONTENT_PROVIDER_NAME = re.compile(r'([A-Za-z0-9_\-\.]+)')
def render_content_provider(econtext, name):
@@ -67,7 +75,7 @@
except ValueError:
args = arg.split('.')
result = econtext.get(args.pop(0))
- for arg in args:
+ for arg in args: # pylint: disable=redefined-argument-from-local
result = getattr(result, arg)
return result
else:
@@ -77,7 +85,7 @@
context = econtext.get('context')
request = econtext.get('request')
if isinstance(request, PyramidPublisherRequest):
- request = request._request
+ request = request._request # pylint: disable=protected-access
view = econtext.get('view')
args, kwargs = [], {}
--- a/src/pyams_viewlet/tests/__init__.py Fri Jan 18 15:32:56 2019 +0100
+++ b/src/pyams_viewlet/tests/__init__.py Wed Nov 27 15:57:21 2019 +0100
@@ -1,1 +1,29 @@
+#
+# 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.
+#
+"""
+Generic Test case for pyams_viewlet doctest
+"""
+
+import os
+import sys
+
+__docformat__ = 'restructuredtext'
+
+
+def get_package_dir(value):
+ """Get package directory"""
+
+ package_dir = os.path.split(value)[0]
+ if package_dir not in sys.path:
+ sys.path.append(package_dir)
+ return package_dir
--- a/src/pyams_viewlet/tests/test_utilsdocs.py Fri Jan 18 15:32:56 2019 +0100
+++ b/src/pyams_viewlet/tests/test_utilsdocs.py Wed Nov 27 15:57:21 2019 +0100
@@ -1,5 +1,3 @@
-### -*- coding: utf-8 -*- ####################################################
-##############################################################################
#
# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
# All Rights Reserved.
@@ -11,23 +9,25 @@
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
-##############################################################################
"""
Generic Test case for pyams_viewlet doctest
"""
+
+import doctest
+import os
+import unittest
+
+from pyams_viewlet.tests import get_package_dir
+
+
__docformat__ = 'restructuredtext'
-import unittest
-import doctest
-import sys
-import os
+CURRENT_DIR = os.path.abspath(os.path.dirname(__file__))
-current_dir = os.path.dirname(__file__)
-
-def doc_suite(test_dir, setUp=None, tearDown=None, globs=None):
- """Returns a test suite, based on doctests found in /doctest."""
+def doc_suite(test_dir, setUp=None, tearDown=None, globs=None): # pylint: disable=invalid-name
+ """Returns a test suite, based on doctests found in /doctests"""
suite = []
if globs is None:
globs = globals()
@@ -35,15 +35,12 @@
flags = (doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE |
doctest.REPORT_ONLY_FIRST_FAILURE)
- package_dir = os.path.split(test_dir)[0]
- if package_dir not in sys.path:
- sys.path.append(package_dir)
-
+ package_dir = get_package_dir(test_dir)
doctest_dir = os.path.join(package_dir, 'doctests')
# filtering files on extension
docs = [os.path.join(doctest_dir, doc) for doc in
- os.listdir(doctest_dir) if doc.endswith('.txt')]
+ os.listdir(doctest_dir) if doc.endswith('.txt') or doc.endswith('.rst')]
for test in docs:
suite.append(doctest.DocFileSuite(test, optionflags=flags,
@@ -53,10 +50,11 @@
return unittest.TestSuite(suite)
+
def test_suite():
"""returns the test suite"""
- return doc_suite(current_dir)
+ return doc_suite(CURRENT_DIR)
+
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')
-
--- a/src/pyams_viewlet/tests/test_utilsdocstrings.py Fri Jan 18 15:32:56 2019 +0100
+++ b/src/pyams_viewlet/tests/test_utilsdocstrings.py Wed Nov 27 15:57:21 2019 +0100
@@ -1,5 +1,3 @@
-### -*- coding: utf-8 -*- ####################################################
-##############################################################################
#
# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
# All Rights Reserved.
@@ -11,21 +9,22 @@
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
-##############################################################################
"""
Generic Test case for pyams_viewlet doc strings
"""
+
+import doctest
+import os
+import sys
+import unittest
+
+
__docformat__ = 'restructuredtext'
-import unittest
-import doctest
-import sys
-import os
+CURRENT_DIR = os.path.abspath(os.path.dirname(__file__))
-current_dir = os.path.abspath(os.path.dirname(__file__))
-
def doc_suite(test_dir, globs=None):
"""Returns a test suite, based on doc tests strings found in /*.py"""
suite = []
@@ -45,7 +44,7 @@
docs = [doc for doc in docs if not doc.startswith('__')]
for test in docs:
- fd = open(os.path.join(package_dir, test))
+ fd = open(os.path.join(package_dir, test)) # pylint: disable=invalid-name
content = fd.read()
fd.close()
if '>>> ' not in content:
@@ -57,9 +56,11 @@
return unittest.TestSuite(suite)
+
def test_suite():
"""returns the test suite"""
- return doc_suite(current_dir)
+ return doc_suite(CURRENT_DIR)
+
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')
--- a/src/pyams_viewlet/viewlet.py Fri Jan 18 15:32:56 2019 +0100
+++ b/src/pyams_viewlet/viewlet.py Wed Nov 27 15:57:21 2019 +0100
@@ -10,7 +10,11 @@
# FOR A PARTICULAR PURPOSE.
#
-__docformat__ = 'restructuredtext'
+"""PyAMS_viewlet.viewlet module
+
+This module provides base content providers and viewlets classes, as well as a decorators
+which can be used instead of ZCML declarations to register content providers and viewlets.
+"""
import logging
@@ -23,12 +27,14 @@
from pyams_template.template import get_view_template
from pyams_viewlet.interfaces import IViewlet, IViewletManager
+__docformat__ = 'restructuredtext'
-logger = logging.getLogger('PyAMS (viewlet)')
+
+LOGGER = logging.getLogger('PyAMS (viewlet)')
@implementer(IContentProvider)
-class EmptyContentProvider(object):
+class EmptyContentProvider:
"""Empty content provider base class"""
permission = None
@@ -38,15 +44,17 @@
self.request = request
def __call__(self):
- if self.permission and not self.request.has_permission(self.permission, context=self.context):
+ if self.permission and not self.request.has_permission(self.permission,
+ context=self.context):
return ''
self.update()
return self.render()
def update(self):
- pass
+ """See `IContentProvider` interface"""
- def render(self):
+ def render(self): # pylint: disable=no-self-use
+ """See `IContentProvider` interface"""
return ''
@@ -71,7 +79,7 @@
self.view = self.__parent__ = view
-class contentprovider_config(object):
+class contentprovider_config: # pylint: disable=invalid-name
"""Class decorator used to declare a content provider
You can provide same arguments as in 'viewlet' ZCML directive:
@@ -95,22 +103,22 @@
def __call__(self, wrapped):
settings = self.__dict__.copy()
- def callback(context, name, ob):
+ def callback(context, name, obj): # pylint: disable=unused-argument
cdict = {
'__name__': settings.get('name'),
- '__module__': ob.__module__
+ '__module__': obj.__module__
}
if 'permission' in settings:
settings['permission'] = settings.get('permission')
- bases = (ob,)
- if not IContentProvider.implementedBy(ob):
+ bases = (obj,)
+ if not IContentProvider.implementedBy(obj): # pylint: disable=no-value-for-parameter
bases = bases + (ViewContentProvider,)
new_class = type('<ViewContentProvider %s>' % settings.get('name'), bases, cdict)
- logger.debug("Registering content provider {0} ({1})".format(settings.get('name'),
+ LOGGER.debug("Registering content provider {0} ({1})".format(settings.get('name'),
str(new_class)))
- config = context.config.with_package(info.module)
+ config = context.config.with_package(info.module) # pylint: disable=no-member
config.registry.registerAdapter(new_class,
(settings.get('context', Interface),
settings.get('layer', IRequest),
@@ -119,19 +127,19 @@
info = self.venusian.attach(wrapped, callback, category='pyams_viewlet')
- 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
@implementer(IViewlet)
-class EmptyViewlet(object):
+class EmptyViewlet:
"""Empty viewlet base class"""
permission = None
@@ -143,9 +151,10 @@
self.manager = manager
def update(self):
- pass
+ """See `IContentProvider` interface"""
- def render(self):
+ def render(self): # pylint: disable=no-self-use
+ """See `IContentProvider` interface"""
return ''
@@ -155,7 +164,7 @@
render = get_view_template()
-class viewlet_config(object):
+class viewlet_config: # pylint: disable=invalid-name
"""Class decorator used to declare a viewlet
You can provide same arguments as in 'viewlet' ZCML directive:
@@ -181,24 +190,24 @@
def __call__(self, wrapped):
settings = self.__dict__.copy()
- def callback(context, name, ob):
+ def callback(context, name, obj): # pylint: disable=unused-argument
cdict = {
'__name__': settings.get('name'),
- '__module__': ob.__module__
+ '__module__': obj.__module__
}
if 'permission' in settings:
cdict['permission'] = settings.get('permission')
if 'weight' in settings:
cdict['weight'] = settings.get('weight')
- bases = (ob,)
- if not IViewlet.implementedBy(ob):
+ bases = (obj,)
+ if not IViewlet.implementedBy(obj): # pylint: disable=no-value-for-parameter
bases = bases + (Viewlet,)
new_class = type('<Viewlet %s>' % settings.get('name'), bases, cdict)
- logger.debug("Registering viewlet {0} ({1})".format(settings.get('name'),
+ LOGGER.debug("Registering viewlet {0} ({1})".format(settings.get('name'),
str(new_class)))
- config = context.config.with_package(info.module)
+ config = context.config.with_package(info.module) # pylint: disable=no-member
config.registry.registerAdapter(new_class,
(settings.get('context', Interface),
settings.get('layer', IRequest),
@@ -208,12 +217,12 @@
info = self.venusian.attach(wrapped, callback, category='pyams_viewlet')
- 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