summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Howitz <mh@gocept.com>2019-04-05 08:14:58 +0200
committerMichael Howitz <mh@gocept.com>2019-04-05 08:14:58 +0200
commit59bd41536f0de971951c6d68b30e741ab93096fc (patch)
tree960588c392adc84b579294d53cbb0467598e3c6b
parent8f7b7e08b5c2775abf9a01a1ed3e1bbf6dac3e52 (diff)
downloadzope-tales-fix-16.tar.gz
Flake8 the code.fix-16
-rw-r--r--.travis.yml4
-rw-r--r--CHANGES.rst2
-rw-r--r--setup.cfg3
-rw-r--r--setup.py115
-rw-r--r--src/zope/tales/__init__.py1
-rw-r--r--src/zope/tales/engine.py7
-rw-r--r--src/zope/tales/expressions.py15
-rw-r--r--src/zope/tales/interfaces.py2
-rw-r--r--src/zope/tales/pythonexpr.py5
-rw-r--r--src/zope/tales/tales.py43
-rw-r--r--src/zope/tales/tests/simpleexpr.py7
-rw-r--r--src/zope/tales/tests/test_expressions.py27
-rw-r--r--src/zope/tales/tests/test_pythonexpr.py1
-rw-r--r--src/zope/tales/tests/test_tales.py15
-rw-r--r--src/zope/tales/tests/test_traverser.py25
-rw-r--r--tox.ini8
16 files changed, 161 insertions, 119 deletions
diff --git a/.travis.yml b/.travis.yml
index 035969a..b0627ed 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,6 +11,10 @@ matrix:
dist: xenial
- python: "3.8-dev"
dist: xenial
+ - name: "flake8"
+ install: pip install flake8
+ script: flake8 src setup.py
+ after_success:
install:
- pip install -U pip setuptools
- pip install -U coverage coverage-python-version coveralls
diff --git a/CHANGES.rst b/CHANGES.rst
index 559616d..6faa270 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -10,6 +10,8 @@
- Fix test failures and deprecation warnings occurring when using Python 3.8a1.
(`#15 <https://github.com/zopefoundation/zope.tales/pull/15>`_)
+- Flake8 the code.
+
4.3 (2018-10-05)
================
diff --git a/setup.cfg b/setup.cfg
index 2a9acf1..c1e4c65 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,2 +1,5 @@
[bdist_wheel]
universal = 1
+
+[flake8]
+doctests = yes
diff --git a/setup.py b/setup.py
index 931a6bc..d8b3f5b 100644
--- a/setup.py
+++ b/setup.py
@@ -26,65 +26,68 @@ def read(*rnames):
with open(os.path.join(os.path.dirname(__file__), *rnames)) as f:
return f.read()
+
TESTS_REQUIRE = [
'zope.testing',
'zope.testrunner',
]
-setup(name='zope.tales',
- version='5.0.dev0',
- author='Zope Foundation and Contributors',
- author_email='zope-dev@zope.org',
- description='Zope Template Application Language Expression Syntax '
- '(TALES)',
- long_description=(
- read('README.rst')
- + '\n\n' +
- read('CHANGES.rst')
- ),
- keywords="zope template xml tales",
- 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.5',
- 'Programming Language :: Python :: 3.6',
- 'Programming Language :: Python :: 3.7',
- 'Programming Language :: Python :: Implementation :: CPython',
- 'Programming Language :: Python :: Implementation :: PyPy',
- 'Natural Language :: English',
- 'Operating System :: OS Independent',
- 'Topic :: Internet :: WWW/HTTP',
- 'Framework :: Zope :: 3',
- ],
- url='https://github.com/zopefoundation/zope.tales',
- license='ZPL 2.1',
- packages=find_packages('src'),
- package_dir={'': 'src'},
- namespace_packages=['zope'],
- python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*',
- extras_require={
- 'test': TESTS_REQUIRE,
- 'tal': [
- 'zope.tal',
- ],
- 'docs': [
- 'Sphinx',
- 'repoze.sphinx.autointerface',
- 'zope.tal',
- ],
- },
- install_requires=[
- 'setuptools',
- 'zope.interface',
- 'six',
- ],
- tests_require=TESTS_REQUIRE,
- include_package_data=True,
- zip_safe=False,
+
+setup(
+ name='zope.tales',
+ version='5.0.dev0',
+ author='Zope Foundation and Contributors',
+ author_email='zope-dev@zope.org',
+ description='Zope Template Application Language Expression Syntax '
+ '(TALES)',
+ long_description=(
+ read('README.rst')
+ + '\n\n' +
+ read('CHANGES.rst')
+ ),
+ keywords="zope template xml tales",
+ 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.5',
+ 'Programming Language :: Python :: 3.6',
+ 'Programming Language :: Python :: 3.7',
+ 'Programming Language :: Python :: Implementation :: CPython',
+ 'Programming Language :: Python :: Implementation :: PyPy',
+ 'Natural Language :: English',
+ 'Operating System :: OS Independent',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Framework :: Zope :: 3',
+ ],
+ url='https://github.com/zopefoundation/zope.tales',
+ license='ZPL 2.1',
+ packages=find_packages('src'),
+ package_dir={'': 'src'},
+ namespace_packages=['zope'],
+ python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*',
+ extras_require={
+ 'test': TESTS_REQUIRE,
+ 'tal': [
+ 'zope.tal',
+ ],
+ 'docs': [
+ 'Sphinx',
+ 'repoze.sphinx.autointerface',
+ 'zope.tal',
+ ],
+ },
+ install_requires=[
+ 'setuptools',
+ 'zope.interface',
+ 'six',
+ ],
+ tests_require=TESTS_REQUIRE,
+ include_package_data=True,
+ zip_safe=False,
)
diff --git a/src/zope/tales/__init__.py b/src/zope/tales/__init__.py
index 61cfd4c..ccf848b 100644
--- a/src/zope/tales/__init__.py
+++ b/src/zope/tales/__init__.py
@@ -13,4 +13,3 @@
##############################################################################
"""Template Attribute Language - Expression Syntax
"""
-
diff --git a/src/zope/tales/engine.py b/src/zope/tales/engine.py
index 7bab8f2..dd07600 100644
--- a/src/zope/tales/engine.py
+++ b/src/zope/tales/engine.py
@@ -24,6 +24,7 @@ from zope.tales.expressions import LazyExpr
from zope.tales.expressions import SimpleModuleImporter
from zope.tales.pythonexpr import PythonExpr
+
def DefaultEngine():
"""
Create and return an instance of :class:`~.ExpressionEngine` (an
@@ -44,8 +45,9 @@ def DefaultEngine():
``modules``
:class:`.SimpleModuleImporter`
- In addition, the default ``path`` expressions (``standard``, ``path``, ``exists``
- and ``nocall``), all implemented by :class:`.PathExpr`, are registered.
+ In addition, the default ``path`` expressions (``standard``, ``path``,
+ ``exists`` and ``nocall``), all implemented by :class:`.PathExpr`, are
+ registered.
"""
e = ExpressionEngine()
reg = e.registerType
@@ -59,4 +61,5 @@ def DefaultEngine():
e.registerBaseName('modules', SimpleModuleImporter())
return e
+
Engine = DefaultEngine()
diff --git a/src/zope/tales/expressions.py b/src/zope/tales/expressions.py
index 48be495..81a626b 100644
--- a/src/zope/tales/expressions.py
+++ b/src/zope/tales/expressions.py
@@ -16,9 +16,9 @@ Basic Page Template expression types.
Expression objects are created by the :class:`.ExpressionEngine`
(they must have previously been registered with
-:func:`~zope.tales.tales.ExpressionEngine.registerType`). The expression object itself
-is a callable object taking one argument, *econtext*, which is the local
-expression namespace.
+:func:`~zope.tales.tales.ExpressionEngine.registerType`). The expression
+object itself is a callable object taking one argument, *econtext*, which is
+the local expression namespace.
"""
import re
@@ -38,6 +38,7 @@ namespace_re = re.compile(r'(\w+):(.+)')
PY2 = sys.version_info[0] == 2
+
def simpleTraverse(object, path_items, econtext):
"""Traverses a sequence of names, first trying attributes then items.
"""
@@ -168,7 +169,7 @@ class PathExpr(object):
'path',
'exists',
'nocall',
- )
+ )
def __init__(self, name, expr, engine, traverser=simpleTraverse):
self._s = expr
@@ -240,11 +241,11 @@ class PathExpr(object):
return '<PathExpr %s:%s>' % (self._name, repr(self._s))
-
_interp = re.compile(
r'\$(%(n)s)|\${(%(n)s(?:/[^}|]*)*(?:\|%(n)s(?:/[^}|]*)*)*)}'
% {'n': NAME_RE})
+
@implementer(ITALESExpression)
class StringExpr(object):
"""
@@ -264,7 +265,8 @@ class StringExpr(object):
path_type = engine.getTypes()['path']
parts = []
for exp in expr.split('$$'):
- if parts: parts.append('$')
+ if parts:
+ parts.append('$')
m = _interp.search(exp)
while m is not None:
parts.append(exp[:m.start()])
@@ -365,6 +367,7 @@ class LazyWrapper(DeferWrapper):
self._result = r = self._expr(self._econtext)
return r
+
class LazyExpr(DeferExpr):
"""
An expression that will defer evaluation of its
diff --git a/src/zope/tales/interfaces.py b/src/zope/tales/interfaces.py
index 158b794..58c234f 100644
--- a/src/zope/tales/interfaces.py
+++ b/src/zope/tales/interfaces.py
@@ -33,6 +33,7 @@ class ITALESFunctionNamespace(Interface):
def setEngine(engine):
"""Sets the engine that is used to evaluate TALES expressions."""
+
class ITALESExpression(Interface):
"""TALES expression
@@ -46,6 +47,7 @@ class ITALESExpression(Interface):
*econtext* and return computed value.
"""
+
class ITALESIterator(ITALIterator):
"""TAL Iterator provided by TALES.
diff --git a/src/zope/tales/pythonexpr.py b/src/zope/tales/pythonexpr.py
index 3f47bed..01df726 100644
--- a/src/zope/tales/pythonexpr.py
+++ b/src/zope/tales/pythonexpr.py
@@ -14,6 +14,7 @@
"""Generic Python Expression Handler
"""
+
class PythonExpr(object):
"""
Evaluates a python expression by calling :func:`eval` after
@@ -25,8 +26,8 @@ class PythonExpr(object):
:param ExpressionEngine engine: The expression compiler that
is creating us.
"""
- text = '\n'.join(expr.splitlines()) # normalize line endings
- text = '(' + text + ')' # Put text in parens so newlines don't matter
+ text = '\n'.join(expr.splitlines()) # normalize line endings
+ text = '(' + text + ')' # Put text in parens so newlines don't matter
self.text = text
try:
code = self._compile(text, '<string>')
diff --git a/src/zope/tales/tales.py b/src/zope/tales/tales.py
index 21a3276..d5ca006 100644
--- a/src/zope/tales/tales.py
+++ b/src/zope/tales/tales.py
@@ -15,7 +15,6 @@
An implementation of a TAL expression engine
"""
-__docformat__ = "reStructuredText"
import re
try:
@@ -29,23 +28,28 @@ import six
from zope.tales.interfaces import ITALESIterator
+
class ITALExpressionEngine(Interface):
pass
+
+
class ITALExpressionCompiler(Interface):
pass
+
+
class ITALExpressionErrorInfo(Interface):
pass
+
try:
# Override with real, if present
- from zope.tal.interfaces import (ITALExpressionEngine,
+ from zope.tal.interfaces import (ITALExpressionEngine, # noqa: F811
ITALExpressionCompiler,
ITALExpressionErrorInfo)
except ImportError:
pass
-
NAME_RE = r"[a-zA-Z][a-zA-Z0-9_]*"
_parse_expr = re.compile(r"(%s):" % NAME_RE).match
_valid_name = re.compile('%s$' % NAME_RE).match
@@ -54,18 +58,22 @@ _valid_name = re.compile('%s$' % NAME_RE).match
class TALESError(Exception):
"""Error during TALES evaluation"""
+
class Undefined(TALESError):
- '''Exception raised on traversal of an undefined path'''
+ """Exception raised on traversal of an undefined path."""
+
class CompilerError(Exception):
- '''TALES Compiler Error'''
+ """TALES Compiler Error"""
+
class RegistrationError(Exception):
- '''Expression type or base name registration Error'''
+ """Expression type or base name registration Error."""
_default = object()
+
@implementer(ITALESIterator)
class Iterator(object):
"""
@@ -568,8 +576,8 @@ class ExpressionEngine(object):
:param str namespace: a string containing the name of the namespace to
be registered
- :param callable namespacecallable: a callable object which takes the following
- parameter:
+ :param callable namespacecallable: a callable object which takes the
+ following parameter:
:context: the object on which the functions
provided by this namespace will
@@ -596,7 +604,6 @@ class ExpressionEngine(object):
"""
self.namespaces[namespacename] = namespacecallable
-
def getFunctionNamespace(self, namespacename):
""" Returns the function namespace """
return self.namespaces[namespacename]
@@ -605,11 +612,12 @@ class ExpressionEngine(object):
"""
Register an expression of *name* to be handled with *handler*.
- :raises RegistrationError: If this is a duplicate registration for *name*,
- or if *name* is not a valid expression type name.
+ :raises RegistrationError: If this is a duplicate registration for
+ *name*, or if *name* is not a valid expression type name.
"""
if not _valid_name(name):
- raise RegistrationError('Invalid expression type name "%s".' % name)
+ raise RegistrationError(
+ 'Invalid expression type name "%s".' % name)
types = self.types
if name in types:
raise RegistrationError(
@@ -674,8 +682,8 @@ class Context(object):
:class:`zope.tal.interfaces.ITALExpressionEngine`.
This class is called ``Context`` because an instance of this class
- holds context information (namespaces) that it uses when evaluating compiled
- expressions.
+ holds context information (namespaces) that it uses when evaluating
+ compiled expressions.
"""
position = (None, None)
source_file = None
@@ -695,7 +703,7 @@ class Context(object):
self.repeat_vars = rv = {}
# Wrap this, as it is visible to restricted code
self.setContext('repeat', rv)
- self.setContext('loop', rv) # alias
+ self.setContext('loop', rv) # alias
self.vars = vars = contexts.copy()
self._vars_stack = [vars]
@@ -704,7 +712,8 @@ class Context(object):
self._scope_stack = []
def setContext(self, name, value):
- """Hook to allow subclasses to do things like adding security proxies."""
+ """Hook to allow subclasses to do things like adding security proxies.
+ """
self.contexts[name] = value
def beginScope(self):
@@ -822,7 +831,7 @@ class TALESTracebackSupplement(object):
import pprint
data = self.context.contexts.copy()
if 'modules' in data:
- del data['modules'] # the list is really long and boring
+ del data['modules'] # the list is really long and boring
s = pprint.pformat(data)
if not as_html:
return ' - Names:\n %s' % s.replace('\n', '\n ')
diff --git a/src/zope/tales/tests/simpleexpr.py b/src/zope/tales/tests/simpleexpr.py
index 7befa35..ac5409c 100644
--- a/src/zope/tales/tests/simpleexpr.py
+++ b/src/zope/tales/tests/simpleexpr.py
@@ -14,15 +14,16 @@
"""Simple TALES Expression
"""
+
class SimpleExpr(object):
- '''Simple example of an expression type handler
+ """Simple example of an expression type handler for testing."""
- for testing
- '''
def __init__(self, name, expr, engine):
self._name = name
self._expr = expr
+
def __call__(self, econtext):
return self._name, self._expr
+
def __repr__(self):
return '<SimpleExpr %s %s>' % (self._name, repr(self._expr))
diff --git a/src/zope/tales/tests/test_expressions.py b/src/zope/tales/tests/test_expressions.py
index 94f8ecf..651ed74 100644
--- a/src/zope/tales/tests/test_expressions.py
+++ b/src/zope/tales/tests/test_expressions.py
@@ -32,8 +32,8 @@ class Data(object):
self.__dict__.update(kw)
def __getattr__(self, name):
- # Let linters (like pylint) know this is a dynamic class and they shouldn't
- # emit "Data has no attribute" errors
+ # Let linters (like pylint) know this is a dynamic class and they
+ # shouldn't emit "Data has no attribute" errors
return object.__getattribute__(self, name)
def __repr__(self):
@@ -41,6 +41,7 @@ class Data(object):
__str__ = __repr__
+
class ErrorGenerator(object):
def __getitem__(self, name):
@@ -51,15 +52,17 @@ class ErrorGenerator(object):
e = getattr(builtins, name, None) or SystemError
raise e('mess')
+
class Callable(object):
def __call__(self):
return 42
-class OldStyleCallable: # NOT object
+class OldStyleCallable: # NOT object
pass
+
class ExpressionTestBase(zope.tales.tests.TestCase):
def setUp(self):
@@ -220,7 +223,8 @@ class TestParsedExpressions(ExpressionTestBase):
# Simple eight bit string interpolation should just work.
# Except on Py3, where we really mess it up.
expr = self.engine.compile('string:a ${eightBits}')
- expected = 'a ' + self.context.vars['eightBits'] if not six.PY3 else self.py3BrokenEightBits
+ expected = ('a ' + self.context.vars['eightBits']
+ if not six.PY3 else self.py3BrokenEightBits)
self._check_evals_to(expr, expected)
def testStringUnicode(self):
@@ -241,7 +245,8 @@ class TestParsedExpressions(ExpressionTestBase):
# poorly.
self.assertTrue(six.PY3)
self.assertEqual(result, self.py3BrokenEightBits)
- self.context.vars['eightBits'].decode('ascii') # raise UnicodeDecodeError
+ # raise UnicodeDecodeError
+ self.context.vars['eightBits'].decode('ascii')
def test_string_escape_percent(self):
self._check_evals_to('string:%', '%')
@@ -283,6 +288,7 @@ class TestParsedExpressions(ExpressionTestBase):
def testEmptyPathSegmentRaisesCompilerError(self):
CompilerError = self.engine.getCompilerError()
+
def check(expr):
self.assertRaises(CompilerError, self.engine.compile, expr)
@@ -394,7 +400,7 @@ class FunctionTests(ExpressionTestBase):
self.engine.registerFunctionNamespace('namespace', self.TestNameSpace)
self.engine.registerFunctionNamespace('not_callable_ns', None)
- ## framework-ish tests
+ # framework-ish tests
def testSetEngine(self):
expr = self.engine.compile('adapterTest/namespace:engine')
@@ -411,7 +417,7 @@ class FunctionTests(ExpressionTestBase):
self.engine.getFunctionNamespace,
'badnamespace')
- ## compile time tests
+ # compile time tests
def testBadNamespace(self):
# namespace doesn't exist
@@ -457,14 +463,15 @@ class FunctionTests(ExpressionTestBase):
e = exc.exception
self.assertEqual(e.args[0], 'title')
- ## runtime tests
+ # runtime tests
def testNormalFunction(self):
expr = self.engine.compile('adapterTest/namespace:upper')
self.assertEqual(expr(self.context), 'YIKES')
def testFunctionOnFunction(self):
- expr = self.engine.compile('adapterTest/namespace:jump/namespace:upper')
+ expr = self.engine.compile(
+ 'adapterTest/namespace:jump/namespace:upper')
self.assertEqual(expr(self.context), 'XANDER')
def testPathOnFunction(self):
@@ -476,6 +483,7 @@ class FunctionTests(ExpressionTestBase):
with self.assertRaisesRegex(ValueError, 'None'):
expr(self.context)
+
class TestSimpleModuleImporter(unittest.TestCase):
def _makeOne(self):
@@ -493,7 +501,6 @@ class TestSimpleModuleImporter(unittest.TestCase):
with self.assertRaises(ImportError):
self._makeOne()['this cannot exist']
-
def test_no_such_submodule_not_package(self):
with self.assertRaises(ImportError):
self._makeOne()['zope.tales.tests.test_expressions.submodule']
diff --git a/src/zope/tales/tests/test_pythonexpr.py b/src/zope/tales/tests/test_pythonexpr.py
index 7410c41..edc8764 100644
--- a/src/zope/tales/tests/test_pythonexpr.py
+++ b/src/zope/tales/tests/test_pythonexpr.py
@@ -20,6 +20,7 @@ from zope.tales.tales import Context
from zope.tales.pythonexpr import PythonExpr
from zope.tales.pythonexpr import ExprTypeProxy
+
class TestPythonExpr(unittest.TestCase):
def setUp(self):
diff --git a/src/zope/tales/tests/test_tales.py b/src/zope/tales/tests/test_tales.py
index 1781624..03a1fe5 100644
--- a/src/zope/tales/tests/test_tales.py
+++ b/src/zope/tales/tests/test_tales.py
@@ -16,6 +16,7 @@
from doctest import DocTestSuite
import unittest
import re
+import sys
import six
from zope.tales import tales
@@ -52,6 +53,7 @@ class TestIterator(unittest.TestCase):
self.assertTrue(not next(it), "Multi-element iterator")
context._complete_()
+
class TALESTests(unittest.TestCase):
def testRegisterType(self):
@@ -150,6 +152,7 @@ class TALESTests(unittest.TestCase):
ctxt.endScope()
+
class TestExpressionEngine(zope.tales.tests.TestCase):
def setUp(self):
@@ -183,6 +186,7 @@ class TestExpressionEngine(zope.tales.tests.TestCase):
self.assertEqual(ctx.contexts['b'], 2)
self.assertEqual(ctx.contexts['c'], 1)
+
class TestContext(unittest.TestCase):
def setUp(self):
@@ -249,7 +253,6 @@ class TestContext(unittest.TestCase):
self.assertEqual(u'text', self.context.evaluateText("it"))
def test_traceback_supplement(self):
- import sys
def raises(self):
raise Exception()
@@ -305,6 +308,7 @@ class Harness(object):
def __getattr__(self, name):
return HarnessMethod(self, name)
+
class HarnessMethod(object):
def __init__(self, harness, name):
@@ -333,11 +337,10 @@ class HarnessMethod(object):
def test_suite():
- checker = renormalizing.RENormalizing(
- [(re.compile(r"object of type 'MyIter' has no len\(\)"),
- r"len() of unsized object"),
- ]
- )
+ checker = renormalizing.RENormalizing([
+ (re.compile(r"object of type 'MyIter' has no len\(\)"),
+ r"len() of unsized object"),
+ ])
suite = unittest.defaultTestLoader.loadTestsFromName(__name__)
suite.addTest(DocTestSuite("zope.tales.tales",
checker=checker))
diff --git a/src/zope/tales/tests/test_traverser.py b/src/zope/tales/tests/test_traverser.py
index b791889..dd9eb0d 100644
--- a/src/zope/tales/tests/test_traverser.py
+++ b/src/zope/tales/tests/test_traverser.py
@@ -13,7 +13,7 @@
##############################################################################
""" Tests for zope.tales.expressions.simpleTraverse
"""
-from unittest import TestCase, TestSuite, makeSuite, main
+from unittest import TestCase
from zope.tales.expressions import simpleTraverse
@@ -21,13 +21,16 @@ class AttrTraversable(object):
"""Traversable by attribute access"""
attr = 'foo'
+
class ItemTraversable(object):
"""Traversable by item access"""
+
def __getitem__(self, name):
if name == 'attr':
return 'foo'
raise KeyError(name)
+
class AllTraversable(AttrTraversable, ItemTraversable):
"""Traversable by attribute and item access"""
pass
@@ -35,6 +38,7 @@ class AllTraversable(AttrTraversable, ItemTraversable):
_marker = object()
+
def getitem(ob, name, default=_marker):
"""Helper a la getattr(ob, name, default)."""
try:
@@ -82,7 +86,7 @@ class TraverserTests(TestCase):
self.assertRaises(KeyError, getitem, ob, 'missing_attr')
def testTraverseEmptyPath(self):
- # simpleTraverse should return the original object if the path is emtpy
+ # simpleTraverse should return the original object if the path is empty
ob = object()
self.assertEqual(simpleTraverse(ob, [], None), ob)
@@ -95,7 +99,8 @@ class TraverserTests(TestCase):
# simpleTraverse should raise AttributeError
ob = AttrTraversable()
# Here lurks the bug (unexpected NamError raised)
- self.assertRaises(AttributeError, simpleTraverse, ob, ['missing_attr'], None)
+ self.assertRaises(
+ AttributeError, simpleTraverse, ob, ['missing_attr'], None)
def testTraverseByItem(self):
# simpleTraverse should find attr through item access
@@ -113,17 +118,7 @@ class TraverserTests(TestCase):
self.assertEqual(simpleTraverse(ob, ['attr'], None), 'foo')
def testTraverseByMissingAll(self):
- # simpleTraverse should raise KeyError (because ob implements __getitem__)
+ # simpleTraverse should raise KeyError (because ob implements
+ # __getitem__)
ob = AllTraversable()
self.assertRaises(KeyError, simpleTraverse, ob, ['missing_attr'], None)
-
-
-def test_suite():
- return TestSuite((
- makeSuite(TraverserTests),
- ))
-
-
-if __name__ == '__main__':
- main(defaultTest='test_suite')
-
diff --git a/tox.ini b/tox.ini
index 8929592..5413964 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,6 +1,6 @@
[tox]
envlist =
- py27,py35,py36,py37,py38,pypy,pypy3,coverage,docs
+ flake8,py27,py35,py36,py37,py38,pypy,pypy3,coverage,docs
[testenv]
commands =
@@ -28,3 +28,9 @@ commands =
deps =
{[testenv]deps}
.[docs]
+
+
+[testenv:flake8]
+deps = flake8
+skipinstall = true
+commands = flake8 setup.py src