Skip to content

Commit

Permalink
Merge pull request #8 from zopefoundation/issue6
Browse files Browse the repository at this point in the history
100% coverage
  • Loading branch information
jamadden committed Sep 22, 2017
2 parents b5f6350 + aaae9b8 commit cc08084
Show file tree
Hide file tree
Showing 9 changed files with 510 additions and 184 deletions.
2 changes: 2 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
[run]
source = zope.tales
omit =
*/flycheck_*py

[report]
precision = 2
Expand Down
8 changes: 2 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,8 @@ python:
- 3.4
- 3.5
- 3.6
# Force a newer PyPy on the old 'precise' CI image
# in order to install 'cryptography' needed for coveralls
# After September 2017 this should be the default and the version
# pin can be removed.
- pypy-5.6.0
- pypy3.5-5.8.0
- pypy
- pypy3
install:
- pip install -U pip setuptools
- pip install -U coverage coveralls
Expand Down
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

- Drop support for ``python setup.py test``.

- Reach 100% test coverage and maintain it via tox.ini and Travis CI.

4.1.1 (2015-06-06)
==================

Expand Down
13 changes: 6 additions & 7 deletions src/zope/tales/expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ def __init__(self, path, traverser, engine):
compiledpath.append(tuple(currentpath))

first = compiledpath[0]
base = first[0]

if callable(first):
# check for initial function
Expand All @@ -101,6 +100,7 @@ def __init__(self, path, traverser, engine):
raise engine.getCompilerError()(
'Dynamic name specified in first subpath element')

base = first[0]
if base and not _valid_name(base):
raise engine.getCompilerError()(
'Invalid variable name "%s"' % element)
Expand Down Expand Up @@ -211,9 +211,7 @@ def _eval(self, econtext):
# __call__.
if getattr(ob, '__call__', _marker) is not _marker:
return ob()
if PY2 and isinstance(ob, types.ClassType):
return ob()
return ob
return ob() if PY2 and isinstance(ob, types.ClassType) else ob

def __call__(self, econtext):
if self._name == 'exists':
Expand All @@ -229,8 +227,8 @@ def __repr__(self):


_interp = re.compile(
r'\$(%(n)s)|\${(%(n)s(?:/[^}|]*)*(?:\|%(n)s(?:/[^}|]*)*)*)}'
% {'n': NAME_RE})
r'\$(%(n)s)|\${(%(n)s(?:/[^}|]*)*(?:\|%(n)s(?:/[^}|]*)*)*)}'
% {'n': NAME_RE})

@implementer(ITALESExpression)
class StringExpr(object):
Expand Down Expand Up @@ -318,9 +316,10 @@ def __repr__(self):
class LazyWrapper(DeferWrapper):
"""Wrapper for lazy: expression
"""
_result = _marker

def __init__(self, expr, econtext):
DeferWrapper.__init__(self, expr, econtext)
self._result = _marker

def __call__(self):
r = self._result
Expand Down
75 changes: 45 additions & 30 deletions src/zope/tales/tales.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,21 @@
from zope.interface import implementer
import six

from zope.interface import Interface
class ITALExpressionEngine(Interface):
pass
class ITALExpressionCompiler(Interface):
pass
class ITALExpressionErrorInfo(Interface):
pass

try:
from zope.tal.interfaces import ITALExpressionEngine
from zope.tal.interfaces import ITALExpressionCompiler
from zope.tal.interfaces import ITALExpressionErrorInfo
# Override with real, if present
from zope.tal.interfaces import (ITALExpressionEngine,
ITALExpressionCompiler,
ITALExpressionErrorInfo)
except ImportError:
from zope.interface import Interface
class ITALExpressionEngine(Interface):
pass
class ITALExpressionCompiler(Interface):
pass
class ITALExpressionErrorInfo(Interface):
pass
pass

from zope.tales.interfaces import ITALESIterator

