From 24f90e30dbeec752accc4443a05129b7fe98cc4f Mon Sep 17 00:00:00 2001 From: Michael Howitz Date: Fri, 21 Dec 2018 20:32:05 +0100 Subject: [PATCH 1/5] Black the code. --- .coveragerc | 2 +- .travis.yml | 6 ++ docs/conf.py | 104 ++++++++++++----------- setup.py | 103 +++++++++++----------- src/z3c/__init__.py | 2 +- src/z3c/pt/__init__.py | 7 +- src/z3c/pt/expressions.py | 73 ++++++++-------- src/z3c/pt/namespaces.py | 12 ++- src/z3c/pt/pagetemplate.py | 122 +++++++++++++++------------ src/z3c/pt/tests/test_doctests.py | 47 ++++++----- src/z3c/pt/tests/test_expressions.py | 78 ++++++++--------- src/z3c/pt/tests/test_loader.py | 28 ++++-- src/z3c/pt/tests/test_namespaces.py | 26 +++--- src/z3c/pt/tests/test_templates.py | 113 +++++++++++++------------ tox.ini | 8 +- 15 files changed, 403 insertions(+), 328 deletions(-) diff --git a/.coveragerc b/.coveragerc index a5f9235..42cd130 100644 --- a/.coveragerc +++ b/.coveragerc @@ -5,7 +5,7 @@ source = z3c.pt precision = 2 exclude_lines = pragma: no cover - if __name__ == '__main__': + if __name__ == "__main__": raise NotImplementedError self.fail raise AssertionError diff --git a/.travis.yml b/.travis.yml index e903051..fe6f1d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,12 @@ python: - 3.6 - pypy - pypy3 +matrix: + include: + - python: 3.6 + name: "Flake8" + install: pip install -U flake8 + script: flake8 --doctests src docs setup.py install: - pip install -U pip setuptools - pip install -U coverage coveralls diff --git a/docs/conf.py b/docs/conf.py index be6c96b..897c2f7 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -3,10 +3,12 @@ # z3c.pt documentation build configuration file, created by # sphinx-quickstart on Wed Jul 16 13:18:14 2008. # -# This file is execfile()d with the current directory set to its containing dir. +# This file is execfile()d with the current directory set to its containing +# dir. # # The contents of this file are pickled, so don't put values in the namespace -# that aren't pickleable (module imports are okay, they're removed automatically). +# that aren't pickleable (module imports are okay, they're removed +# automatically). # # All configuration values have a default value; values that are commented out # serve to show the default value. @@ -15,61 +17,62 @@ # General configuration # --------------------- -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest'] +extensions = ["sphinx.ext.autodoc", "sphinx.ext.doctest"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['.templates'] +templates_path = [".templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'index' +master_doc = "index" # General substitutions. -project = 'z3c.pt' -copyright = '2007-2009 The Zope Community' +project = "z3c.pt" +copyright = "2007-2009 The Zope Community" # The default replacements for |version| and |release|, also used in various # other places throughout the built documents. # # The short X.Y version. -version = '1.0' +version = "1.0" # The full version, including alpha/beta/rc tags. -release = '1.0b14' +release = "1.0b14" # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -today_fmt = '%B %d, %Y' +today_fmt = "%B %d, %Y" # List of documents that shouldn't be included in the build. -#unused_docs = [] +# unused_docs = [] -# List of directories, relative to source directories, that shouldn't be searched -# for source files. -#exclude_dirs = [] +# List of directories, relative to source directories, that shouldn't be +# searched for source files. +# exclude_dirs = [] -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None +# The reST default role (used for this markup: `text`) to use for all +# documents. +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # Options for HTML output @@ -78,96 +81,97 @@ # The style sheet to use for HTML and HTML Help pages. A file of that name # must exist either in Sphinx' static/ path, or in one of the custom paths # given in html_static_path. -html_style = 'default.css' +html_style = "default.css" # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -#html_title = None +# html_title = None # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# html_short_title = None # The name of an image file (within the static path) to place at the top of # the sidebar. -#html_logo = None +# html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +# html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['.static'] +html_static_path = [".static"] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -html_last_updated_fmt = '%b %d, %Y' +html_last_updated_fmt = "%b %d, %Y" # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_use_modindex = True +# html_use_modindex = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, the reST sources are included in the HTML build as _sources/. -#html_copy_source = True +# html_copy_source = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -#html_use_opensearch = '' +# html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = '' +# html_file_suffix = '' # Output file base name for HTML help builder. -htmlhelp_basename = 'z3cptdoc' +htmlhelp_basename = "z3cptdoc" # Options for LaTeX output # ------------------------ # The paper size ('letter' or 'a4'). -#latex_paper_size = 'letter' +# latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). -#latex_font_size = '10pt' +# latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, document class [howto/manual]). +# (source start file, target name, title, author, document class +# [howto/manual]). latex_documents = [ - ('index', 'z3cpt.tex', 'z3c.pt Documentation', 'Malthe Borch', 'manual'), + ("index", "z3cpt.tex", "z3c.pt Documentation", "Malthe Borch", "manual") ] # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # Additional stuff for the LaTeX preamble. -#latex_preamble = '' +# latex_preamble = '' # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_use_modindex = True +# latex_use_modindex = True diff --git a/setup.py b/setup.py index ab81297..4f865d3 100644 --- a/setup.py +++ b/setup.py @@ -25,78 +25,75 @@ def read(*filenames): def alltests(): import sys import unittest + # use the zope.testrunner machinery to find all the # test suites we've put under ourselves import zope.testrunner.find import zope.testrunner.options - here = os.path.abspath(os.path.join(os.path.dirname(__file__), 'src')) + + here = os.path.abspath(os.path.join(os.path.dirname(__file__), "src")) args = sys.argv[:] defaults = ["--test-path", here] options = zope.testrunner.options.get_options(args, defaults) suites = list(zope.testrunner.find.find_suites(options)) return unittest.TestSuite(suites) -TESTS_REQUIRE = [ - 'zope.pagetemplate', - 'zope.testing', - 'zope.testrunner', -] + +TESTS_REQUIRE = ["zope.pagetemplate", "zope.testing", "zope.testrunner"] setup( - name='z3c.pt', - version='3.1.1.dev0', - author='Malthe Borch and the Zope Community', - author_email='zope-dev@zope.org', - description='Fast ZPT engine.', + name="z3c.pt", + version="3.1.1.dev0", + author="Malthe Borch and the Zope Community", + author_email="zope-dev@zope.org", + description="Fast ZPT engine.", long_description=( - read('README.rst') - + '\n\n' - + read('src', 'z3c', 'pt', 'README.rst') - + '\n\n' - + read('CHANGES.rst') + read("README.rst") + + "\n\n" + + read("src", "z3c", "pt", "README.rst") + + "\n\n" + + read("CHANGES.rst") ), - license='ZPL', - keywords='tal tales pagetemplate zope chameleon', + license="ZPL", + keywords="tal tales pagetemplate zope chameleon", classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Environment :: Web Environment', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: Zope Public License', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: Implementation', - 'Programming Language :: Python :: Implementation :: CPython', - 'Programming Language :: Python :: Implementation :: PyPy', - 'Natural Language :: English', - 'Operating System :: OS Independent', - 'Topic :: Text Processing :: Markup :: HTML', - 'Topic :: Text Processing :: Markup :: XML', - 'Framework :: Zope :: 3', + "Development Status :: 5 - Production/Stable", + "Environment :: Web Environment", + "Intended Audience :: Developers", + "License :: OSI Approved :: Zope Public License", + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: Implementation", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Natural Language :: English", + "Operating System :: OS Independent", + "Topic :: Text Processing :: Markup :: HTML", + "Topic :: Text Processing :: Markup :: XML", + "Framework :: Zope :: 3", ], - url='https://github.com/zopefoundation/z3c.pt', - namespace_packages=['z3c'], - packages=find_packages('src'), - package_dir={'': 'src'}, + url="https://github.com/zopefoundation/z3c.pt", + namespace_packages=["z3c"], + packages=find_packages("src"), + package_dir={"": "src"}, install_requires=[ - 'setuptools', - 'six', - 'zope.interface', - 'zope.component', - 'zope.i18n >= 3.5', - 'zope.traversing', - 'zope.contentprovider', - 'Chameleon >= 2.4', + "setuptools", + "six", + "zope.interface", + "zope.component", + "zope.i18n >= 3.5", + "zope.traversing", + "zope.contentprovider", + "Chameleon >= 2.4", ], - extras_require={ - 'test': TESTS_REQUIRE, - }, + extras_require={"test": TESTS_REQUIRE}, tests_require=TESTS_REQUIRE, - test_suite='__main__.alltests', + test_suite="__main__.alltests", include_package_data=True, zip_safe=False, ) diff --git a/src/z3c/__init__.py b/src/z3c/__init__.py index 2cdb0e4..fe35068 100644 --- a/src/z3c/__init__.py +++ b/src/z3c/__init__.py @@ -1 +1 @@ -__import__('pkg_resources').declare_namespace(__name__) # pragma: no cover +__import__("pkg_resources").declare_namespace(__name__) # pragma: no cover diff --git a/src/z3c/pt/__init__.py b/src/z3c/pt/__init__.py index fb8bc9c..3bf4324 100644 --- a/src/z3c/pt/__init__.py +++ b/src/z3c/pt/__init__.py @@ -1,6 +1,7 @@ -__import__('pkg_resources').declare_namespace(__name__) +__import__("pkg_resources").declare_namespace(__name__) # Fix a Python 3 bug in Chameleon. -import chameleon.i18n -import six +import chameleon.i18n # noqa: E402 +import six # noqa: E402 + chameleon.i18n.basestring = six.string_types diff --git a/src/z3c/pt/expressions.py b/src/z3c/pt/expressions.py index 9d664ba..cc170ca 100644 --- a/src/z3c/pt/expressions.py +++ b/src/z3c/pt/expressions.py @@ -44,12 +44,13 @@ def render_content_provider(econtext, name): name = name.strip() - context = econtext.get('context') - request = econtext.get('request') - view = econtext.get('view') + context = econtext.get("context") + request = econtext.get("request") + view = econtext.get("view") cp = zope.component.queryMultiAdapter( - (context, request, view), IContentProvider, name=name) + (context, request, view), IContentProvider, name=name + ) # provide a useful error message, if the provider was not found. # Be sure to provide the objects in addition to the name so @@ -74,19 +75,20 @@ def render_content_provider(econtext, name): def path_traverse(base, econtext, call, path_items): if path_items: - request = econtext.get('request') + request = econtext.get("request") path_items = list(path_items) path_items.reverse() while path_items: name = path_items.pop() - ns_used = ':' in name + ns_used = ":" in name if ns_used: - namespace, name = name.split(':', 1) + namespace, name = name.split(":", 1) base = z3c.pt.namespaces.function_namespaces[namespace](base) if ITraversable.providedBy(base): base = traversePathElement( - base, name, path_items, request=request) + base, name, path_items, request=request + ) # base = proxify(base) @@ -102,15 +104,17 @@ def path_traverse(base, econtext, call, path_items): base = next if ns_used and isinstance(base, MethodType): base = base() - continue # pragma: no cover (bytecode peephole optimizer removes this) + # The bytecode peephole optimizer removes the next line: + continue # pragma: no cover else: base = traversePathElement( - base, name, path_items, request=request) + base, name, path_items, request=request + ) # if not isinstance(base, (basestring, tuple, list)): # base = proxify(base) - if call and getattr(base, '__call__', _marker) is not _marker: + if call and getattr(base, "__call__", _marker) is not _marker: return base() return base @@ -123,25 +127,26 @@ class ContextExpressionMixin(object): def __call__(self, target, engine): # Make call to superclass to assign value to target - assignment = super(ContextExpressionMixin, self).\ - __call__(target, engine) + assignment = super(ContextExpressionMixin, self).__call__( + target, engine + ) transform = template( "target = transform(econtext, target)", target=target, transform=self.transform, - ) + ) return assignment + transform class PathExpr(TalesExpr): path_regex = re.compile( - r'^(?:(nocall|not):\s*)*((?:[A-Za-z0-9_][A-Za-z0-9_:]*)' + - r'(?:/[?A-Za-z0-9_@\-+][?A-Za-z0-9_@\-\.+/:]*)*)$') + r"^(?:(nocall|not):\s*)*((?:[A-Za-z0-9_][A-Za-z0-9_:]*)" + + r"(?:/[?A-Za-z0-9_@\-+][?A-Za-z0-9_@\-\.+/:]*)*)$" + ) - interpolation_regex = re.compile( - r'\?[A-Za-z][A-Za-z0-9_]+') + interpolation_regex = re.compile(r"\?[A-Za-z][A-Za-z0-9_]+") traverser = Symbol(path_traverse) @@ -152,8 +157,7 @@ def _find_translation_components(self, parts): def replace(match): start, end = match.span() - interpolation_args.append( - part[start + 1:end]) + interpolation_args.append(part[start + 1: end]) return "%s" while True: @@ -163,12 +167,13 @@ def replace(match): if interpolation_args: component = template( - "format % args", format=ast.Str(part), + "format % args", + format=ast.Str(part), args=ast.Tuple( - list(map(load, interpolation_args)), - ast.Load() - ), - mode="eval") + list(map(load, interpolation_args)), ast.Load() + ), + mode="eval", + ) else: component = ast.Str(part) @@ -194,14 +199,14 @@ def translate(self, string, target): nocall, path = m.groups() # note that unicode paths are not allowed - parts = str(path).split('/') + parts = str(path).split("/") components = self._find_translation_components(parts) base = parts[0] if not components: - if len(parts) == 1 and (nocall or base == 'None'): + if len(parts) == 1 and (nocall or base == "None"): return template("target = base", base=base, target=target) else: components = () @@ -213,7 +218,7 @@ def translate(self, string, target): call=load(str(not nocall)), path_items=ast.Tuple(elts=components), mode="eval", - ) + ) return template("target = value", target=target, value=call) @@ -223,7 +228,8 @@ class NocallExpr(PathExpr): def translate(self, expression, engine): return super(NocallExpr, self).translate( - "nocall:%s" % expression, engine) + "nocall:%s" % expression, engine + ) class ExistsExpr(BaseExistsExpr): @@ -243,8 +249,9 @@ class PythonExpr(BasePythonExpr): "tales(econtext, rcontext, name)", tales=Builtin("tales"), name=ast.Str(s=name), - mode="eval") - for name in ('path', 'exists', 'string', 'nocall') + mode="eval", + ) + for name in ("path", "exists", "string", "nocall") } def __call__(self, target, engine): @@ -258,8 +265,8 @@ def rewrite(self, node): get=Builtin("get"), name=ast.Str(s=node.id), builtin=builtin, - mode="eval" - ) + mode="eval", + ) @property def transform(self): diff --git a/src/z3c/pt/namespaces.py b/src/z3c/pt/namespaces.py index 7889c65..afb561c 100644 --- a/src/z3c/pt/namespaces.py +++ b/src/z3c/pt/namespaces.py @@ -14,6 +14,7 @@ import zope.component from zope.traversing.interfaces import IPathAdapter + class AdapterNamespaces(object): """Simulate tales function namespaces with adapter lookup. @@ -47,16 +48,18 @@ def __init__(self): def __getitem__(self, name): namespace = self.namespaces.get(name) if namespace is None: + def namespace(object): try: - return zope.component.getAdapter(object, IPathAdapter, name) + return zope.component.getAdapter( + object, IPathAdapter, name + ) except zope.component.ComponentLookupError: raise KeyError(name) self.namespaces[name] = namespace return namespace - def registerFunctionNamespace(self, namespacename, namespacecallable): """Register a function namespace @@ -91,7 +94,6 @@ def lower(self): """ self.namespaces[namespacename] = namespacecallable - def getFunctionNamespace(self, namespacename): """ Returns the function namespace, if registered. @@ -101,6 +103,7 @@ def getFunctionNamespace(self, namespacename): """ return self.namespaces[namespacename] + function_namespaces = AdapterNamespaces() try: @@ -108,6 +111,7 @@ def getFunctionNamespace(self, namespacename): # registered with the main zope.pagetemplate engine so that # we don't need to re-register them. from zope.pagetemplate.engine import Engine + function_namespaces = Engine.namespaces -except (ImportError, AttributeError): # pragma: no cover +except (ImportError, AttributeError): # pragma: no cover pass diff --git a/src/z3c/pt/pagetemplate.py b/src/z3c/pt/pagetemplate.py index 8c827fe..9ca6200 100644 --- a/src/z3c/pt/pagetemplate.py +++ b/src/z3c/pt/pagetemplate.py @@ -29,6 +29,7 @@ try: from Missing import MV + MV = MV # pyflakes pragma: no cover except ImportError: MV = object() @@ -36,16 +37,27 @@ _marker = object() -BOOLEAN_HTML_ATTRS = frozenset([ - # List of Boolean attributes in HTML that should be rendered in - # minimized form (e.g. rather than ) - # From http://www.w3.org/TR/xhtml1/#guidelines (C.10) - # TODO: The problem with this is that this is not valid XML and - # can't be parsed back! - "compact", "nowrap", "ismap", "declare", "noshade", "checked", - "disabled", "readonly", "multiple", "selected", "noresize", - "defer" -]) +BOOLEAN_HTML_ATTRS = frozenset( + [ + # List of Boolean attributes in HTML that should be rendered in + # minimized form (e.g. rather than ) + # From http://www.w3.org/TR/xhtml1/#guidelines (C.10) + # TODO: The problem with this is that this is not valid XML and + # can't be parsed back! + "compact", + "nowrap", + "ismap", + "declare", + "noshade", + "checked", + "disabled", + "readonly", + "multiple", + "selected", + "noresize", + "defer", + ] +) class OpaqueDict(dict): @@ -63,6 +75,7 @@ def __len__(self): def __repr__(self): return "{...} (%d entries)" % len(self) + sys_modules = ProxyFactory(OpaqueDict(sys.modules)) @@ -71,14 +84,14 @@ class BaseTemplate(template.PageTemplate): version = 2 expression_types = { - 'python': expressions.PythonExpr, - 'string': StringExpr, - 'not': NotExpr, - 'exists': expressions.ExistsExpr, - 'path': expressions.PathExpr, - 'provider': expressions.ProviderExpr, - 'nocall': expressions.NocallExpr, - } + "python": expressions.PythonExpr, + "string": StringExpr, + "not": NotExpr, + "exists": expressions.ExistsExpr, + "path": expressions.PathExpr, + "provider": expressions.ProviderExpr, + "nocall": expressions.NocallExpr, + } default_expression = "path" @@ -90,20 +103,17 @@ class BaseTemplate(template.PageTemplate): @property def boolean_attributes(self): - if self.content_type == 'text/xml': + if self.content_type == "text/xml": return set() return BOOLEAN_HTML_ATTRS @property def builtins(self): - builtins = { - 'nothing': None, - 'modules': sys_modules, - } + builtins = {"nothing": None, "modules": sys_modules} tales = ExpressionEvaluator(self.engine, builtins) - builtins['tales'] = tales + builtins["tales"] = tales return builtins @@ -117,7 +127,7 @@ def render(request=request, **kwargs): def render(self, target_language=None, **context): # We always include a ``request`` variable; it is (currently) # depended on in various expression types and must be defined - request = context.setdefault('request', None) + request = context.setdefault("request", None) if target_language is None: try: @@ -125,13 +135,17 @@ def render(self, target_language=None, **context): except Exception: target_language = None - context['target_language'] = target_language + context["target_language"] = target_language # bind translation-method to request def translate( - msgid, domain=None, mapping=None, - target_language=None, default=None, - context=None): + msgid, + domain=None, + mapping=None, + target_language=None, + default=None, + context=None, + ): if msgid is MV: # Special case handling of Zope2's Missing.MV # (Missing.Value) used by the ZCatalog but is @@ -140,19 +154,20 @@ def translate( # This case cannot arise in ordinary templates; msgid # comes from i18n:translate attributes, which does not # take a TALES expression, just a literal string. - # However, the 'context' argument is available as an implementation - # detail for macros + # However, the 'context' argument is available as an + # implementation detail for macros return return fast_translate( - msgid, domain, mapping, request, target_language, default) + msgid, domain, mapping, request, target_language, default + ) + context["translate"] = translate if request is not None and not isinstance(request, six.string_types): - content_type = self.content_type or 'text/html' + content_type = self.content_type or "text/html" response = request.response if response and not response.getHeader("Content-Type"): - response.setHeader( - "Content-Type", content_type) + response.setHeader("Content-Type", content_type) base_renderer = super(BaseTemplate, self).render return base_renderer(**context) @@ -168,7 +183,7 @@ def _pt_get_context(self, instance, request, kwargs): options=kwargs, request=request, template=self, - ) + ) class BaseTemplateFile(BaseTemplate, template.PageTemplateFile): @@ -184,18 +199,20 @@ def __init__(self, filename, path=None, content_type=None, **kwargs): if not os.path.isabs(filename): for depth in (1, 2): frame = sys._getframe(depth) - package_name = frame.f_globals.get('__name__', None) - if package_name is not None and \ - package_name != self.__module__: + package_name = frame.f_globals.get("__name__", None) + if ( + package_name is not None + and package_name != self.__module__ + ): module = sys.modules[package_name] try: path = module.__path__[0] except AttributeError: path = module.__file__ - path = path[:path.rfind(os.sep)] + path = path[: path.rfind(os.sep)] break else: - package_path = frame.f_globals.get('__file__', None) + package_path = frame.f_globals.get("__file__", None) if package_path is not None: path = os.path.dirname(package_path) break @@ -203,8 +220,7 @@ def __init__(self, filename, path=None, content_type=None, **kwargs): if path is not None: filename = os.path.join(path, filename) - template.PageTemplateFile.__init__( - self, filename, **kwargs) + template.PageTemplateFile.__init__(self, filename, **kwargs) # Set content-type last, so that we can override whatever was # magically sniffed from the source template. @@ -247,21 +263,21 @@ class ViewPageTemplate(PageTemplate): is 'path' (standard Zope traversal).""" def _pt_get_context(self, view, request, kwargs): - context = kwargs.get('context') + context = kwargs.get("context") if context is None: context = view.context - request = request or kwargs.get('request') or view.request + request = request or kwargs.get("request") or view.request return dict( view=view, context=context, request=request, options=kwargs, template=self, - ) + ) def __call__(self, _ob=None, context=None, request=None, **kwargs): - kwargs.setdefault('context', context) - kwargs.setdefault('request', request) + kwargs.setdefault("context", context) + kwargs.setdefault("request", request) bound_pt = self.bind(_ob) return bound_pt(**kwargs) @@ -282,8 +298,8 @@ class BoundPageTemplate(object): __func__ = None def __init__(self, pt, render): - object.__setattr__(self, '__self__', pt) - object.__setattr__(self, '__func__', render) + object.__setattr__(self, "__self__", pt) + object.__setattr__(self, "__func__", render) im_self = property(lambda self: self.__self__) im_func = property(lambda self: self.__func__) @@ -291,7 +307,7 @@ def __init__(self, pt, render): filename = property(lambda self: self.__self__.filename) def __call__(self, *args, **kw): - kw.setdefault('args', args) + kw.setdefault("args", args) return self.__func__(**kw) def __setattr__(self, name, v): @@ -300,4 +316,6 @@ def __setattr__(self, name, v): def __repr__(self): return "<%s.Bound%s %r>" % ( type(self.__self__).__module__, - type(self.__self__).__name__, self.filename) + type(self.__self__).__name__, + self.filename, + ) diff --git a/src/z3c/pt/tests/test_doctests.py b/src/z3c/pt/tests/test_doctests.py index 63ba8f0..417e7bb 100644 --- a/src/z3c/pt/tests/test_doctests.py +++ b/src/z3c/pt/tests/test_doctests.py @@ -18,31 +18,40 @@ import zope.configuration.xmlconfig import z3c.pt -OPTIONFLAGS = (doctest.ELLIPSIS - | doctest.NORMALIZE_WHITESPACE) +OPTIONFLAGS = doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE def setUp(suite): zope.component.testing.setUp(suite) - zope.configuration.xmlconfig.XMLConfig('configure.zcml', z3c.pt)() + zope.configuration.xmlconfig.XMLConfig("configure.zcml", z3c.pt)() def test_suite(): - filesuites = ('README.rst',) - testsuites = 'z3c.pt.expressions', 'z3c.pt.namespaces' + filesuites = ("README.rst",) + testsuites = "z3c.pt.expressions", "z3c.pt.namespaces" return unittest.TestSuite( - [doctest.DocFileSuite( - filesuite, optionflags=OPTIONFLAGS, - setUp=setUp, tearDown=zope.component.testing.tearDown, - package="z3c.pt") - for filesuite in filesuites] - + - [doctest.DocTestSuite( - testsuite, optionflags=OPTIONFLAGS, - setUp=setUp, tearDown=zope.component.testing.tearDown) - for testsuite in testsuites] - ) - -if __name__ == '__main__': - unittest.main(defaultTest='test_suite') + [ + doctest.DocFileSuite( + filesuite, + optionflags=OPTIONFLAGS, + setUp=setUp, + tearDown=zope.component.testing.tearDown, + package="z3c.pt", + ) + for filesuite in filesuites + ] + + [ + doctest.DocTestSuite( + testsuite, + optionflags=OPTIONFLAGS, + setUp=setUp, + tearDown=zope.component.testing.tearDown, + ) + for testsuite in testsuites + ] + ) + + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/src/z3c/pt/tests/test_expressions.py b/src/z3c/pt/tests/test_expressions.py index 22e1138..569b25c 100644 --- a/src/z3c/pt/tests/test_expressions.py +++ b/src/z3c/pt/tests/test_expressions.py @@ -11,24 +11,22 @@ # pylint:disable=protected-access -class TestRenderContentProvider(CleanUp, - unittest.TestCase): +class TestRenderContentProvider(CleanUp, unittest.TestCase): def test_not_found(self): from zope.contentprovider.interfaces import ContentProviderLookupError context = object() request = object() view = object() - name = 'a provider' - econtext = {'context': context, 'request': request, 'view': view} + name = "a provider" + econtext = {"context": context, "request": request, "view": view} with self.assertRaises(ContentProviderLookupError) as exc: expressions.render_content_provider(econtext, name) e = exc.exception - self.assertEqual(e.args, - (name, (context, request, view))) + self.assertEqual(e.args, (name, (context, request, view))) def test_sets_ilocation_name(self): from zope import component @@ -48,29 +46,29 @@ def __setattr__(self, name, value): update = render = lambda s: None - component.provideAdapter(Provider, - adapts=(object, object, object), - provides=IContentProvider, - name='a provider') + component.provideAdapter( + Provider, + adapts=(object, object, object), + provides=IContentProvider, + name="a provider", + ) context = object() request = object() view = object() - econtext = {'context': context, 'request': request, 'view': view} + econtext = {"context": context, "request": request, "view": view} - expressions.render_content_provider(econtext, 'a provider') + expressions.render_content_provider(econtext, "a provider") - self.assertEqual(attrs, {'__name__': 'a provider'}) + self.assertEqual(attrs, {"__name__": "a provider"}) -class TestPathExpr(CleanUp, - unittest.TestCase): - +class TestPathExpr(CleanUp, unittest.TestCase): def test_translate_empty_string(self): import ast - expr = expressions.PathExpr('') - result = expr.translate('', 'foo') + expr = expressions.PathExpr("") + result = expr.translate("", "foo") self.assertEqual(len(result), 1) self.assertIsInstance(result[0], ast.Assign) @@ -78,64 +76,64 @@ def test_translate_empty_string(self): def test_translate_invalid_path(self): from chameleon.exc import ExpressionError - expr = expressions.PathExpr('') + expr = expressions.PathExpr("") with self.assertRaises(ExpressionError): - expr.translate('not valid', None) + expr.translate("not valid", None) def test_translate_components(self): from chameleon.codegen import TemplateCodeGenerator from chameleon.astutil import ASTCodeGenerator from chameleon.astutil import node_annotations - expr = expressions.PathExpr('') - comps = expr._find_translation_components(['a']) + + expr = expressions.PathExpr("") + comps = expr._find_translation_components(["a"]) # First component is skipped self.assertEqual(comps, []) # Single literal - comps = expr._find_translation_components(['a', 'b']) - self.assertEqual([s.s for s in comps], ['b']) + comps = expr._find_translation_components(["a", "b"]) + self.assertEqual([s.s for s in comps], ["b"]) # Multiple literals - comps = expr._find_translation_components(['a', 'b', 'c']) - self.assertEqual([s.s for s in comps], ['b', 'c']) + comps = expr._find_translation_components(["a", "b", "c"]) + self.assertEqual([s.s for s in comps], ["b", "c"]) # Single interpolation---must be longer than one character - comps = expr._find_translation_components(['a', '?b']) - self.assertEqual([s.s for s in comps], ['?b']) + comps = expr._find_translation_components(["a", "?b"]) + self.assertEqual([s.s for s in comps], ["?b"]) - comps = expr._find_translation_components(['a', '?var']) + comps = expr._find_translation_components(["a", "?var"]) self.assertEqual(len(comps), 1) code = ASTCodeGenerator(comps[0]).code - self.assertEqual(code, '(format % args)') + self.assertEqual(code, "(format % args)") code = TemplateCodeGenerator(comps[0]).code self.assertEqual(code, "('%s' % (var, ))") args = node_annotations[comps[0].right] code = TemplateCodeGenerator(args).code - self.assertEqual(code, '(var, )') - + self.assertEqual(code, "(var, )") # Multiple interpolations - comps = expr._find_translation_components(['a', '?var', "?var2"]) + comps = expr._find_translation_components(["a", "?var", "?var2"]) self.assertEqual(len(comps), 2) code = ASTCodeGenerator(comps[0]).code - self.assertEqual(code, '(format % args)') + self.assertEqual(code, "(format % args)") code = TemplateCodeGenerator(comps[0]).code self.assertEqual(code, "('%s' % (var, ))") args = node_annotations[comps[0].right] code = TemplateCodeGenerator(args).code - self.assertEqual(code, '(var, )') + self.assertEqual(code, "(var, )") code = ASTCodeGenerator(comps[1]).code - self.assertEqual(code, '(format % args)') + self.assertEqual(code, "(format % args)") code = TemplateCodeGenerator(comps[1]).code self.assertEqual(code, "('%s' % (var2, ))") args = node_annotations[comps[1].right] code = TemplateCodeGenerator(args).code - self.assertEqual(code, '(var2, )') + self.assertEqual(code, "(var2, )") translated = expr.translate("a/?var/?var2", None) self.assertEqual(len(translated), 1) @@ -143,7 +141,9 @@ def test_translate_components(self): # XXX: Normally this starts with 'None =', but sometimes on Python 2, # at least in tox, it starts with '__package__ ='. Why # is this? - code = code.strip().replace("__package__", 'None') + code = code.strip().replace("__package__", "None") self.assertEqual( code, - "None = _path_traverse(a, econtext, True, (('%s' % (var, )), ('%s' % (var2, )), ))") + "None = _path_traverse(a, econtext, True, (('%s' % (var, )), " + "('%s' % (var2, )), ))", + ) diff --git a/src/z3c/pt/tests/test_loader.py b/src/z3c/pt/tests/test_loader.py index a2e3431..0eb151d 100644 --- a/src/z3c/pt/tests/test_loader.py +++ b/src/z3c/pt/tests/test_loader.py @@ -13,6 +13,7 @@ ############################################################################## import unittest + class LoadTests: def _makeOne(self, search_path=None, **kwargs): klass = self._getTargetClass() @@ -20,43 +21,52 @@ def _makeOne(self, search_path=None, **kwargs): def _getTargetClass(self): from z3c.pt.loader import TemplateLoader + return TemplateLoader def test_load_relative(self): import os + here = os.path.dirname(__file__) - loader = self._makeOne(search_path = [here]) + loader = self._makeOne(search_path=[here]) - result = self._load(loader, 'view.pt') - self.assertEqual(result.filename, os.path.join(here, 'view.pt')) + result = self._load(loader, "view.pt") + self.assertEqual(result.filename, os.path.join(here, "view.pt")) def test_consecutive_loads(self): import os + here = os.path.dirname(__file__) - loader = self._makeOne(search_path = [here]) + loader = self._makeOne(search_path=[here]) self.assertTrue( - self._load(loader, 'view.pt') is self._load(loader, 'view.pt')) + self._load(loader, "view.pt") is self._load(loader, "view.pt") + ) def test_load_relative_badpath_in_searchpath(self): import os + here = os.path.dirname(__file__) - loader = self._makeOne(search_path = [os.path.join(here, 'none'), here]) - result = self._load(loader, 'view.pt') - self.assertEqual(result.filename, os.path.join(here, 'view.pt')) + loader = self._makeOne(search_path=[os.path.join(here, "none"), here]) + result = self._load(loader, "view.pt") + self.assertEqual(result.filename, os.path.join(here, "view.pt")) def test_load_abs(self): import os + here = os.path.dirname(__file__) loader = self._makeOne() - abs = os.path.join(here, 'view.pt') + abs = os.path.join(here, "view.pt") result = self._load(loader, abs) self.assertEqual(result.filename, abs) + class LoadPageTests(unittest.TestCase, LoadTests): def _load(self, loader, filename): return loader.load_page(filename) + def test_suite(): import sys + return unittest.findTestCases(sys.modules[__name__]) diff --git a/src/z3c/pt/tests/test_namespaces.py b/src/z3c/pt/tests/test_namespaces.py index 28b08a3..502ee36 100644 --- a/src/z3c/pt/tests/test_namespaces.py +++ b/src/z3c/pt/tests/test_namespaces.py @@ -8,27 +8,31 @@ from z3c.pt import namespaces -class TestAdapterNamespaces(unittest.TestCase): +class TestAdapterNamespaces(unittest.TestCase): def test_registered_name(self): nss = namespaces.AdapterNamespaces() - func = lambda ctx: ctx - nss.registerFunctionNamespace('ns', func) - self.assertIs(func, nss['ns']) - self.assertIs(func, nss.getFunctionNamespace('ns')) + func = lambda ctx: ctx # noqa: E731 + nss.registerFunctionNamespace("ns", func) + self.assertIs(func, nss["ns"]) + self.assertIs(func, nss.getFunctionNamespace("ns")) def test_unregistered_name(self): nss = namespaces.AdapterNamespaces() with self.assertRaises(KeyError): - nss.getFunctionNamespace('ns') + nss.getFunctionNamespace("ns") # but __getitem__ makes one up - self.assertIsNotNone(nss['ns']) + self.assertIsNotNone(nss["ns"]) def test_using_pagetemplate_version(self): from zope.pagetemplate import engine - self.assertFalse(isinstance(namespaces.function_namespaces, - namespaces.AdapterNamespaces)) - self.assertIsInstance(namespaces.function_namespaces, - engine.AdapterNamespaces) + self.assertFalse( + isinstance( + namespaces.function_namespaces, namespaces.AdapterNamespaces + ) + ) + self.assertIsInstance( + namespaces.function_namespaces, engine.AdapterNamespaces + ) diff --git a/src/z3c/pt/tests/test_templates.py b/src/z3c/pt/tests/test_templates.py index 49c138b..630ac9b 100644 --- a/src/z3c/pt/tests/test_templates.py +++ b/src/z3c/pt/tests/test_templates.py @@ -21,60 +21,67 @@ from z3c.pt.pagetemplate import PageTemplateFile from z3c.pt.pagetemplate import ViewPageTemplateFile -class Setup(CleanUp): +class Setup(CleanUp): def setUp(self): CleanUp.setUp(self) import z3c.pt - zope.configuration.xmlconfig.file('configure.zcml', z3c.pt) -class TestPageTemplate(Setup, - unittest.TestCase): + zope.configuration.xmlconfig.file("configure.zcml", z3c.pt) + +class TestPageTemplate(Setup, unittest.TestCase): def test_string_function(self): - template = pagetemplate.PageTemplate('''
''') + template = pagetemplate.PageTemplate( + """
""" + ) result = template.render() - self.assertEqual(result, - '
a string
') + self.assertEqual(result, "
a string
") def test_nocall_function(self): class Call(object): def __call__(self): raise AssertionError("Should not be called") + def __str__(self): return "Not Called" - arg = {'call': Call()} - template = pagetemplate.PageTemplate('''
''') + + arg = {"call": Call()} + template = pagetemplate.PageTemplate( + """
""" + ) result = template.render(arg=arg) - self.assertEqual(result, - '
Not Called
') + self.assertEqual(result, "
Not Called
") -class TestPageTemplateFile(Setup, - unittest.TestCase): +class TestPageTemplateFile(Setup, unittest.TestCase): def test_nocall(self): template = PageTemplateFile("nocall.pt") + def dont_call(): raise AssertionError("Should not be called") + result = template(callable=dont_call) self.assertTrue(repr(dont_call) in result) def test_exists(self): template = PageTemplateFile("exists.pt") + def dont_call(): raise AssertionError("Should not be called") + result = template(callable=dont_call) - self.assertTrue('ok' in result) + self.assertTrue("ok" in result) def test_false_attribute(self): template = PageTemplateFile("false.pt") result = template() - self.assertTrue('False' in result) + self.assertTrue("False" in result) def test_boolean_attribute(self): template = PageTemplateFile("boolean.pt") result = template() - self.assertFalse('False' in result) + self.assertFalse("False" in result) self.assertTrue('checked="checked"' in result) def test_path(self): @@ -90,11 +97,9 @@ class Context(object): self.assertTrue("supported" in result) self.assertTrue("some path" in result) -class TestViewPageTemplateFile(Setup, - unittest.TestCase): +class TestViewPageTemplateFile(Setup, unittest.TestCase): def test_provider(self): - class Context(object): pass @@ -121,7 +126,6 @@ class ITestProvider(Interface): @implementer(ITestProvider) class Provider(object): - def __init__(self, *args): data.extend(list(args)) @@ -129,8 +133,7 @@ def update(self): data.extend("updated") def render(self): - return """""" % ( - data, self.__dict__) + return """""" % (data, self.__dict__) view = View() data = [] @@ -140,13 +143,14 @@ def render(self): from zope.contentprovider.interfaces import IContentProvider provideAdapter( - Provider, ( + Provider, + ( implementedBy(Context), implementedBy(Request), - implementedBy(View) + implementedBy(View), ), IContentProvider, - name="content" + name="content", ) context = Context() @@ -154,42 +158,43 @@ def render(self): result = view(context=context, request=request) self.assertIn(repr(data), result) - self.assertIn(repr({'context': context}), result) + self.assertIn(repr({"context": context}), result) -class TestOpaqueDict(unittest.TestCase): +class TestOpaqueDict(unittest.TestCase): def test_getitem(self): import operator + d = {} od = pagetemplate.OpaqueDict(d) with self.assertRaises(KeyError): - operator.itemgetter('key')(od) + operator.itemgetter("key")(od) - d['key'] = 42 - self.assertEqual(od['key'], 42) + d["key"] = 42 + self.assertEqual(od["key"], 42) def test_len(self): d = {} od = pagetemplate.OpaqueDict(d) self.assertEqual(0, len(od)) - d['key'] = 42 + d["key"] = 42 self.assertEqual(1, len(od)) def test_repr(self): d = {} od = pagetemplate.OpaqueDict(d) - self.assertEqual('{...} (0 entries)', repr(od)) + self.assertEqual("{...} (0 entries)", repr(od)) - d['key'] = 42 - self.assertEqual('{...} (1 entries)', repr(od)) + d["key"] = 42 + self.assertEqual("{...} (1 entries)", repr(od)) class TestBaseTemplate(unittest.TestCase): - def test_negotiate_fails(self): class I18N(object): request = None + def negotiate(self, request): self.request = request raise Exception("This is caught") @@ -198,56 +203,60 @@ def negotiate(self, request): orig_i18n = pagetemplate.i18n pagetemplate.i18n = i18n try: - template = pagetemplate.BaseTemplate('') - request = 'strings are allowed' + template = pagetemplate.BaseTemplate("") + request = "strings are allowed" template.render(request=request) self.assertIs(i18n.request, request) finally: pagetemplate.i18n = orig_i18n def test_translate_mv(self): - template = pagetemplate.BaseTemplate(""" + template = pagetemplate.BaseTemplate( + """ - """) + """ + ) class Macro(object): translate = None + def include(self, stream, econtext, *args, **kwargs): - self.translate = econtext['translate'] + self.translate = econtext["translate"] + macro = Macro() template.render(m=macro) self.assertIsNone(macro.translate(pagetemplate.MV)) -class TestBaseTemplateFile(unittest.TestCase): +class TestBaseTemplateFile(unittest.TestCase): def test_init_with_path(self): here = os.path.abspath(os.path.dirname(__file__)) - template = pagetemplate.BaseTemplateFile('view.pt', path=here) + template = pagetemplate.BaseTemplateFile("view.pt", path=here) - self.assertEqual(template.filename, - os.path.join(here, 'view.pt')) + self.assertEqual(template.filename, os.path.join(here, "view.pt")) -class TestBoundPageTemplate(unittest.TestCase): +class TestBoundPageTemplate(unittest.TestCase): def test_setattr(self): bound = pagetemplate.BoundPageTemplate(None, None) - with self.assertRaisesRegexp(AttributeError, - "Can't set attribute"): - setattr(bound, '__self__', 42) + with self.assertRaisesRegexp(AttributeError, "Can't set attribute"): + setattr(bound, "__self__", 42) def test_repr(self): # It requires the 'filename' attribute class Template(object): - filename = 'file.pt' + filename = "file.pt" - bound = pagetemplate.BoundPageTemplate(Template(), 'render') - self.assertEqual("", - repr(bound)) + bound = pagetemplate.BoundPageTemplate(Template(), "render") + self.assertEqual( + "", + repr(bound), + ) def test_attributes(self): func = object() diff --git a/tox.ini b/tox.ini index fef112b..cf33e1f 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] envlist = - py27,py34,py35,py36,pypy,pypy3,coverage + flake8,py27,py34,py35,py36,pypy,pypy3,coverage [testenv] commands = @@ -18,3 +18,9 @@ commands = deps = {[testenv]deps} coverage + +[testenv:flake8] +basepython = python3.6 +skip_install = true +deps = flake8 +commands = flake8 --doctests src docs setup.py From a7f73d7cbcd4f36ec35f6a4a9659310f910ae91d Mon Sep 17 00:00:00 2001 From: Michael Howitz Date: Fri, 21 Dec 2018 20:35:24 +0100 Subject: [PATCH 2/5] Add support for Python 3.7. --- .travis.yml | 3 ++- CHANGES.rst | 2 +- setup.py | 1 + tox.ini | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index fe6f1d9..0e26ec2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,4 @@ language: python -sudo: false python: - 2.7 - 3.4 @@ -9,6 +8,8 @@ python: - pypy3 matrix: include: + - python: 3.7 + dist: xenial - python: 3.6 name: "Flake8" install: pip install -U flake8 diff --git a/CHANGES.rst b/CHANGES.rst index 6260824..f6173b1 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,7 +5,7 @@ 3.1.1 (unreleased) ================== -- Nothing changed yet. +- Add support for Python 3.7. 3.1.0 (2017-10-17) diff --git a/setup.py b/setup.py index 4f865d3..3f376a0 100644 --- a/setup.py +++ b/setup.py @@ -68,6 +68,7 @@ def alltests(): "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", "Programming Language :: Python :: Implementation", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", diff --git a/tox.ini b/tox.ini index cf33e1f..2485677 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] envlist = - flake8,py27,py34,py35,py36,pypy,pypy3,coverage + flake8,py27,py34,py35,py36,py37,pypy,pypy3,coverage [testenv] commands = From b79372b17a6b90d00518767f3fe9a6d5e65ebbaf Mon Sep 17 00:00:00 2001 From: Michael Howitz Date: Fri, 21 Dec 2018 20:37:58 +0100 Subject: [PATCH 3/5] Drop support for running the tests using `python setup.py test` --- CHANGES.rst | 2 ++ setup.py | 19 ------------------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index f6173b1..f96d62c 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,6 +7,8 @@ - Add support for Python 3.7. +- Drop support for running the tests using `python setup.py test`. + 3.1.0 (2017-10-17) ================== diff --git a/setup.py b/setup.py index 3f376a0..5d71def 100644 --- a/setup.py +++ b/setup.py @@ -22,23 +22,6 @@ def read(*filenames): return f.read() -def alltests(): - import sys - import unittest - - # use the zope.testrunner machinery to find all the - # test suites we've put under ourselves - import zope.testrunner.find - import zope.testrunner.options - - here = os.path.abspath(os.path.join(os.path.dirname(__file__), "src")) - args = sys.argv[:] - defaults = ["--test-path", here] - options = zope.testrunner.options.get_options(args, defaults) - suites = list(zope.testrunner.find.find_suites(options)) - return unittest.TestSuite(suites) - - TESTS_REQUIRE = ["zope.pagetemplate", "zope.testing", "zope.testrunner"] setup( @@ -93,8 +76,6 @@ def alltests(): "Chameleon >= 2.4", ], extras_require={"test": TESTS_REQUIRE}, - tests_require=TESTS_REQUIRE, - test_suite="__main__.alltests", include_package_data=True, zip_safe=False, ) From 31b94590cbe21f64cd58ba39699b8d3a299fcc0c Mon Sep 17 00:00:00 2001 From: Michael Howitz Date: Fri, 21 Dec 2018 20:57:33 +0100 Subject: [PATCH 4/5] Prevent editing the files inside the tox env. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 2485677..717903b 100644 --- a/tox.ini +++ b/tox.ini @@ -3,13 +3,13 @@ envlist = flake8,py27,py34,py35,py36,py37,pypy,pypy3,coverage [testenv] +usedevelop = true commands = zope-testrunner --test-path=src [] deps = .[test] [testenv:coverage] -usedevelop = true basepython = python2.7 commands = From 18acc1576ea4d3432e2ca5e2a811f64371ba4d1f Mon Sep 17 00:00:00 2001 From: Michael Howitz Date: Fri, 21 Dec 2018 20:57:44 +0100 Subject: [PATCH 5/5] Fix deprecation warning. --- src/z3c/pt/tests/test_templates.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/z3c/pt/tests/test_templates.py b/src/z3c/pt/tests/test_templates.py index 630ac9b..d1446a5 100644 --- a/src/z3c/pt/tests/test_templates.py +++ b/src/z3c/pt/tests/test_templates.py @@ -242,9 +242,15 @@ def test_init_with_path(self): class TestBoundPageTemplate(unittest.TestCase): + + # Avoid DeprecationWarning for assertRaisesRegexp on Python 3 while + # coping with Python 2 not having the Regex spelling variant + assertRaisesRegex = getattr(unittest.TestCase, 'assertRaisesRegex', + unittest.TestCase.assertRaisesRegexp) + def test_setattr(self): bound = pagetemplate.BoundPageTemplate(None, None) - with self.assertRaisesRegexp(AttributeError, "Can't set attribute"): + with self.assertRaisesRegex(AttributeError, "Can't set attribute"): setattr(bound, "__self__", 42) def test_repr(self):