Expand Down Expand Up @@ -107,7 +110,7 @@ def __init__(self, name, seq, context):
# but we can't know that without trying to get it. :(
self._last = False
try:
self._next = six.advance_iterator(i)
self._next = next(i)
except StopIteration:
self._done = True
else:
Expand Down Expand Up @@ -159,7 +162,7 @@ def __next__(self):
return False
self._item = v = self._next
try:
self._next = six.advance_iterator(self._iter)
self._next = next(self._iter)
except StopIteration:
self._done = True
self._last = True
Expand All @@ -175,6 +178,10 @@ def index(self):
>>> context = Context(ExpressionEngine(), {})
>>> it = Iterator('foo', ("apple", "pear", "orange"), context)
>>> it.index()
Traceback (most recent call last):
...
TypeError: No iteration position
>>> int(bool(it.next()))
1
>>> it.index()
Expand Down Expand Up @@ -280,6 +287,10 @@ def letter(self, base=ord('a'), radix=26):
>>> context = Context(ExpressionEngine(), {})
>>> it = Iterator('foo', ("apple", "pear", "orange"), context)
>>> it.letter()
Traceback (most recent call last):
...
TypeError: No iteration position
>>> it.next()
True
>>> it.letter()
Expand All @@ -300,7 +311,8 @@ def letter(self, base=ord('a'), radix=26):
while 1:
index, off = divmod(index, radix)
s = chr(base + off) + s
if not index: return s
if not index:
return s

def Letter(self):
"""Get the iterator position as an upper-case letter
Expand All @@ -323,9 +335,9 @@ def Letter(self):
return self.letter(base=ord('A'))

def Roman(self, rnvalues=(
(1000,'M'),(900,'CM'),(500,'D'),(400,'CD'),
(100,'C'),(90,'XC'),(50,'L'),(40,'XL'),
(10,'X'),(9,'IX'),(5,'V'),(4,'IV'),(1,'I')) ):
(1000, 'M'), (900, 'CM'), (500, 'D'), (400, 'CD'),
(100, 'C'), (90, 'XC'), (50, 'L'), (40, 'XL'),
(10, 'X'), (9, 'IX'), (5, 'V'), (4, 'IV'), (1, 'I'))):
"""Get the iterator position as an upper-case roman numeral
>>> context = Context(ExpressionEngine(), {})
Expand Down Expand Up @@ -431,6 +443,10 @@ def item(self):
>>> context = Context(ExpressionEngine(), {})
>>> it = Iterator('foo', ("apple", "pear", "orange"), context)
>>> it.item()
Traceback (most recent call last):
...
TypeError: No iteration position
>>> it.next()
True
>>> it.item()
Expand Down Expand Up @@ -495,13 +511,14 @@ def length(self):
class ErrorInfo(object):
"""Information about an exception passed to an on-error handler."""

value = None

def __init__(self, err, position=(None, None)):
self.type = err
if isinstance(err, Exception):
self.type = err.__class__
self.value = err
else:
self.type = err
self.value = None

self.lineno = position[0]
self.offset = position[1]

Expand Down Expand Up @@ -691,12 +708,15 @@ def evaluate(self, expression):
if isinstance(expression, str):
expression = self._engine.compile(expression)
__traceback_supplement__ = (
TALESTracebackSupplement, self, expression)
TALESTracebackSupplement, self, expression)
return expression(self)

evaluateValue = evaluate

def evaluateBoolean(self, expr):
# "not not", while frowned upon by linters might be faster
# than bool() because it avoids a builtin lookup. Plus it can't be
# reassigned.
return not not self.evaluate(expr)

def evaluateText(self, expr):
Expand All @@ -708,13 +728,9 @@ def evaluateText(self, expr):
return text
return six.text_type(text)

def evaluateStructure(self, expr):
return self.evaluate(expr)
evaluateStructure = evaluate

def evaluateMacro(self, expr):
# TODO: Should return None or a macro definition
return self.evaluate(expr)
# TODO: Should return None or a macro definition
evaluateMacro = evaluate

def createErrorInfo(self, err, position):
Expand Down Expand Up @@ -749,11 +765,10 @@ def getInfo(self, as_html=0):
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 ')
else:
from cgi import escape
return '<b>Names:</b><pre>%s</pre>' % (escape(s))
return None

from cgi import escape
return '<b>Names:</b><pre>%s</pre>' % (escape(s))
Loading

0 comments on commit cc08084

Please sign in to comment.