summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Howitz <mh@gocept.com>2021-05-27 14:20:23 +0200
committerMichael Howitz <mh@gocept.com>2021-05-28 08:03:35 +0200
commit0f8a8f11cb74b988e947fe20034a76ed1bc7f27e (patch)
treea267c937426eb4c832f9914b26136a649042eab0
parent23529db8a317f3e3cf209349f154eccccbb37e7b (diff)
downloadzope-tal-0f8a8f11cb74b988e947fe20034a76ed1bc7f27e.tar.gz
Lint the code.
Add support for Python 3.8 and 3.9. Drop support for Python 3.4.
-rw-r--r--CHANGES.rst4
-rw-r--r--setup.py10
-rw-r--r--src/zope/__init__.py2
-rw-r--r--src/zope/tal/driver.py58
-rw-r--r--src/zope/tal/dummyengine.py43
-rw-r--r--src/zope/tal/htmltalparser.py19
-rw-r--r--src/zope/tal/interfaces.py7
-rw-r--r--src/zope/tal/runtest.py39
-rw-r--r--src/zope/tal/taldefs.py26
-rw-r--r--src/zope/tal/talgenerator.py40
-rw-r--r--src/zope/tal/talgettext.py13
-rw-r--r--src/zope/tal/talinterpreter.py67
-rw-r--r--src/zope/tal/talparser.py10
-rw-r--r--src/zope/tal/tests/markbench.py44
-rw-r--r--src/zope/tal/tests/run.py4
-rw-r--r--src/zope/tal/tests/test_files.py5
-rw-r--r--src/zope/tal/tests/test_htmltalparser.py1130
-rw-r--r--src/zope/tal/tests/test_sourcepos.py1
-rw-r--r--src/zope/tal/tests/test_talgettext.py1
-rw-r--r--src/zope/tal/tests/test_talinterpreter.py76
-rw-r--r--src/zope/tal/tests/test_xmlparser.py46
-rw-r--r--src/zope/tal/tests/utils.py14
-rw-r--r--src/zope/tal/timer.py4
-rw-r--r--src/zope/tal/translationcontext.py1
-rw-r--r--src/zope/tal/xmlparser.py4
25 files changed, 898 insertions, 770 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index 89411df..b13aa07 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -7,6 +7,10 @@
- Avoid traceback reference cycle in ``TALInterpreter.do_onError_tal``.
+- Add support for Python 3.8 and 3.9.
+
+- Drop support for Python 3.4.
+
4.4 (2018-10-05)
================
diff --git a/setup.py b/setup.py
index 537a1e5..68a7f47 100644
--- a/setup.py
+++ b/setup.py
@@ -24,10 +24,12 @@ from setuptools import setup, find_packages
here = os.path.dirname(__file__)
+
def read(*rnames):
with open(os.path.join(here, *rnames)) as f:
return f.read()
+
def alltests():
# use the zope.testrunner machinery to find all the
# test suites we've put under ourselves
@@ -42,6 +44,7 @@ def alltests():
suites = list(find_suites(options))
return TestSuite(suites)
+
TESTS_REQUIRE = [
'zope.testing',
'zope.testrunner',
@@ -67,10 +70,11 @@ setup(name='zope.tal',
'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 :: 3.7',
+ 'Programming Language :: Python :: 3.8',
+ 'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'Natural Language :: English',
@@ -90,7 +94,7 @@ setup(name='zope.tal',
'repoze.sphinx.autointerface',
],
},
- test_suite="__main__.alltests", # to support "setup.py test"
+ test_suite="__main__.alltests", # to support "setup.py test"
tests_require=TESTS_REQUIRE,
install_requires=[
'setuptools',
@@ -99,4 +103,4 @@ setup(name='zope.tal',
],
include_package_data=True,
zip_safe=False,
-)
+ )
diff --git a/src/zope/__init__.py b/src/zope/__init__.py
index 2cdb0e4..656dc0f 100644
--- a/src/zope/__init__.py
+++ b/src/zope/__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/zope/tal/driver.py b/src/zope/tal/driver.py
index e139bb2..c64c602 100644
--- a/src/zope/tal/driver.py
+++ b/src/zope/tal/driver.py
@@ -54,9 +54,9 @@ class TestEngine(DummyEngine):
def evaluatePathOrVar(self, expr):
if expr == 'here/currentTime':
- return {'hours' : 6,
+ return {'hours': 6,
'minutes': 59,
- 'ampm' : 'PM',
+ 'ampm': 'PM',
}
elif expr == 'context/@@object_name':
return '7'
@@ -80,28 +80,36 @@ ENGINES = {'test23.html': TestEngine,
OPTIONS = [
- optparse.make_option('-H', '--html',
- action='store_const', const='html', dest='mode',
- help='explicitly choose HTML input (default: use file extension)'),
- optparse.make_option('-x', '--xml',
- action='store_const', const='xml', dest='mode',
- help='explicitly choose XML input (default: use file extension)'),
+ optparse.make_option(
+ '-H', '--html',
+ action='store_const', const='html', dest='mode',
+ help='explicitly choose HTML input (default: use file extension)'),
+ optparse.make_option(
+ '-x', '--xml',
+ action='store_const', const='xml', dest='mode',
+ help='explicitly choose XML input (default: use file extension)'),
optparse.make_option('-l', '--lenient', action='store_true',
- help='lenient structure insertion'),
- # aka don't validate HTML/XML inserted by
- # tal:content="structure expr"
- optparse.make_option('-m', '--macro-only', action='store_true',
- help='macro expansion only'),
- optparse.make_option('-s', '--show-code', action='store_true',
- help='print intermediate opcodes only'),
- optparse.make_option('-t', '--show-tal', action='store_true',
- help='leave TAL/METAL attributes in output'),
- optparse.make_option('-i', '--show-i18n', action='store_true',
- help='leave I18N substitution string un-interpolated'),
- optparse.make_option('-a', '--annotate', action='store_true',
- help='enable source annotations'),
+ help='lenient structure insertion'),
+ # aka don't validate HTML/XML inserted by
+ # tal:content="structure expr"
+ optparse.make_option(
+ '-m', '--macro-only', action='store_true',
+ help='macro expansion only'),
+ optparse.make_option(
+ '-s', '--show-code', action='store_true',
+ help='print intermediate opcodes only'),
+ optparse.make_option(
+ '-t', '--show-tal', action='store_true',
+ help='leave TAL/METAL attributes in output'),
+ optparse.make_option(
+ '-i', '--show-i18n', action='store_true',
+ help='leave I18N substitution string un-interpolated'),
+ optparse.make_option(
+ '-a', '--annotate', action='store_true',
+ help='enable source annotations'),
]
+
def main(values=None):
parser = optparse.OptionParser('usage: %prog [options] testfile',
description=__doc__,
@@ -130,6 +138,7 @@ def main(values=None):
i18nInterpolate=not opts.show_i18n,
sourceAnnotations=opts.annotate)
+
def interpretit(it, engine=None, stream=None, tal=1, showtal=-1,
strictinsert=1, i18nInterpolate=1, sourceAnnotations=0):
from zope.tal.talinterpreter import TALInterpreter
@@ -142,6 +151,7 @@ def interpretit(it, engine=None, stream=None, tal=1, showtal=-1,
i18nInterpolate=i18nInterpolate,
sourceAnnotations=sourceAnnotations)()
+
def compilefile(file, mode=None):
assert mode in ("html", "xml", None)
if mode is None:
@@ -153,13 +163,13 @@ def compilefile(file, mode=None):
# make sure we can find the file
prefix = os.path.dirname(os.path.abspath(__file__)) + os.path.sep
if (not os.path.exists(file)
- and os.path.exists(os.path.join(prefix, file))):
+ and os.path.exists(os.path.join(prefix, file))):
file = os.path.join(prefix, file)
# normalize filenames for test output
filename = os.path.abspath(file)
if filename.startswith(prefix):
filename = filename[len(prefix):]
- filename = filename.replace(os.sep, '/') # test files expect slashes
+ filename = filename.replace(os.sep, '/') # test files expect slashes
# parse
from zope.tal.talgenerator import TALGenerator
if mode == "html":
@@ -171,9 +181,11 @@ def compilefile(file, mode=None):
p.parseFile(file)
return p.getCode()
+
def showit(it):
from pprint import pprint
pprint(it)
+
if __name__ == "__main__":
main()
diff --git a/src/zope/tal/dummyengine.py b/src/zope/tal/dummyengine.py
index 2987c2d..cfc71ea 100644
--- a/src/zope/tal/dummyengine.py
+++ b/src/zope/tal/dummyengine.py
@@ -31,13 +31,14 @@ from zope.i18nmessageid import Message
try:
unicode
except NameError:
- unicode = str # Python 3.x
+ unicode = str # Python 3.x
Default = object()
name_match = re.compile(r"(?s)(%s):(.*)\Z" % NAME_RE).match
+
class CompilerError(Exception):
pass
@@ -48,7 +49,6 @@ class DummyEngine(object):
position = None
source_file = None
-
def __init__(self, macros=None):
if macros is None:
macros = {}
@@ -119,7 +119,7 @@ class DummyEngine(object):
if type == "python":
try:
return eval(expr, self.globals, self.locals)
- except:
+ except BaseException:
raise TALExpressionError("evaluation error in %s" % repr(expr))
if type == "position":
# Insert the current source file name, line number,
@@ -129,7 +129,9 @@ class DummyEngine(object):
else:
lineno, offset = None, None
return '%s (%s,%s)' % (self.source_file, lineno, offset)
- raise TALExpressionError("unrecognized expression: " + repr(expression))
+ raise TALExpressionError(
+ "unrecognized expression: " +
+ repr(expression))
# implementation; can be overridden
def evaluatePathOrVar(self, expr):
@@ -193,7 +195,7 @@ class DummyEngine(object):
else:
# Up to last slash is the filename
fileName = macroName[:i]
- localName = macroName[i+1:]
+ localName = macroName[i + 1:]
return fileName, localName
def setRepeat(self, name, expr):
@@ -231,7 +233,7 @@ class DummyEngine(object):
# Prepare code.
lines = code.split('\n')
- lines = [l for l in lines if l.strip() != '']
+ lines = [line for line in lines if line.strip() != '']
code = '\n'.join(lines)
# This saves us from all indentation issues :)
if code.startswith(' ') or code.startswith('\t'):
@@ -253,6 +255,7 @@ class DummyEngine(object):
return result.getvalue()
+
class Iterator(object):
def __init__(self, name, seq, engine):
@@ -267,23 +270,23 @@ class Iterator(object):
item = self.seq[i]
except IndexError:
return 0
- self.nextIndex = i+1
+ self.nextIndex = i + 1
self.engine.setLocal(self.name, item)
return 1
- next = __next__ # Python 2 compatibility
+ next = __next__ # Python 2 compatibility
class DummyTranslationDomain(object):
domain = ''
- msgids = {}
+ msgids = {}
def appendMsgid(self, domain, data):
if domain not in self.msgids:
self.msgids[domain] = []
- self.msgids[domain].append(data)
-
+ self.msgids[domain].append(data)
+
def getMsgids(self, domain):
return self.msgids[domain]
@@ -309,8 +312,8 @@ class DummyTranslationDomain(object):
domain = msgid.domain
mapping = msgid.mapping
default = msgid.default
- if default is None: # Message doesn't substitute itself for
- default = msgid # missing default
+ if default is None: # Message doesn't substitute itself for
+ default = msgid # missing default
# simulate an unknown msgid by returning None
if msgid == "don't translate me":
@@ -322,23 +325,23 @@ class DummyTranslationDomain(object):
text = msgid.upper()
self.appendMsgid(domain, (msgid, mapping))
-
+
def repl(m):
return unicode(mapping[m.group(m.lastindex).lower()])
cre = re.compile(r'\$(?:([_A-Za-z][-\w]*)|\{([_A-Za-z][-\w]*)\})')
return cre.sub(repl, text)
+
class MultipleDomainsDummyEngine(DummyEngine):
-
+
def translate(self, msgid, domain=None, mapping=None, default=None):
-
+
if isinstance(msgid, Message):
domain = msgid.domain
-
- if domain == 'a_very_explicit_domain_setup_by_template_developer_that_wont_be_taken_into_account_by_the_ZPT_engine':
+
+ if domain == 'a_very_explicit_domain_setup_by_template_developer_that_wont_be_taken_into_account_by_the_ZPT_engine': # noqa: E501 line too long
domain = 'lower'
-
+
self.translationDomain.domain = domain
return self.translationDomain.translate(
msgid, mapping, default=default)
-
diff --git a/src/zope/tal/htmltalparser.py b/src/zope/tal/htmltalparser.py
index 1761bc7..fe4b6ca 100644
--- a/src/zope/tal/htmltalparser.py
+++ b/src/zope/tal/htmltalparser.py
@@ -60,7 +60,7 @@ BOOLEAN_HTML_ATTRS = frozenset([
"compact", "nowrap", "ismap", "declare", "noshade", "checked",
"disabled", "readonly", "multiple", "selected", "noresize",
"defer"
- ])
+])
#: List of HTML tags with an empty content model; these are
#: rendered in minimized form, e.g. ``<img />``.
@@ -68,13 +68,13 @@ BOOLEAN_HTML_ATTRS = frozenset([
EMPTY_HTML_TAGS = frozenset([
"base", "meta", "link", "hr", "br", "param", "img", "area",
"input", "col", "basefont", "isindex", "frame",
- ])
+])
#: List of HTML elements that close open paragraph-level elements
#: and are themselves paragraph-level.
PARA_LEVEL_HTML_TAGS = frozenset([
"h1", "h2", "h3", "h4", "h5", "h6", "p",
- ])
+])
#: Tags that automatically close other tags.
BLOCK_CLOSING_TAG_MAP = {
@@ -84,13 +84,13 @@ BLOCK_CLOSING_TAG_MAP = {
"li": frozenset(["li"]),
"dd": frozenset(["dd", "dt"]),
"dt": frozenset(["dd", "dt"]),
- }
+}
#: List of HTML tags that denote larger sections than paragraphs.
BLOCK_LEVEL_HTML_TAGS = frozenset([
"blockquote", "table", "tr", "th", "td", "thead", "tfoot", "tbody",
"noframe", "ul", "ol", "li", "dl", "dt", "dd", "div",
- ])
+])
#: Section level HTML tags
SECTION_LEVEL_HTML_TAGS = PARA_LEVEL_HTML_TAGS.union(BLOCK_LEVEL_HTML_TAGS)
@@ -114,6 +114,7 @@ class NestingError(HTMLParseError):
msg = 'No tags are open to match </%s>' % endtag
HTMLParseError.__init__(self, msg, position)
+
class EmptyTagError(NestingError):
"""Exception raised when empty elements have an end tag."""
@@ -122,6 +123,7 @@ class EmptyTagError(NestingError):
msg = 'Close tag </%s> should be removed' % tag
HTMLParseError.__init__(self, msg, position)
+
class OpenTagError(NestingError):
"""Exception raised when a tag is not allowed in another tag."""
@@ -130,6 +132,7 @@ class OpenTagError(NestingError):
msg = 'Tag <%s> is not allowed in <%s>' % (tag, tagstack[-1])
HTMLParseError.__init__(self, msg, position)
+
class HTMLTALParser(HTMLParser):
"""
Parser for HTML.
@@ -188,7 +191,7 @@ class HTMLTALParser(HTMLParser):
self.close_para_tags(tag)
self.scan_xmlns(attrs)
tag, attrlist, taldict, metaldict, i18ndict \
- = self.process_ns(tag, attrs)
+ = self.process_ns(tag, attrs)
if tag in EMPTY_HTML_TAGS and "content" in taldict:
raise TALError(
"empty HTML tags cannot use tal:content: %s" % repr(tag),
@@ -209,7 +212,7 @@ class HTMLTALParser(HTMLParser):
self.close_para_tags(tag)
self.scan_xmlns(attrs)
tag, attrlist, taldict, metaldict, i18ndict \
- = self.process_ns(tag, attrs)
+ = self.process_ns(tag, attrs)
if "content" in taldict:
if tag in EMPTY_HTML_TAGS:
raise TALError(
@@ -345,7 +348,7 @@ class HTMLTALParser(HTMLParser):
for item in attrs:
key, value = item
key, keybase, keyns = self.fixname(key)
- ns = keyns or namens # default to tag namespace
+ ns = keyns or namens # default to tag namespace
if ns and ns != 'unknown':
item = (key, value, ns)
if ns == 'tal':
diff --git a/src/zope/tal/interfaces.py b/src/zope/tal/interfaces.py
index f6c1aec..bd6286a 100644
--- a/src/zope/tal/interfaces.py
+++ b/src/zope/tal/interfaces.py
@@ -43,9 +43,9 @@ class ITALExpressionCompiler(Interface):
*expression* is the source text of the expression.
The return value may be passed to the various ``evaluate*()``
- methods of the :class:`ITALExpressionEngine` interface. No compatibility is
- required for the values of the compiled expression between
- different :class:`ITALExpressionEngine` implementations.
+ methods of the :class:`ITALExpressionEngine` interface. No
+ compatibility is required for the values of the compiled expression
+ between different :class:`ITALExpressionEngine` implementations.
"""
def getContext(namespace):
@@ -54,6 +54,7 @@ class ITALExpressionCompiler(Interface):
The given *namespace* provides the initial top-level names.
"""
+
class ITALExpressionEngine(Interface):
"""Render-time interface provided by a TAL expression implementation.
diff --git a/src/zope/tal/runtest.py b/src/zope/tal/runtest.py
index 518a1b0..df9d1c7 100644
--- a/src/zope/tal/runtest.py
+++ b/src/zope/tal/runtest.py
@@ -37,24 +37,31 @@ except ImportError:
import zope.tal.driver
import zope.tal.tests.utils
+
def showdiff(a, b, out):
print(''.join(difflib.ndiff(a, b)), file=out)
+
def main(argv=None, out=sys.stdout):
parser = optparse.OptionParser('usage: %prog [options] [testfile ...]',
description=__doc__)
parser.add_option('-q', '--quiet', action='store_true',
- help="less verbose output")
+ help="less verbose output")
internal_options = optparse.OptionGroup(parser, 'Internal options')
- internal_options.add_option('-Q', '--very-quiet',
- action='store_true', dest='unittesting',
- help="no output on success, only diff/traceback on failure")
+ internal_options.add_option(
+ '-Q',
+ '--very-quiet',
+ action='store_true',
+ dest='unittesting',
+ help="no output on success, only diff/traceback on failure")
internal_options.add_option('-N', '--normalize-newlines',
- action='store_true', dest='normalize_newlines',
- help="ignore differences between CRLF and LF")
+ action='store_true', dest='normalize_newlines',
+ help="ignore differences between CRLF and LF")
parser.add_option_group(internal_options)
- driver_options = optparse.OptionGroup(parser, 'Driver options',
- "(for debugging only; supplying these *will* cause test failures)")
+ driver_options = optparse.OptionGroup(
+ parser,
+ 'Driver options',
+ "(for debugging only; supplying these *will* cause test failures)")
for option in zope.tal.driver.OPTIONS:
driver_options.add_option(option)
parser.add_option_group(driver_options)
@@ -66,10 +73,8 @@ def main(argv=None, out=sys.stdout):
if zope.tal.tests.utils.skipxml:
xmlargs = []
else:
- xmlargs = glob.glob(prefix + "xml")
- xmlargs.sort()
- htmlargs = glob.glob(prefix + "html")
- htmlargs.sort()
+ xmlargs = sorted(glob.glob(prefix + "xml"))
+ htmlargs = sorted(glob.glob(prefix + "html"))
args = xmlargs + htmlargs
if not args:
sys.stderr.write("No tests found -- please supply filenames\n")
@@ -97,7 +102,7 @@ def main(argv=None, out=sys.stdout):
sys.stdout, sys.argv = save
except SystemExit:
raise
- except:
+ except BaseException:
errors = 1
if opts.quiet:
print(sys.exc_info()[0].__name__, file=out)
@@ -141,9 +146,9 @@ def main(argv=None, out=sys.stdout):
# also have \r\n's going through the TAL engine and showing
# up both in actual and expected lists. Except for source
# annotation lines added by TAL, which always use just \n.
- actual = [l.replace('\r\n', '\n') for l in actual]
+ actual = [line.replace('\r\n', '\n') for line in actual]
if expected is not None:
- expected = [l.replace('\r\n', '\n') for l in expected]
+ expected = [line.replace('\r\n', '\n') for line in expected]
if actual == expected:
if not opts.unittesting:
print("OK", file=out)
@@ -161,14 +166,16 @@ def main(argv=None, out=sys.stdout):
else:
sys.exit(1)
+
def readlines(f):
L = []
- while 1:
+ while True:
line = f.readline()
if not line:
break
L.append(line)
return L
+
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
diff --git a/src/zope/tal/taldefs.py b/src/zope/tal/taldefs.py
index 539e541..61d20d1 100644
--- a/src/zope/tal/taldefs.py
+++ b/src/zope/tal/taldefs.py
@@ -43,7 +43,7 @@ KNOWN_METAL_ATTRIBUTES = frozenset([
"use-macro",
"define-slot",
"fill-slot",
- ])
+])
#: Known TAL attributes
KNOWN_TAL_ATTRIBUTES = frozenset([
@@ -58,7 +58,7 @@ KNOWN_TAL_ATTRIBUTES = frozenset([
"script",
"tal tag", # a pseudo attribute that holds the namespace of elements
# like <tal:x>, <metal:y>, <i18n:z>
- ])
+])
#: Known I18N attributes
KNOWN_I18N_ATTRIBUTES = frozenset([
@@ -71,7 +71,8 @@ KNOWN_I18N_ATTRIBUTES = frozenset([
"name",
"ignore",
"ignore-attributes",
- ])
+])
+
class TALError(Exception):
"""
@@ -99,12 +100,15 @@ class TALError(Exception):
result = result + ', in file %s' % self.filename
return result
+
class METALError(TALError):
"""An error parsing on running METAL macros."""
+
class TALExpressionError(TALError):
"""An error parsing or running a TAL expression."""
+
class I18NError(TALError):
"""An error parsing a I18N expression."""
@@ -112,7 +116,8 @@ class I18NError(TALError):
@implementer(ITALExpressionErrorInfo)
class ErrorInfo(object):
"""
- Default implementation of :class:`zope.tal.interfaces.ITALExpressionErrorInfo`.
+ Default implementation of
+ :class:`zope.tal.interfaces.ITALExpressionErrorInfo`.
"""
def __init__(self, err, position=(None, None)):
@@ -129,6 +134,7 @@ class ErrorInfo(object):
_attr_re = re.compile(r"\s*([^\s]+)\s+([^\s].*)\Z", re.S)
_subst_re = re.compile(r"\s*(?:(text|structure)\s+)?(.*)\Z", re.S)
+
def parseAttributeReplacements(arg, xml):
attr_dict = {}
for part in splitParts(arg):
@@ -143,6 +149,7 @@ def parseAttributeReplacements(arg, xml):
attr_dict[name] = expr
return attr_dict
+
def parseSubstitution(arg, position=(None, None)):
m = _subst_re.match(arg)
if not m:
@@ -152,6 +159,7 @@ def parseSubstitution(arg, position=(None, None)):
key = "text"
return key, expr
+
def splitParts(arg):
# Break in pieces at undoubled semicolons and
# change double semicolons to singles:
@@ -159,13 +167,15 @@ def splitParts(arg):
parts = arg.split(';')
parts = [p.replace("\0", ";") for p in parts]
if len(parts) > 1 and not parts[-1].strip():
- del parts[-1] # It ended in a semicolon
+ del parts[-1] # It ended in a semicolon
return parts
+
def isCurrentVersion(program):
version = getProgramVersion(program)
return version == TAL_VERSION
+
def isinstance_(ob, kind):
# Proxy-friendly and faster isinstance_ check for new-style objects
try:
@@ -183,6 +193,7 @@ def getProgramMode(program):
return mode
return None
+
def getProgramVersion(program):
if (len(program) >= 2
and isinstance_(program[0], tuple) and len(program[0]) == 2):
@@ -191,12 +202,14 @@ def getProgramVersion(program):
return version
return None
+
_ent1_re = re.compile('&(?![A-Z#])', re.I)
_entch_re = re.compile('&([A-Z][A-Z0-9]*)(?![A-Z0-9;])', re.I)
_entn1_re = re.compile('&#(?![0-9X])', re.I)
_entnx_re = re.compile('&(#X[A-F0-9]*)(?![A-F0-9;])', re.I)
_entnd_re = re.compile('&(#[0-9][0-9]*)(?![0-9;])')
+
def attrEscape(s):
"""Replace special characters '&<>' by character entities,
except when '&' already begins a syntactically valid entity."""
@@ -210,8 +223,9 @@ def attrEscape(s):
s = s.replace('"', '&quot;')
return s
+
def quote(s):
- s = s.replace("&", "&amp;") # Must be done first!
+ s = s.replace("&", "&amp;") # Must be done first!
s = s.replace("<", "&lt;")
s = s.replace(">", "&gt;")
s = s.replace('"', "&quot;")
diff --git a/src/zope/tal/talgenerator.py b/src/zope/tal/talgenerator.py
index ce7470c..a7adf3d 100644
--- a/src/zope/tal/talgenerator.py
+++ b/src/zope/tal/talgenerator.py
@@ -32,11 +32,12 @@ from zope.tal.translationcontext import TranslationContext, DEFAULT_DOMAIN
try:
xrange
except NameError:
- xrange = range # Python 3.x
+ xrange = range # Python 3.x
_name_rx = re.compile(NAME_RE)
+
class TALGenerator(object):
"""
Generate intermediate code.
@@ -89,7 +90,7 @@ class TALGenerator(object):
output = []
collect = []
cursor = 0
- for cursor in xrange(len(program)+1):
+ for cursor in xrange(len(program) + 1):
try:
item = program[cursor]
except IndexError:
@@ -128,7 +129,7 @@ class TALGenerator(object):
output.append(("rawtextColumn", (text, i)))
else:
output.append(("rawtextOffset", (text, len(text))))
- if opcode != None:
+ if opcode is not None:
output.append(self.optimizeArgsList(item))
collect = []
return self.optimizeCommonTriple(output)
@@ -257,8 +258,8 @@ class TALGenerator(object):
self.emit("endTag", name)
def emitOptTag(self, name, optTag, isend):
- program = self.popProgram() #block
- start = self.popProgram() #start tag
+ program = self.popProgram() # block
+ start = self.popProgram() # start tag
if (isend or not program) and self.xml:
# Minimize empty element
start[-1] = ("startEndTag",) + start[-1][1:]
@@ -367,8 +368,9 @@ class TALGenerator(object):
program = self.popProgram()
macroName = macroName.strip()
if macroName in self.macros:
- raise METALError("duplicate macro definition: %s" % repr(macroName),
- self.position)
+ raise METALError(
+ "duplicate macro definition: %s" %
+ repr(macroName), self.position)
if not re.match('%s$' % NAME_RE, macroName):
raise METALError("invalid macro name: %s" % repr(macroName),
self.position)
@@ -422,8 +424,8 @@ class TALGenerator(object):
if not re.match(r"\A\s*\Z", text):
break
collect.append(text)
- i = i-1
- del self.program[i+1:]
+ i = i - 1
+ del self.program[i + 1:]
if i >= 0 and self.program[i][0] == "rawtext":
text = self.program[i][1]
m = re.search(r"\s+\Z", text)
@@ -437,7 +439,7 @@ class TALGenerator(object):
collect = []
i = len(self.program)
while i > 0:
- i = i-1
+ i = i - 1
item = self.program[i]
if item[0] != "rawtext":
break
@@ -629,9 +631,9 @@ class TALGenerator(object):
domain = i18ndict.get("domain") or self.i18nContext.domain
source = i18ndict.get("source") or self.i18nContext.source
target = i18ndict.get("target") or self.i18nContext.target
- if ( domain != DEFAULT_DOMAIN
- or source is not None
- or target is not None):
+ if (domain != DEFAULT_DOMAIN
+ or source is not None
+ or target is not None):
self.i18nContext = TranslationContext(self.i18nContext,
domain=domain,
source=source,
@@ -648,13 +650,13 @@ class TALGenerator(object):
self.emit("beginScope", dict)
todo["scope"] = 1
if onError:
- self.pushProgram() # handler
+ self.pushProgram() # handler
if TALtag:
- self.pushProgram() # start
- self.emitStartTag(name, list(attrlist)) # Must copy attrlist!
+ self.pushProgram() # start
+ self.emitStartTag(name, list(attrlist)) # Must copy attrlist!
if TALtag:
- self.pushProgram() # start
- self.pushProgram() # block
+ self.pushProgram() # start
+ self.pushProgram() # block
todo["onError"] = onError
if define:
self.emitDefines(define)
@@ -863,6 +865,7 @@ def _parseI18nAttributes(i18nattrs, position, xml):
d[attr] = msgid
return d
+
def test():
t = TALGenerator()
t.pushProgram()
@@ -870,5 +873,6 @@ def test():
p = t.popProgram()
t.emit("foo", p)
+
if __name__ == "__main__":
test()
diff --git a/src/zope/tal/talgettext.py b/src/zope/tal/talgettext.py
index a4e3917..bc90439 100644
--- a/src/zope/tal/talgettext.py
+++ b/src/zope/tal/talgettext.py
@@ -28,6 +28,9 @@ Options:
found.
"""
+# XXX this module seems to be unused, it has NameErrors and is not Python 3
+# compatible.
+
from __future__ import print_function
import sys
@@ -112,10 +115,10 @@ class POEngine(DummyEngine):
return 'XXX'
def evaluateSequence(self, expr):
- return (0,) # dummy
+ return (0,) # dummy
def evaluateBoolean(self, expr):
- return True # dummy
+ return True # dummy
def translate(self, msgid, domain=None, mapping=None, default=None,
# Position is not part of the ITALExpressionEngine
@@ -139,7 +142,7 @@ class POEngine(DummyEngine):
idx = msgids.index(msgid)
existing_msgid = msgids[idx]
if msgid.default != existing_msgid.default:
- references = '\n'.join([location[0]+':'+str(location[1])
+ references = '\n'.join([location[0] + ':' + str(location[1])
for location in domain[msgid]])
# Note: a lot of encode calls here are needed so
# Python 3 does not break.
@@ -161,7 +164,7 @@ class UpdatePOEngine(POEngine):
"""A slightly-less braindead POEngine which supports loading an existing
.po file first."""
- def __init__ (self, macros=None, filename=None):
+ def __init__(self, macros=None, filename=None):
POEngine.__init__(self, macros)
self._filename = filename
@@ -301,7 +304,7 @@ def main():
program, macros = p.getCode()
POTALInterpreter(program, macros, engine, stream=Devnull(),
metal=False)()
- except: # Hee hee, I love bare excepts!
+ except BaseException: # Hee hee, I love bare excepts!
print('There was an error processing', filename)
traceback.print_exc()
diff --git a/src/zope/tal/talinterpreter.py b/src/zope/tal/talinterpreter.py
index ce2837e..7e442d3 100644
--- a/src/zope/tal/talinterpreter.py
+++ b/src/zope/tal/talinterpreter.py
@@ -27,7 +27,7 @@ from zope.tal.translationcontext import TranslationContext
try:
unicode
except NameError:
- unicode = str # Python 3.x
+ unicode = str # Python 3.x
_BLANK = u''
@@ -51,6 +51,7 @@ BOOLEAN_HTML_ATTRS = frozenset([
_nulljoin = ''.join
_spacejoin = ' '.join
+
def normalize(text):
# Now we need to normalize the whitespace in implicit message ids and
# implicit $name substitution values by stripping leading and trailing
@@ -90,7 +91,6 @@ class AltTALGenerator(TALGenerator):
return TALGenerator.replaceAttrs(self, attrlist, repldict)
-
class MacroStackItem(list):
# This is a `list` subclass for backward compability.
"""Stack entry for the TALInterpreter.macroStack.
@@ -116,24 +116,25 @@ class TALInterpreter(object):
"""TAL interpreter.
Some notes on source annotations. They are HTML/XML comments added to the
- output whenever ``sourceFile`` is changed by a ``setSourceFile`` bytecode. Source
- annotations are disabled by default, but you can turn them on by passing a
- ``sourceAnnotations`` argument to the constructor. You can change the format
- of the annotations by overriding formatSourceAnnotation in a subclass.
+ output whenever ``sourceFile`` is changed by a ``setSourceFile`` bytecode.
+ Source annotations are disabled by default, but you can turn them on by
+ passing a ``sourceAnnotations`` argument to the constructor. You can
+ change the format of the annotations by overriding formatSourceAnnotation
+ in a subclass.
The output of the annotation is delayed until some actual text is output
for two reasons:
- 1. ``setPosition`` bytecode follows ``setSourceFile``, and we need position
- information to output the line number.
+ 1. ``setPosition`` bytecode follows ``setSourceFile``, and we need
+ position information to output the line number.
2. Comments are not allowed in XML documents before the ``<?xml?>``
declaration.
For performance reasons (TODO: premature optimization?) instead of checking
the value of ``_pending_source_annotation`` on every write to the output
stream, the ``_stream_write`` attribute is changed to point to
- ``_annotated_stream_write`` method whenever ``_pending_source_annotation`` is
- set to True, and to _stream.write when it is False. The following
+ ``_annotated_stream_write`` method whenever ``_pending_source_annotation``
+ is set to True, and to _stream.write when it is False. The following
invariant always holds::
if self._pending_source_annotation:
@@ -157,13 +158,14 @@ class TALInterpreter(object):
Optional arguments:
:keyword stream: output stream (defaults to sys.stdout).
- :keyword bool debug: enable debugging output to sys.stderr (off by default).
- :keyword int wrap: try to wrap attributes on opening tags to this number of
- column (default: 1023).
+ :keyword bool debug: enable debugging output to sys.stderr (off by
+ default).
+ :keyword int wrap: try to wrap attributes on opening tags to this
+ number of column (default: 1023).
:keyword bool metal: enable METAL macro processing (on by default).
:keyword bool tal: enable TAL processing (on by default).
- :keyword int showtal: do not strip away TAL directives. A special value of
- -1 (which is the default setting) enables showtal when TAL
+ :keyword int showtal: do not strip away TAL directives. A special
+ value of -1 (which is the default setting) enables showtal when TAL
processing is disabled, and disables showtal when TAL processing is
enabled. Note that you must use 0, 1, or -1; true boolean values
are not supported (for historical reasons).
@@ -172,12 +174,12 @@ class TALInterpreter(object):
Note that Zope turns this value off by default.
:keyword int stackLimit: set macro nesting limit (default: 100).
:keyword bool i18nInterpolate: enable i18n translations (default: on).
- :keyword bool sourceAnnotations: enable source annotations with HTML comments
- (default: off).
+ :keyword bool sourceAnnotations: enable source annotations with HTML
+ comments (default: off).
"""
self.program = program
self.macros = macros
- self.engine = engine # Execution engine (aka context)
+ self.engine = engine # Execution engine (aka context)
self.Default = engine.getDefault()
self._pending_source_annotation = False
self._currentTag = ""
@@ -295,8 +297,8 @@ class TALInterpreter(object):
# Do not preprend comments in front of the <?xml?> declaration.
end_of_doctype = s.find('?>', idx)
if end_of_doctype > idx:
- self.stream.write(s[:end_of_doctype+2])
- s = s[end_of_doctype+2:]
+ self.stream.write(s[:end_of_doctype + 2])
+ s = s[end_of_doctype + 2:]
# continue
else:
self.stream.write(s)
@@ -333,7 +335,7 @@ class TALInterpreter(object):
try:
if self.debug:
for (opcode, args) in program:
- s = "%sdo_%s(%s)\n" % (" "*self.level, opcode,
+ s = "%sdo_%s(%s)\n" % (" " * self.level, opcode,
repr(args))
if len(s) > 80:
s = s[:76] + "...\n"
@@ -389,7 +391,7 @@ class TALInterpreter(object):
col = self.col + _len(name) + 1
wrap = self.wrap
align = col + 1
- if align >= wrap/2:
+ if align >= wrap / 2:
align = 4 # Avoid a narrow column far to the right
attrAction = self.dispatch["<attrAction>"]
try:
@@ -410,9 +412,9 @@ class TALInterpreter(object):
slen = _len(s)
if (wrap and
col >= align and
- col + 1 + slen > wrap):
+ col + 1 + slen > wrap):
append("\n")
- append(" "*align)
+ append(" " * align)
col = align + slen
else:
append(" ")
@@ -473,7 +475,7 @@ class TALInterpreter(object):
if self.html and name.lower() in BOOLEAN_HTML_ATTRS:
evalue = self.engine.evaluateBoolean(item[3])
if evalue is self.Default:
- if action == 'insert': # Cancelled insert
+ if action == 'insert': # Cancelled insert
ok = 0
elif evalue:
value = None
@@ -482,7 +484,7 @@ class TALInterpreter(object):
elif expr is not None:
evalue = self.engine.evaluateText(item[3])
if evalue is self.Default:
- if action == 'insert': # Cancelled insert
+ if action == 'insert': # Cancelled insert
ok = 0
else:
if evalue is None:
@@ -786,7 +788,7 @@ class TALInterpreter(object):
def insertHTMLStructure(self, text, repldict):
from zope.tal.htmltalparser import HTMLTALParser
gen = AltTALGenerator(repldict, self.engine, 0)
- p = HTMLTALParser(gen) # Raises an exception if text is invalid
+ p = HTMLTALParser(gen) # Raises an exception if text is invalid
p.parseString(text)
program, macros = p.getCode()
self.interpret(program)
@@ -798,7 +800,7 @@ class TALInterpreter(object):
gen.enable(0)
p.parseFragment('<!DOCTYPE foo PUBLIC "foo" "bar"><foo>')
gen.enable(1)
- p.parseFragment(text) # Raises an exception if text is invalid
+ p.parseFragment(text) # Raises an exception if text is invalid
gen.enable(0)
p.parseFragment('</foo>', 1)
program, macros = gen.getCode()
@@ -883,9 +885,10 @@ class TALInterpreter(object):
macro = block
else:
if not isCurrentVersion(macro):
- raise METALError("macro %s has incompatible version %s" %
- (repr(macroName), repr(getProgramVersion(macro))),
- self.position)
+ raise METALError(
+ "macro %s has incompatible version %s" %
+ (repr(macroName), repr(
+ getProgramVersion(macro))), self.position)
mode = getProgramMode(macro)
if mode != (self.html and "html" or "xml"):
raise METALError("macro %s has incompatible mode %s" %
@@ -985,7 +988,7 @@ class TALInterpreter(object):
# The ITALExpressionEngine interface should provide a way of
# getting the set of exception types that should not be
# handled.
- except:
+ except BaseException:
exc = sys.exc_info()[1]
try:
self.restoreState(state)
diff --git a/src/zope/tal/talparser.py b/src/zope/tal/talparser.py
index d99fc9f..d7d1964 100644
--- a/src/zope/tal/talparser.py
+++ b/src/zope/tal/talparser.py
@@ -32,7 +32,7 @@ class TALParser(XMLParser):
ordered_attributes = 1
- def __init__(self, gen=None, encoding=None): # Override
+ def __init__(self, gen=None, encoding=None): # Override
"""
:keyword TALGenerator gen: The configured (with an expression compiler)
code generator to use. If one is not given, a default will be used.
@@ -67,9 +67,9 @@ class TALParser(XMLParser):
attrlist.append((key, value))
else:
# attrs is a dict of {name: value}
- attrlist = sorted(attrs.items()) # sort for definiteness
+ attrlist = sorted(attrs.items()) # sort for definiteness
name, attrlist, taldict, metaldict, i18ndict \
- = self.process_ns(name, attrlist)
+ = self.process_ns(name, attrlist)
attrlist = self.xmlnsattrs() + attrlist
self.gen.emitStartElement(name, attrlist, taldict, metaldict, i18ndict,
self.getpos())
@@ -82,7 +82,7 @@ class TALParser(XMLParser):
name, namebase, namens = self.fixname(name)
for key, value in attrlist:
key, keybase, keyns = self.fixname(key)
- ns = keyns or namens # default to tag namespace
+ ns = keyns or namens # default to tag namespace
item = key, value
if ns == 'metal':
metaldict[keybase] = value
@@ -137,6 +137,7 @@ class TALParser(XMLParser):
def DefaultHandler(self, text):
self.gen.emitRawText(text)
+
def test():
import sys
p = TALParser()
@@ -150,5 +151,6 @@ def test():
engine = DummyEngine(macros)
TALInterpreter(program, macros, engine, sys.stdout, wrap=0)()
+
if __name__ == "__main__":
test()
diff --git a/src/zope/tal/tests/markbench.py b/src/zope/tal/tests/markbench.py
index 3122cb2..6dafa74 100644
--- a/src/zope/tal/tests/markbench.py
+++ b/src/zope/tal/tests/markbench.py
@@ -16,25 +16,23 @@
"""
from __future__ import print_function
+from zope.tal.dummyengine import DummyEngine
+from zope.tal.talinterpreter import TALInterpreter
+from zope.tal.htmltalparser import HTMLTALParser
+from cStringIO import StringIO
+import errno
+import time
+import sys
+import getopt
+import os
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
-import os
os.environ['NO_SECURITY'] = 'true'
-import getopt
-import sys
-import time
-import errno
-
-from cStringIO import StringIO
-
-#from zope.documenttemplate.dt_html import HTMLFile
-from zope.tal.htmltalparser import HTMLTALParser
-from zope.tal.talinterpreter import TALInterpreter
-from zope.tal.dummyengine import DummyEngine
+# from zope.documenttemplate.dt_html import HTMLFile
def time_apply(f, args, kwargs, count):
@@ -50,12 +48,14 @@ def time_apply(f, args, kwargs, count):
t = time.clock() - t1 - (t1 - t0)
return t / count
+
def time_zpt(fn, count):
from zope.pagetemplate.pagetemplate import PageTemplate
pt = PageTemplate()
pt.write(open(fn).read())
return time_apply(pt.pt_render, (data,), {}, count)
+
def time_tal(fn, count):
p = HTMLTALParser()
p.parseFile(fn)
@@ -66,10 +66,12 @@ def time_tal(fn, count):
tal=1, strictinsert=0)
return time_apply(tal, (), {}, count)
+
def time_dtml(fn, count):
- html = HTMLFile(fn)
+ html = HTMLFile(fn) # noqa: F821 undefined name 'HTMLFile'
return time_apply(html, (), data, count)
+
def profile_zpt(fn, count, profiler):
from zope.pagetemplate.pagetemplate import PageTemplate
pt = PageTemplate()
@@ -80,6 +82,7 @@ def profile_zpt(fn, count, profiler):
for i in r:
profiler.runcall(pt.pt_render, 0, data)
+
def profile_tal(fn, count, profiler):
p = HTMLTALParser()
p.parseFile(fn)
@@ -94,6 +97,7 @@ def profile_tal(fn, count, profiler):
for i in r:
profiler.runcall(tal)
+
# Figure out where the benchmark files are:
try:
fname = __file__
@@ -106,15 +110,17 @@ benchdir = os.path.join(taldir, 'benchmark')
tal_fn = os.path.join(benchdir, 'tal%.2d.html')
dtml_fn = os.path.join(benchdir, 'dtml%.2d.html')
+
def compare(n, count, profiler=None, verbose=1):
if verbose:
t1 = int(time_zpt(tal_fn % n, count) * 1000 + 0.5)
t2 = int(time_tal(tal_fn % n, count) * 1000 + 0.5)
- t3 = 'n/a' # int(time_dtml(dtml_fn % n, count) * 1000 + 0.5)
+ t3 = 'n/a' # int(time_dtml(dtml_fn % n, count) * 1000 + 0.5)
print('%.2d: %10s %10s %10s' % (n, t1, t2, t3))
if profiler:
profile_tal(tal_fn % n, count, profiler)
+
def main(count, profiler=None, verbose=1):
n = 1
if verbose:
@@ -123,6 +129,7 @@ def main(count, profiler=None, verbose=1):
compare(n, count, profiler, verbose)
n = n + 1
+
def get_signal_name(sig):
import signal
for name in dir(signal):
@@ -130,7 +137,8 @@ def get_signal_name(sig):
return name
return None
-data = {'x':'X', 'r2': [0, 1], 'r8': list(range(8)), 'r64': list(range(64))}
+
+data = {'x': 'X', 'r2': [0, 1], 'r8': list(range(8)), 'r64': list(range(64))}
for i in range(10):
data['x%s' % i] = 'X%s' % i
@@ -163,9 +171,9 @@ if __name__ == "__main__":
sys.exit(rc)
elif rc < 0:
sig = -rc
- print((
- "Process exited, signal %d (%s)."
- % (sig, get_signal_name(sig) or "<unknown signal>")), file=sys.stderr)
+ print(("Process exited, signal %d (%s)." %
+ (sig, get_signal_name(sig) or "<unknown signal>")),
+ file=sys.stderr)
sys.exit(1)
os.chdir(pwd)
diff --git a/src/zope/tal/tests/run.py b/src/zope/tal/tests/run.py
index 6de4a50..01a52c2 100644
--- a/src/zope/tal/tests/run.py
+++ b/src/zope/tal/tests/run.py
@@ -24,6 +24,8 @@ from zope.tal.tests import test_files
from zope.tal.tests import test_sourcepos
# TODO this code isn't picked up by the Zope 3 test framework..
+
+
def test_suite():
suite = unittest.TestSuite()
suite.addTest(test_htmltalparser.test_suite())
@@ -35,9 +37,11 @@ def test_suite():
suite.addTest(test_sourcepos.test_suite())
return suite
+
def main():
return utils.run_suite(test_suite())
+
if __name__ == "__main__":
errs = main()
sys.exit(errs and 1 or 0)
diff --git a/src/zope/tal/tests/test_files.py b/src/zope/tal/tests/test_files.py
index eca051c..9ecefd1 100644
--- a/src/zope/tal/tests/test_files.py
+++ b/src/zope/tal/tests/test_files.py
@@ -61,7 +61,7 @@ def _factory(filename, dirname):
captured_stdout = buf.getvalue()
if failed:
raise AssertionError("output for %s didn't match:\n%s"
- % (filename, captured_stdout))
+ % (filename, captured_stdout))
return unittest.FunctionTestCase(runTest, setUp, tearDown, short_path)
@@ -81,10 +81,13 @@ def _find_files():
# Nose doesn't handle 'test_suite' in the same was as zope.testrunner,
# so we'll use its generator-as-test-factory feature. See:
# https://nose.readthedocs.org/en/latest/writing_tests.html#test-generators
+
+
def test_for_nose_discovery():
for arg in _find_files():
yield _factory(arg, PARENTDIR)
+
def test_suite():
return unittest.TestSuite(
[_factory(arg, PARENTDIR) for arg in _find_files()])
diff --git a/src/zope/tal/tests/test_htmltalparser.py b/src/zope/tal/tests/test_htmltalparser.py
index 126b707..ba2770b 100644
--- a/src/zope/tal/tests/test_htmltalparser.py
+++ b/src/zope/tal/tests/test_htmltalparser.py
@@ -14,11 +14,9 @@
"""Tests for the HTMLTALParser code generator.
"""
import pprint
-import sys
import unittest
from zope.tal import htmltalparser, taldefs
-from zope.tal.tests import utils
class TestCaseBase(unittest.TestCase):
@@ -36,7 +34,7 @@ class TestCaseBase(unittest.TestCase):
return (p1[:-1]
+ [rawtext(args1[0] + args2[0])]
+ p2[1:])
- return p1+p2
+ return p1 + p2
def _run_check(self, source, program, macros={}):
parser = htmltalparser.HTMLTALParser()
@@ -72,29 +70,31 @@ class HTMLTALParserTestCases(TestCaseBase):
self._run_check("""<html a='b' b="c" c=d><title>My Title</html>""", [
rawtext('<html a="b" b="c" c="d">'
'<title>My Title</title></html>'),
- ])
+ ])
def test_code_implied_list_closings(self):
self._run_check("""<ul><li><p><p><li></ul>""", [
rawtext('<ul><li><p></p><p></p></li><li></li></ul>'),
- ])
+ ])
self._run_check("""<dl><dt><dt><dd><dd><ol><li><li></ol></dl>""", [
rawtext('<dl><dt></dt><dt></dt><dd></dd>'
'<dd><ol><li></li><li></li></ol></dd></dl>'),
- ])
+ ])
def test_code_implied_table_closings(self):
- self._run_check("""<p>text <table><tr><th>head\t<tr><td>cell\t"""
- """<table><tr><td>cell \n \t \n<tr>""", [
- rawtext('<p>text</p> <table><tr><th>head</th>'
+ self._run_check(
+ """<p>text <table><tr><th>head\t<tr><td>cell\t"""
+ """<table><tr><td>cell \n \t \n<tr>""", [
+ rawtext(
+ '<p>text</p> <table><tr><th>head</th>'
'</tr>\t<tr><td>cell\t<table><tr><td>cell</td>'
- '</tr> \n \t \n<tr></tr></table></td></tr></table>'),
- ])
- self._run_check("""<table><tr><td>cell """
- """<table><tr><td>cell </table></table>""", [
- rawtext('<table><tr><td>cell <table><tr><td>cell</td></tr>'
- ' </table></td></tr></table>'),
- ])
+ '</tr> \n \t \n<tr></tr></table></td></tr></table>'), ])
+ self._run_check(
+ """<table><tr><td>cell """
+ """<table><tr><td>cell </table></table>""",
+ [rawtext('<table><tr><td>cell <table><tr><td>cell</td></tr>'
+ ' </table></td></tr></table>'),
+ ])
def test_code_bad_nesting(self):
def check(self=self):
@@ -104,7 +104,7 @@ class HTMLTALParserTestCases(TestCaseBase):
def test_code_attr_syntax(self):
output = [
rawtext('<a b="v" c="v" d="v" e></a>'),
- ]
+ ]
self._run_check("""<a b='v' c="v" d=v e>""", output)
self._run_check("""<a b = 'v' c = "v" d = v e>""", output)
self._run_check("""<a\nb\n=\n'v'\nc\n=\n"v"\nd\n=\nv\ne>""", output)
@@ -113,40 +113,40 @@ class HTMLTALParserTestCases(TestCaseBase):
def test_code_attr_values(self):
self._run_check(
"""<a b='xxx\n\txxx' c="yyy\t\nyyy" d='\txyz\n'>""", [
- rawtext('<a b="xxx\n\txxx" c="yyy\t\nyyy" d="\txyz\n"></a>')])
+ rawtext('<a b="xxx\n\txxx" c="yyy\t\nyyy" d="\txyz\n"></a>')])
self._run_check("""<a b='' c="">""", [
rawtext('<a b="" c=""></a>'),
- ])
+ ])
def test_code_attr_entity_replacement(self):
# we expect entities *not* to be replaced by HTLMParser!
self._run_check("""<a b='&amp;&gt;&lt;&quot;&apos;'>""", [
rawtext('<a b="&amp;&gt;&lt;&quot;\'"></a>'),
- ])
+ ])
self._run_check("""<a b='\"'>""", [
rawtext('<a b="&quot;"></a>'),
- ])
+ ])
self._run_check("""<a b='&'>""", [
rawtext('<a b="&amp;"></a>'),
- ])
+ ])
self._run_check("""<a b='<'>""", [
rawtext('<a b="&lt;"></a>'),
- ])
+ ])
def test_code_attr_funky_names(self):
self._run_check("""<a a.b='v' c:d=v e-f=v>""", [
rawtext('<a a.b="v" c:d="v" e-f="v"></a>'),
- ])
+ ])
def test_code_pcdata_entityref(self):
self._run_check("""&nbsp;""", [
rawtext('&nbsp;'),
- ])
+ ])
def test_code_short_endtags(self):
self._run_check("""<html><img/></html>""", [
rawtext('<html><img /></html>'),
- ])
+ ])
class METALGeneratorTestCases(TestCaseBase):
@@ -158,11 +158,11 @@ class METALGeneratorTestCases(TestCaseBase):
macro = self.initial_program + [
('startTag', ('p', [('metal:define-macro', 'M', 'metal')])),
rawtext('booh</p>'),
- ]
+ ]
program = [
('setPosition', (1, 0)),
('defineMacro', ('M', macro)),
- ]
+ ]
macros = {'M': macro}
self._run_check('<p metal:define-macro="M">booh</p>', program, macros)
@@ -173,7 +173,7 @@ class METALGeneratorTestCases(TestCaseBase):
('M', '$M$', {},
[('startTag', ('p', [('metal:use-macro', 'M', 'metal')])),
rawtext('booh</p>')])),
- ])
+ ])
def test_define_slot(self):
macro = self.initial_program + [
@@ -181,10 +181,12 @@ class METALGeneratorTestCases(TestCaseBase):
rawtext('foo'),
('setPosition', (1, 29)),
('defineSlot', ('S',
- [('startTag', ('span', [('metal:define-slot', 'S', 'metal')])),
- rawtext('spam</span>')])),
+ [('startTag', ('span', [('metal:define-slot',
+ 'S',
+ 'metal')])),
+ rawtext('spam</span>')])),
rawtext('bar</p>'),
- ]
+ ]
program = [('setPosition', (1, 0)),
('defineMacro', ('M', macro))]
macros = {'M': macro}
@@ -193,21 +195,24 @@ class METALGeneratorTestCases(TestCaseBase):
program, macros)
def test_fill_slot(self):
- self._run_check('<p metal:use-macro="M">foo'
- '<span metal:fill-slot="S">spam</span>bar</p>', [
- ('setPosition', (1, 0)),
- ('useMacro',
- ('M', '$M$',
- {'S': [('startTag', ('span',
- [('metal:fill-slot', 'S', 'metal')])),
- rawtext('spam</span>')]},
- [('startTag', ('p', [('metal:use-macro', 'M', 'metal')])),
- rawtext('foo'),
- ('setPosition', (1, 26)),
- ('fillSlot', ('S',
- [('startTag', ('span', [('metal:fill-slot', 'S', 'metal')])),
- rawtext('spam</span>')])),
- rawtext('bar</p>')])),
+ self._run_check(
+ '<p metal:use-macro="M">foo'
+ '<span metal:fill-slot="S">spam</span>bar</p>', [
+ ('setPosition', (1, 0)),
+ ('useMacro',
+ ('M', '$M$',
+ {'S': [('startTag', ('span',
+ [('metal:fill-slot', 'S', 'metal')])),
+ rawtext('spam</span>')]},
+ [('startTag', ('p', [('metal:use-macro', 'M', 'metal')])),
+ rawtext('foo'),
+ ('setPosition', (1, 26)),
+ ('fillSlot', ('S', [
+ ('startTag', (
+ 'span',
+ [('metal:fill-slot', 'S', 'metal')])),
+ rawtext('spam</span>')])),
+ rawtext('bar</p>')])),
])
@@ -224,7 +229,7 @@ class TALGeneratorTestCases(TestCaseBase):
('startTag', ('p', [('tal:define', 'xyzzy string:spam', 'tal')])),
('endScope', ()),
rawtext('</p>'),
- ])
+ ])
def test_define_2(self):
self._run_check("<p tal:define='local xyzzy string:spam'></p>", [
@@ -232,10 +237,10 @@ class TALGeneratorTestCases(TestCaseBase):
('beginScope', {'tal:define': 'local xyzzy string:spam'}),
('setLocal', ('xyzzy', '$string:spam$')),
('startTag', ('p',
- [('tal:define', 'local xyzzy string:spam', 'tal')])),
+ [('tal:define', 'local xyzzy string:spam', 'tal')])),
('endScope', ()),
rawtext('</p>'),
- ])
+ ])
def test_define_3(self):
self._run_check("<p tal:define='global xyzzy string:spam'></p>", [
@@ -243,10 +248,12 @@ class TALGeneratorTestCases(TestCaseBase):
('beginScope', {'tal:define': 'global xyzzy string:spam'}),
('setGlobal', ('xyzzy', '$string:spam$')),
('startTag', ('p',
- [('tal:define', 'global xyzzy string:spam', 'tal')])),
+ [('tal:define',
+ 'global xyzzy string:spam',
+ 'tal')])),
('endScope', ()),
rawtext('</p>'),
- ])
+ ])
def test_define_4(self):
self._run_check("<p tal:define='x string:spam; y x'></p>", [
@@ -257,7 +264,7 @@ class TALGeneratorTestCases(TestCaseBase):
('startTag', ('p', [('tal:define', 'x string:spam; y x', 'tal')])),
('endScope', ()),
rawtext('</p>'),
- ])
+ ])
def test_define_5(self):
self._run_check("<p tal:define='x string:;;;;; y x'></p>", [
@@ -268,162 +275,179 @@ class TALGeneratorTestCases(TestCaseBase):
('startTag', ('p', [('tal:define', 'x string:;;;;; y x', 'tal')])),
('endScope', ()),
rawtext('</p>'),
- ])
+ ])
def test_define_6(self):
self._run_check(
"<p tal:define='x string:spam; global y x; local z y'></p>", [
- ('setPosition', (1, 0)),
- ('beginScope',
- {'tal:define': 'x string:spam; global y x; local z y'}),
- ('setLocal', ('x', '$string:spam$')),
- ('setGlobal', ('y', '$x$')),
- ('setLocal', ('z', '$y$')),
- ('startTag', ('p',
- [('tal:define', 'x string:spam; global y x; local z y', 'tal')])),
- ('endScope', ()),
- rawtext('</p>'),
+ ('setPosition', (1, 0)),
+ ('beginScope',
+ {'tal:define': 'x string:spam; global y x; local z y'}),
+ ('setLocal', ('x', '$string:spam$')),
+ ('setGlobal', ('y', '$x$')),
+ ('setLocal', ('z', '$y$')),
+ ('startTag', ('p',
+ [('tal:define',
+ 'x string:spam; global y x; local z y',
+ 'tal')])),
+ ('endScope', ()),
+ rawtext('</p>'),
])
def test_condition(self):
self._run_check(
"<p><span tal:condition='python:1'><b>foo</b></span></p>", [
- rawtext('<p>'),
- ('setPosition', (1, 3)),
- ('beginScope', {'tal:condition': 'python:1'}),
- ('condition', ('$python:1$',
- [('startTag', ('span', [('tal:condition', 'python:1', 'tal')])),
- rawtext('<b>foo</b></span>')])),
- ('endScope', ()),
- rawtext('</p>'),
+ rawtext('<p>'),
+ ('setPosition', (1, 3)),
+ ('beginScope', {'tal:condition': 'python:1'}),
+ ('condition', ('$python:1$',
+ [('startTag', ('span', [('tal:condition',
+ 'python:1',
+ 'tal')])),
+ rawtext('<b>foo</b></span>')])),
+ ('endScope', ()),
+ rawtext('</p>'),
])
def test_content_1(self):
self._run_check("<p tal:content='string:foo'>bar</p>", [
- ('setPosition', (1, 0)),
- ('beginScope', {'tal:content': 'string:foo'}),
- ('startTag', ('p', [('tal:content', 'string:foo', 'tal')])),
- ('insertText', ('$string:foo$', [rawtext('bar')])),
- ('endScope', ()),
- rawtext('</p>'),
- ])
+ ('setPosition', (1, 0)),
+ ('beginScope', {'tal:content': 'string:foo'}),
+ ('startTag', ('p', [('tal:content', 'string:foo', 'tal')])),
+ ('insertText', ('$string:foo$', [rawtext('bar')])),
+ ('endScope', ()),
+ rawtext('</p>'),
+ ])
def test_content_2(self):
self._run_check("<p tal:content='text string:foo'>bar</p>", [
- ('setPosition', (1, 0)),
- ('beginScope', {'tal:content': 'text string:foo'}),
- ('startTag', ('p', [('tal:content', 'text string:foo', 'tal')])),
- ('insertText', ('$string:foo$', [rawtext('bar')])),
- ('endScope', ()),
- rawtext('</p>'),
- ])
+ ('setPosition', (1, 0)),
+ ('beginScope', {'tal:content': 'text string:foo'}),
+ ('startTag', ('p', [('tal:content', 'text string:foo', 'tal')])),
+ ('insertText', ('$string:foo$', [rawtext('bar')])),
+ ('endScope', ()),
+ rawtext('</p>'),
+ ])
def test_content_3(self):
self._run_check("<p tal:content='structure string:<br>'>bar</p>", [
- ('setPosition', (1, 0)),
- ('beginScope', {'tal:content': 'structure string:<br>'}),
- ('startTag', ('p',
- [('tal:content', 'structure string:<br>', 'tal')])),
- ('insertStructure',
- ('$string:<br>$', {}, [rawtext('bar')])),
- ('endScope', ()),
- rawtext('</p>'),
- ])
+ ('setPosition', (1, 0)),
+ ('beginScope', {'tal:content': 'structure string:<br>'}),
+ ('startTag', ('p',
+ [('tal:content', 'structure string:<br>', 'tal')])),
+ ('insertStructure',
+ ('$string:<br>$', {}, [rawtext('bar')])),
+ ('endScope', ()),
+ rawtext('</p>'),
+ ])
def test_replace_1(self):
self._run_check("<p tal:replace='string:foo'>bar</p>", [
- ('setPosition', (1, 0)),
- ('beginScope', {'tal:replace': 'string:foo'}),
- ('optTag',
- ('p',
- '',
- None,
- 0,
- [('startTag', ('p', [('tal:replace', 'string:foo', 'tal')]))],
- [('insertText', ('$string:foo$', [('rawtextOffset', ('bar', 3))]))])),
- ('endScope', ()),
- ])
+ ('setPosition', (1, 0)),
+ ('beginScope', {'tal:replace': 'string:foo'}),
+ ('optTag',
+ ('p',
+ '',
+ None,
+ 0,
+ [('startTag', ('p', [('tal:replace', 'string:foo', 'tal')]))],
+ [('insertText', ('$string:foo$', [('rawtextOffset',
+ ('bar', 3))]))])),
+ ('endScope', ()),
+ ])
def test_replace_2(self):
self._run_check("<p tal:replace='text string:foo'>bar</p>", [
- ('setPosition', (1, 0)),
- ('beginScope', {'tal:replace': 'text string:foo'}),
- ('optTag',
- ('p',
- '',
- None,
- 0,
- [('startTag', ('p', [('tal:replace', 'text string:foo', 'tal')]))],
- [('insertText', ('$string:foo$', [('rawtextOffset', ('bar', 3))]))])),
- ('endScope', ()),
- ])
+ ('setPosition', (1, 0)),
+ ('beginScope', {'tal:replace': 'text string:foo'}),
+ ('optTag',
+ ('p',
+ '',
+ None,
+ 0,
+ [('startTag', ('p', [('tal:replace',
+ 'text string:foo',
+ 'tal')]))],
+ [('insertText', ('$string:foo$', [('rawtextOffset',
+ ('bar', 3))]))])),
+ ('endScope', ()),
+ ])
def test_replace_3(self):
- self._run_check("<p tal:replace='structure string:<br>'>bar</p>", [
- ('setPosition', (1, 0)),
- ('beginScope', {'tal:replace': 'structure string:<br>'}),
- ('optTag',
- ('p',
- '',
- None,
- 0,
- [('startTag', ('p', [('tal:replace', 'structure string:<br>', 'tal')]))],
- [('insertStructure',
- ('$string:<br>$', {}, [('rawtextOffset', ('bar', 3))]))])),
- ('endScope', ()),
- ])
+ self._run_check(
+ "<p tal:replace='structure string:<br>'>bar</p>", [
+ ('setPosition', (1, 0)),
+ ('beginScope',
+ {'tal:replace': 'structure string:<br>'}),
+ ('optTag',
+ ('p',
+ '',
+ None,
+ 0,
+ [('startTag', (
+ 'p', [(
+ 'tal:replace',
+ 'structure string:<br>',
+ 'tal')]))],
+ [('insertStructure', ('$string:<br>$', {}, [
+ ('rawtextOffset', ('bar', 3))]))])),
+ ('endScope', ()), ])
def test_repeat(self):
- self._run_check("<p tal:repeat='x python:(1,2,3)'>"
- "<span tal:replace='x'>dummy</span></p>", [
- ('setPosition', (1, 0)),
- ('beginScope', {'tal:repeat': 'x python:(1,2,3)'}),
- ('loop', ('x', '$python:(1,2,3)$',
- [('startTag', ('p',
- [('tal:repeat', 'x python:(1,2,3)', 'tal')])),
- ('setPosition', (1, 33)),
- ('beginScope', {'tal:replace': 'x'}),
- ('optTag',
- ('span',
- '',
- None,
- 0,
- [('startTag', ('span', [('tal:replace', 'x', 'tal')]))],
- [('insertText', ('$x$', [('rawtextOffset', ('dummy', 5))]))])),
+ self._run_check(
+ "<p tal:repeat='x python:(1,2,3)'>"
+ "<span tal:replace='x'>dummy</span></p>", [
+ ('setPosition', (1, 0)),
+ ('beginScope', {'tal:repeat': 'x python:(1,2,3)'}),
+ ('loop', ('x', '$python:(1,2,3)$',
+ [('startTag', ('p',
+ [('tal:repeat',
+ 'x python:(1,2,3)', 'tal')])),
+ ('setPosition', (1, 33)),
+ ('beginScope', {'tal:replace': 'x'}),
+ ('optTag',
+ ('span',
+ '',
+ None,
+ 0,
+ [('startTag',
+ ('span', [('tal:replace', 'x', 'tal')]))],
+ [('insertText',
+ ('$x$',
+ [('rawtextOffset', ('dummy', 5))]))])),
+ ('endScope', ()),
+ rawtext('</p>')])),
('endScope', ()),
- rawtext('</p>')])),
- ('endScope', ()),
- ])
+ ])
def test_script_1(self):
self._run_check('<p tal:script="text/server-python">code</p>', [
- ('setPosition', (1, 0)),
- ('beginScope', {'tal:script': 'text/server-python'}),
- ('startTag', ('p',
- [('tal:script', 'text/server-python', 'tal')])),
- ('evaluateCode', ('text/server-python',
- [('rawtextOffset', ('code', 4))])),
- ('endScope', ()),
- rawtext('</p>'),
- ])
+ ('setPosition', (1, 0)),
+ ('beginScope', {'tal:script': 'text/server-python'}),
+ ('startTag', ('p',
+ [('tal:script', 'text/server-python', 'tal')])),
+ ('evaluateCode', ('text/server-python',
+ [('rawtextOffset', ('code', 4))])),
+ ('endScope', ()),
+ rawtext('</p>'),
+ ])
def test_script_2(self):
- self._run_check('<tal:block script="text/server-python">'
- 'code'
- '</tal:block>', [
- ('setPosition', (1, 0)),
- ('beginScope', {'script': 'text/server-python'}),
- ('optTag',
- ('tal:block',
- None,
- 'tal',
- 0,
- [('startTag', ('tal:block',
- [('script', 'text/server-python', 'tal')]))],
- [('evaluateCode',
- ('text/server-python',
- [('rawtextOffset', ('code', 4))]))])),
- ('endScope', ())
+ self._run_check(
+ '<tal:block script="text/server-python">code</tal:block>', [
+ ('setPosition', (1, 0)),
+ ('beginScope', {'script': 'text/server-python'}),
+ ('optTag',
+ ('tal:block',
+ None,
+ 'tal',
+ 0,
+ [('startTag',
+ ('tal:block', [('script', 'text/server-python', 'tal')]))],
+ [('evaluateCode',
+ ('text/server-python',
+ [('rawtextOffset', ('code', 4))]))])),
+ ('endScope', ())
])
def test_script_3(self):
@@ -439,104 +463,113 @@ class TALGeneratorTestCases(TestCaseBase):
[('evaluateCode',
('text/server-python', [('rawtextOffset', ('code', 4))]))])),
('endScope', ())
- ])
+ ])
def test_script_4(self):
self._run_check('<script type="text/javascript">code</script>', [
('rawtextOffset',
('<script type="text/javascript">code</script>', 44))
- ])
-
+ ])
+
def test_script_5(self):
- self._run_check("""<script type="text/javascript">var foo = '<div></div>';</script>""", [
- ('rawtextOffset',
- ("""<script type="text/javascript">var foo = '<div></div>';</script>""", 64))
- ])
+ self._run_check(
+ """<script type="text/javascript">var foo = '<div></div>';</script>""", [ # noqa: E501 line too long
+ ('rawtextOffset',
+ ("""<script type="text/javascript">var foo = '<div></div>';</script>""", # noqa: E501 line too long
+ 64))])
def test_attributes_1(self):
- self._run_check("<a href='foo' name='bar' tal:attributes="
- "'href string:http://www.zope.org; x string:y'>"
- "link</a>", [
- ('setPosition', (1, 0)),
- ('beginScope',
- {'tal:attributes': 'href string:http://www.zope.org; x string:y',
- 'name': 'bar', 'href': 'foo'}),
- ('startTag', ('a',
- [('href', 'foo', 'replace', '$string:http://www.zope.org$', 0, None),
- ('name', 'name="bar"'),
- ('tal:attributes',
- 'href string:http://www.zope.org; x string:y', 'tal'),
- ('x', None, 'insert', '$string:y$', 0, None)])),
- ('endScope', ()),
- rawtext('link</a>'),
+ self._run_check(
+ "<a href='foo' name='bar' tal:attributes="
+ "'href string:http://www.zope.org; x string:y'>"
+ "link</a>", [
+ ('setPosition', (1, 0)),
+ ('beginScope',
+ {'tal:attributes':
+ 'href string:http://www.zope.org; x string:y',
+ 'name': 'bar', 'href': 'foo'}),
+ ('startTag',
+ ('a',
+ [('href', 'foo', 'replace', '$string:http://www.zope.org$',
+ 0, None),
+ ('name', 'name="bar"'),
+ ('tal:attributes',
+ 'href string:http://www.zope.org; x string:y', 'tal'),
+ ('x', None, 'insert', '$string:y$', 0, None)])),
+ ('endScope', ()),
+ rawtext('link</a>'),
])
def test_attributes_2(self):
- self._run_check("<p tal:replace='structure string:<img>' "
- "tal:attributes='src string:foo.png'>duh</p>", [
- ('setPosition', (1, 0)),
- ('beginScope',
- {'tal:attributes': 'src string:foo.png',
- 'tal:replace': 'structure string:<img>'}),
- ('optTag',
- ('p',
- '',
- None,
- 0,
- [('startTag',
+ self._run_check(
+ "<p tal:replace='structure string:<img>' "
+ "tal:attributes='src string:foo.png'>duh</p>", [
+ ('setPosition', (1, 0)),
+ ('beginScope',
+ {'tal:attributes': 'src string:foo.png',
+ 'tal:replace': 'structure string:<img>'}),
+ ('optTag',
('p',
- [('tal:replace', 'structure string:<img>', 'tal'),
- ('tal:attributes', 'src string:foo.png', 'tal')]))],
- [('insertStructure',
- ('$string:<img>$',
- {'src': ('$string:foo.png$', False, None)},
- [('rawtextOffset', ('duh', 3))]))])),
- ('endScope', ())])
+ '',
+ None,
+ 0,
+ [('startTag',
+ ('p',
+ [('tal:replace', 'structure string:<img>', 'tal'),
+ ('tal:attributes', 'src string:foo.png', 'tal')]))],
+ [('insertStructure',
+ ('$string:<img>$',
+ {'src': ('$string:foo.png$', False, None)},
+ [('rawtextOffset', ('duh', 3))]))])),
+ ('endScope', ())])
def test_on_error_1(self):
- self._run_check("<p tal:on-error='string:error' "
- "tal:content='notHere'>okay</p>", [
- ('setPosition', (1, 0)),
- ('beginScope',
- {'tal:content': 'notHere', 'tal:on-error': 'string:error'}),
- ('onError',
- ([('startTag', ('p',
- [('tal:on-error', 'string:error', 'tal'),
- ('tal:content', 'notHere', 'tal')])),
- ('insertText', ('$notHere$', [rawtext('okay')])),
- rawtext('</p>')],
- [('startTag', ('p',
- [('tal:on-error', 'string:error', 'tal'),
- ('tal:content', 'notHere', 'tal')])),
- ('insertText', ('$string:error$', [])),
- rawtext('</p>')])),
- ('endScope', ()),
+ self._run_check(
+ "<p tal:on-error='string:error' "
+ "tal:content='notHere'>okay</p>", [
+ ('setPosition', (1, 0)),
+ ('beginScope',
+ {'tal:content': 'notHere', 'tal:on-error': 'string:error'}),
+ ('onError',
+ ([('startTag', ('p',
+ [('tal:on-error', 'string:error', 'tal'),
+ ('tal:content', 'notHere', 'tal')])),
+ ('insertText', ('$notHere$', [rawtext('okay')])),
+ rawtext('</p>')],
+ [('startTag', ('p',
+ [('tal:on-error', 'string:error', 'tal'),
+ ('tal:content', 'notHere', 'tal')])),
+ ('insertText', ('$string:error$', [])),
+ rawtext('</p>')])),
+ ('endScope', ()),
])
def test_on_error_2(self):
- self._run_check("<p tal:on-error='string:error' "
- "tal:replace='notHere'>okay</p>", [
- ('setPosition', (1, 0)),
- ('beginScope',
- {'tal:replace': 'notHere', 'tal:on-error': 'string:error'}),
- ('onError',
- ([('optTag',
- ('p',
- '',
- None,
- 0,
- [('startTag',
+ self._run_check(
+ "<p tal:on-error='string:error' "
+ "tal:replace='notHere'>okay</p>", [
+ ('setPosition', (1, 0)),
+ ('beginScope',
+ {'tal:replace': 'notHere', 'tal:on-error': 'string:error'}),
+ ('onError',
+ ([('optTag',
('p',
- [('tal:on-error', 'string:error', 'tal'),
- ('tal:replace', 'notHere', 'tal')]))],
- [('insertText', ('$notHere$', [('rawtextOffset', ('okay', 4))]))]))],
- [('startTag',
- ('p',
- [('tal:on-error', 'string:error', 'tal'),
- ('tal:replace', 'notHere', 'tal')])),
- ('insertText', ('$string:error$', [])),
- ('rawtextOffset', ('</p>', 4))])),
- ('endScope', ()),
+ '',
+ None,
+ 0,
+ [('startTag',
+ ('p',
+ [('tal:on-error', 'string:error', 'tal'),
+ ('tal:replace', 'notHere', 'tal')]))],
+ [('insertText',
+ ('$notHere$', [('rawtextOffset', ('okay', 4))]))]))],
+ [('startTag',
+ ('p',
+ [('tal:on-error', 'string:error', 'tal'),
+ ('tal:replace', 'notHere', 'tal')])),
+ ('insertText', ('$string:error$', [])),
+ ('rawtextOffset', ('</p>', 4))])),
+ ('endScope', ()),
])
def test_dup_attr(self):
@@ -555,9 +588,9 @@ class TALGeneratorTestCases(TestCaseBase):
def test_metal_errors(self):
exc = taldefs.METALError
- self._should_error(2*"<p metal:define-macro='x'>xxx</p>", exc)
+ self._should_error(2 * "<p metal:define-macro='x'>xxx</p>", exc)
self._should_error("<html metal:use-macro='x'>" +
- 2*"<p metal:fill-slot='y' />" + "</html>", exc)
+ 2 * "<p metal:fill-slot='y' />" + "</html>", exc)
self._should_error("<p metal:foobar='x' />", exc)
self._should_error("<p metal:define-macro='x'>", exc)
@@ -582,19 +615,19 @@ class TALGeneratorTestCases(TestCaseBase):
('setPosition', (1, 0)),
('beginScope', {'alt': 'foo', 'i18n:attributes': 'alt'}),
('startTag', ('img',
- [('alt', 'foo', 'replace', None, 1, None),
- ('i18n:attributes', 'alt', 'i18n')])),
+ [('alt', 'foo', 'replace', None, 1, None),
+ ('i18n:attributes', 'alt', 'i18n')])),
('endScope', ()),
- ])
+ ])
self._run_check("<img alt='foo' i18n:attributes='alt foo ; bar'>", [
('setPosition', (1, 0)),
('beginScope', {'alt': 'foo', 'i18n:attributes': 'alt foo ; bar'}),
('startTag', ('img',
- [('alt', 'foo', 'replace', None, 1, 'foo'),
- ('i18n:attributes', 'alt foo ; bar', 'i18n'),
- ('bar', None, 'insert', None, 1, None)])),
+ [('alt', 'foo', 'replace', None, 1, 'foo'),
+ ('i18n:attributes', 'alt foo ; bar', 'i18n'),
+ ('bar', None, 'insert', None, 1, None)])),
('endScope', ()),
- ])
+ ])
def test_i18n_name_bad_name(self):
self._should_error("<span i18n:name='not a valid name' />")
@@ -613,46 +646,52 @@ translated string</span>
<span i18n:translate="">And another
translated string</span>
''', [
- ('setPosition', (1, 0)),
- ('beginScope', {'i18n:translate': ''}),
- ('startTag', ('span', [('i18n:translate', '', 'i18n')])),
- ('insertTranslation', ('', [('rawtextOffset', ('Replace this', 12))])),
- ('rawtextBeginScope',
- ('</span>\n', 0, (2, 0), 1, {'i18n:translate': 'msgid'})),
- ('startTag', ('span', [('i18n:translate', 'msgid', 'i18n')])),
- ('insertTranslation',
- ('msgid', [('rawtextColumn', ('This is a\ntranslated string', 17))])),
- ('rawtextBeginScope', ('</span>\n', 0, (4, 0), 1, {'i18n:translate': ''})),
- ('startTag', ('span', [('i18n:translate', '', 'i18n')])),
- ('insertTranslation',
- ('', [('rawtextColumn', ('And another\ntranslated string', 17))])),
- ('endScope', ()),
- ('rawtextColumn', ('</span>\n', 0))])
+ ('setPosition', (1, 0)),
+ ('beginScope', {'i18n:translate': ''}),
+ ('startTag', ('span', [('i18n:translate', '', 'i18n')])),
+ ('insertTranslation',
+ ('', [('rawtextOffset', ('Replace this', 12))])),
+ ('rawtextBeginScope',
+ ('</span>\n', 0, (2, 0), 1, {'i18n:translate': 'msgid'})),
+ ('startTag', ('span', [('i18n:translate', 'msgid', 'i18n')])),
+ ('insertTranslation',
+ ('msgid',
+ [('rawtextColumn', ('This is a\ntranslated string', 17))])),
+ ('rawtextBeginScope',
+ ('</span>\n', 0, (4, 0), 1, {'i18n:translate': ''})),
+ ('startTag', ('span', [('i18n:translate', '', 'i18n')])),
+ ('insertTranslation',
+ ('', [('rawtextColumn',
+ ('And another\ntranslated string', 17))])),
+ ('endScope', ()),
+ ('rawtextColumn', ('</span>\n', 0))])
def test_i18n_translate_with_nested_tal(self):
self._run_check('''\
<span i18n:translate="">replaceable <p tal:replace="str:here">content</p></span>
-''', [
- ('setPosition', (1, 0)),
- ('beginScope', {'i18n:translate': ''}),
- ('startTag', ('span', [('i18n:translate', '', 'i18n')])),
- ('insertTranslation',
- ('',
- [('rawtextOffset', ('replaceable ', 12)),
- ('setPosition', (1, 36)),
- ('beginScope', {'tal:replace': 'str:here'}),
- ('optTag',
- ('p',
- '',
- None,
- 0,
- [('startTag', ('p', [('tal:replace', 'str:here', 'tal')]))],
- [('insertText',
- ('$str:here$', [('rawtextOffset', ('content', 7))]))])),
- ('endScope', ())])),
- ('endScope', ()),
- ('rawtextColumn', ('</span>\n', 0))
- ])
+''', [ # noqa: E501 line too long
+ ('setPosition', (1, 0)),
+ ('beginScope', {'i18n:translate': ''}),
+ ('startTag', ('span', [('i18n:translate', '', 'i18n')])),
+ ('insertTranslation',
+ ('',
+ [('rawtextOffset', ('replaceable ', 12)),
+ ('setPosition', (1, 36)),
+ ('beginScope', {'tal:replace': 'str:here'}),
+ ('optTag',
+ ('p',
+ '',
+ None,
+ 0,
+ [('startTag', ('p', [('tal:replace',
+ 'str:here', 'tal')]))],
+ [('insertText',
+ ('$str:here$', [('rawtextOffset',
+ ('content', 7))]))])),
+ ('endScope', ())])),
+ ('endScope', ()),
+ ('rawtextColumn', ('</span>\n', 0))
+ ])
def test_i18n_name(self):
# input/test21.html
@@ -662,86 +701,90 @@ translated string</span>
<span tal:replace="str:Antarctica" i18n:name="country" />.
</span>
''', [
- ('setPosition', (1, 0)),
- ('beginScope', {'i18n:translate': ''}),
- ('startTag', ('span', [('i18n:translate', '', 'i18n')])),
- ('insertTranslation',
- ('',
- [('rawtextBeginScope',
- ('\n ',
- 2,
- (2, 2),
- 0,
- {'i18n:name': 'name', 'tal:replace': 'str:Lomax'})),
- ('i18nVariable',
- ('name',
- [('optTag',
- ('span',
- '',
- None,
- 1,
- [('startEndTag',
- ('span',
- [('tal:replace', 'str:Lomax', 'tal'),
- ('i18n:name', 'name', 'i18n')]))],
- [('insertText', ('$str:Lomax$', []))]))],
- None,
- 0)),
- ('rawtextBeginScope',
- (' was born in\n ',
- 2,
- (3, 2),
- 1,
- {'i18n:name': 'country', 'tal:replace': 'str:Antarctica'})),
- ('i18nVariable',
- ('country',
- [('optTag',
- ('span',
- '',
- None,
- 1,
- [('startEndTag',
- ('span',
- [('tal:replace', 'str:Antarctica', 'tal'),
- ('i18n:name', 'country', 'i18n')]))],
- [('insertText', ('$str:Antarctica$', []))]))],
- None,
- 0)),
- ('endScope', ()),
- ('rawtextColumn', ('.\n', 0))])),
- ('endScope', ()),
- ('rawtextColumn', ('</span>\n', 0))
- ])
+ ('setPosition', (1, 0)),
+ ('beginScope', {'i18n:translate': ''}),
+ ('startTag', ('span', [('i18n:translate', '', 'i18n')])),
+ ('insertTranslation',
+ ('',
+ [('rawtextBeginScope',
+ ('\n ',
+ 2,
+ (2, 2),
+ 0,
+ {'i18n:name': 'name', 'tal:replace': 'str:Lomax'})),
+ ('i18nVariable',
+ ('name',
+ [('optTag',
+ ('span',
+ '',
+ None,
+ 1,
+ [('startEndTag',
+ ('span',
+ [('tal:replace', 'str:Lomax', 'tal'),
+ ('i18n:name', 'name', 'i18n')]))],
+ [('insertText', ('$str:Lomax$', []))]))],
+ None,
+ 0)),
+ ('rawtextBeginScope',
+ (' was born in\n ',
+ 2,
+ (3, 2),
+ 1,
+ {'i18n:name': 'country',
+ 'tal:replace': 'str:Antarctica'})),
+ ('i18nVariable',
+ ('country',
+ [('optTag',
+ ('span',
+ '',
+ None,
+ 1,
+ [('startEndTag',
+ ('span',
+ [('tal:replace', 'str:Antarctica', 'tal'),
+ ('i18n:name', 'country', 'i18n')]))],
+ [('insertText', ('$str:Antarctica$', []))]))],
+ None,
+ 0)),
+ ('endScope', ()),
+ ('rawtextColumn', ('.\n', 0))])),
+ ('endScope', ()),
+ ('rawtextColumn', ('</span>\n', 0))
+ ])
def test_i18n_name_with_content(self):
- self._run_check('<div i18n:translate="">This is text for '
+ self._run_check(
+ '<div i18n:translate="">This is text for '
'<span i18n:translate="" tal:content="bar" i18n:name="bar_name"/>.'
'</div>', [
-('setPosition', (1, 0)),
-('beginScope', {'i18n:translate': ''}),
-('startTag', ('div', [('i18n:translate', '', 'i18n')])),
-('insertTranslation',
- ('',
- [('rawtextOffset', ('This is text for ', 17)),
- ('setPosition', (1, 40)),
- ('beginScope',
- {'tal:content': 'bar', 'i18n:name': 'bar_name', 'i18n:translate': ''}),
- ('i18nVariable',
- ('bar_name',
- [('startTag',
- ('span',
- [('i18n:translate', '', 'i18n'),
- ('tal:content', 'bar', 'tal'),
- ('i18n:name', 'bar_name', 'i18n')])),
- ('insertI18nText', ('$bar$', [])),
- ('rawtextOffset', ('</span>', 7))],
- None,
- 0)),
- ('endScope', ()),
- ('rawtextOffset', ('.', 1))])),
-('endScope', ()),
-('rawtextOffset', ('</div>', 6))
- ])
+ ('setPosition', (1, 0)),
+ ('beginScope', {'i18n:translate': ''}),
+ ('startTag', ('div', [('i18n:translate', '', 'i18n')])),
+ ('insertTranslation',
+ ('',
+ [('rawtextOffset', ('This is text for ', 17)),
+ ('setPosition', (1, 40)),
+ ('beginScope',
+ {'tal:content': 'bar',
+ 'i18n:name': 'bar_name',
+ 'i18n:translate': ''}),
+ ('i18nVariable',
+ ('bar_name',
+ [('startTag',
+ ('span',
+ [('i18n:translate', '', 'i18n'),
+ ('tal:content', 'bar', 'tal'),
+ ('i18n:name', 'bar_name', 'i18n')])),
+ ('insertI18nText', ('$bar$', [])),
+ ('rawtextOffset', ('</span>', 7))],
+ None,
+ 0)),
+ ('endScope', ()),
+ ('rawtextOffset', ('.', 1))])),
+ ('endScope', ()),
+ ('rawtextOffset', ('</div>', 6))
+ ])
def test_i18n_name_implicit_value(self):
# input/test22.html
@@ -751,51 +794,52 @@ translated string</span>
<span tal:omit-tag="" i18n:name="country">the USA</span>.
</span>
''', [('setPosition', (1, 0)),
- ('beginScope', {'i18n:translate': ''}),
- ('startTag', ('span', [('i18n:translate', '', 'i18n')])),
- ('insertTranslation',
- ('',
- [('rawtextBeginScope',
- ('\n ', 2, (2, 2), 0, {'i18n:name': 'name', 'tal:omit-tag': ''})),
- ('i18nVariable',
- ('name',
- [('optTag',
- ('span',
- '',
- None,
- 0,
- [('startTag',
- ('span',
- [('tal:omit-tag', '', 'tal'),
- ('i18n:name', 'name', 'i18n')]))],
- [('rawtextOffset', ('<b>Jim</b>', 10))]))],
- None,
- 0)),
- ('rawtextBeginScope',
- (' was born in\n ',
- 2,
- (3, 2),
- 1,
- {'i18n:name': 'country', 'tal:omit-tag': ''})),
- ('i18nVariable',
- ('country',
- [('optTag',
- ('span',
- '',
- None,
- 0,
- [('startTag',
- ('span',
- [('tal:omit-tag', '', 'tal'),
- ('i18n:name', 'country', 'i18n')]))],
- [('rawtextOffset', ('the USA', 7))]))],
- None,
- 0)),
- ('endScope', ()),
- ('rawtextColumn', ('.\n', 0))])),
- ('endScope', ()),
- ('rawtextColumn', ('</span>\n', 0))
- ])
+ ('beginScope', {'i18n:translate': ''}),
+ ('startTag', ('span', [('i18n:translate', '', 'i18n')])),
+ ('insertTranslation',
+ ('',
+ [('rawtextBeginScope',
+ ('\n ', 2, (2, 2), 0,
+ {'i18n:name': 'name', 'tal:omit-tag': ''})),
+ ('i18nVariable',
+ ('name',
+ [('optTag',
+ ('span',
+ '',
+ None,
+ 0,
+ [('startTag',
+ ('span',
+ [('tal:omit-tag', '', 'tal'),
+ ('i18n:name', 'name', 'i18n')]))],
+ [('rawtextOffset', ('<b>Jim</b>', 10))]))],
+ None,
+ 0)),
+ ('rawtextBeginScope',
+ (' was born in\n ',
+ 2,
+ (3, 2),
+ 1,
+ {'i18n:name': 'country', 'tal:omit-tag': ''})),
+ ('i18nVariable',
+ ('country',
+ [('optTag',
+ ('span',
+ '',
+ None,
+ 0,
+ [('startTag',
+ ('span',
+ [('tal:omit-tag', '', 'tal'),
+ ('i18n:name', 'country', 'i18n')]))],
+ [('rawtextOffset', ('the USA', 7))]))],
+ None,
+ 0)),
+ ('endScope', ()),
+ ('rawtextColumn', ('.\n', 0))])),
+ ('endScope', ()),
+ ('rawtextColumn', ('</span>\n', 0))
+ ])
def test_i18n_context_domain(self):
self._run_check("<span i18n:domain='mydomain'/>", [
@@ -806,7 +850,7 @@ translated string</span>
('startEndTag', ('span', [('i18n:domain', 'mydomain', 'i18n')])),
('endScope', ()),
('endI18nContext', ()),
- ])
+ ])
def test_i18n_context_source(self):
self._run_check("<span i18n:source='en'/>", [
@@ -817,7 +861,7 @@ translated string</span>
('startEndTag', ('span', [('i18n:source', 'en', 'i18n')])),
('endScope', ()),
('endI18nContext', ()),
- ])
+ ])
def test_i18n_context_source_target(self):
self._run_check("<span i18n:source='en' i18n:target='ru'/>", [
@@ -829,7 +873,7 @@ translated string</span>
('i18n:target', 'ru', 'i18n')])),
('endScope', ()),
('endI18nContext', ()),
- ])
+ ])
def test_i18n_context_in_define_slot(self):
text = ("<div metal:use-macro='M' i18n:domain='mydomain'>"
@@ -856,7 +900,7 @@ translated string</span>
('endScope', ()),
rawtext('</div>'),
('endI18nContext', ())])),
- ])
+ ])
def test_i18n_data(self):
# input/test23.html
@@ -864,18 +908,20 @@ translated string</span>
<span i18n:data="here/currentTime"
i18n:translate="timefmt">2:32 pm</span>
''', [
- ('setPosition', (1, 0)),
- ('beginScope',
- {'i18n:translate': 'timefmt', 'i18n:data': 'here/currentTime'}),
- ('startTag',
- ('span',
- [('i18n:data', 'here/currentTime', 'i18n'),
- ('i18n:translate', 'timefmt', 'i18n')])),
- ('insertTranslation',
- ('timefmt', [('rawtextOffset', ('2:32 pm', 7))], '$here/currentTime$')),
- ('endScope', ()),
- ('rawtextColumn', ('</span>\n', 0))
- ])
+ ('setPosition', (1, 0)),
+ ('beginScope',
+ {'i18n:translate': 'timefmt', 'i18n:data': 'here/currentTime'}),
+ ('startTag',
+ ('span',
+ [('i18n:data', 'here/currentTime', 'i18n'),
+ ('i18n:translate', 'timefmt', 'i18n')])),
+ ('insertTranslation',
+ ('timefmt',
+ [('rawtextOffset', ('2:32 pm', 7))],
+ '$here/currentTime$')),
+ ('endScope', ()),
+ ('rawtextColumn', ('</span>\n', 0))
+ ])
def test_i18n_data_with_name(self):
# input/test29.html
@@ -885,37 +931,37 @@ translated string</span>
i18n:translate="timefmt"
i18n:name="time">2:32 pm</span>... beep!</div>
''', [('setPosition', (1, 0)),
- ('beginScope', {'i18n:translate': ''}),
- ('startTag', ('div', [('i18n:translate', '', 'i18n')])),
- ('insertTranslation',
- ('',
- [('rawtextBeginScope',
- ('At the tone the time will be\n',
- 0,
- (2, 0),
- 0,
- {'i18n:data': 'here/currentTime',
- 'i18n:name': 'time',
- 'i18n:translate': 'timefmt'})),
- ('i18nVariable',
- ('time',
- [('startTag',
- ('span',
- [('i18n:data', 'here/currentTime', 'i18n'),
- ('i18n:translate', 'timefmt', 'i18n'),
- ('i18n:name', 'time', 'i18n')])),
- ('insertTranslation',
- ('timefmt',
- [('rawtextOffset', ('2:32 pm', 7))],
- '$here/currentTime$')),
- ('rawtextOffset', ('</span>', 7))],
- None,
- 0)),
- ('endScope', ()),
- ('rawtextOffset', ('... beep!', 9))])),
- ('endScope', ()),
- ('rawtextColumn', ('</div>\n', 0))
- ])
+ ('beginScope', {'i18n:translate': ''}),
+ ('startTag', ('div', [('i18n:translate', '', 'i18n')])),
+ ('insertTranslation',
+ ('',
+ [('rawtextBeginScope',
+ ('At the tone the time will be\n',
+ 0,
+ (2, 0),
+ 0,
+ {'i18n:data': 'here/currentTime',
+ 'i18n:name': 'time',
+ 'i18n:translate': 'timefmt'})),
+ ('i18nVariable',
+ ('time',
+ [('startTag',
+ ('span',
+ [('i18n:data', 'here/currentTime', 'i18n'),
+ ('i18n:translate', 'timefmt', 'i18n'),
+ ('i18n:name', 'time', 'i18n')])),
+ ('insertTranslation',
+ ('timefmt',
+ [('rawtextOffset', ('2:32 pm', 7))],
+ '$here/currentTime$')),
+ ('rawtextOffset', ('</span>', 7))],
+ None,
+ 0)),
+ ('endScope', ()),
+ ('rawtextOffset', ('... beep!', 9))])),
+ ('endScope', ()),
+ ('rawtextColumn', ('</div>\n', 0))
+ ])
def test_i18n_name_around_tal_content(self):
# input/test28.html
@@ -926,50 +972,50 @@ translated string</span>
tal:content="request/submitter">user@host.com</a></span>
</p>
''', [('setPosition', (1, 0)),
- ('beginScope', {'i18n:translate': 'verify'}),
- ('startTag', ('p', [('i18n:translate', 'verify', 'i18n')])),
- ('insertTranslation',
- ('verify',
- [('rawtextBeginScope',
- ('Your contact email address is recorded as\n ',
- 4,
- (2, 4),
- 0,
- {'i18n:name': 'email', 'tal:omit-tag': ''})),
- ('i18nVariable',
- ('email',
- [('optTag',
- ('span',
- '',
- None,
- 0,
- [('startTag',
- ('span',
- [('tal:omit-tag', '', 'tal'),
- ('i18n:name', 'email', 'i18n')]))],
- [('rawtextBeginScope',
- ('\n ',
- 4,
- (3, 4),
- 0,
- {'href': 'mailto:user@example.com',
- 'tal:content': 'request/submitter'})),
- ('startTag',
- ('a',
- [('href', 'href="mailto:user@example.com"'),
- ('tal:content', 'request/submitter', 'tal')])),
- ('insertText',
- ('$request/submitter$',
- [('rawtextOffset', ('user@host.com', 13))])),
- ('endScope', ()),
- ('rawtextOffset', ('</a>', 4))]))],
- None,
- 0)),
- ('endScope', ()),
- ('rawtextColumn', ('\n', 0))])),
- ('endScope', ()),
- ('rawtextColumn', ('</p>\n', 0))
- ])
+ ('beginScope', {'i18n:translate': 'verify'}),
+ ('startTag', ('p', [('i18n:translate', 'verify', 'i18n')])),
+ ('insertTranslation',
+ ('verify',
+ [('rawtextBeginScope',
+ ('Your contact email address is recorded as\n ',
+ 4,
+ (2, 4),
+ 0,
+ {'i18n:name': 'email', 'tal:omit-tag': ''})),
+ ('i18nVariable',
+ ('email',
+ [('optTag',
+ ('span',
+ '',
+ None,
+ 0,
+ [('startTag',
+ ('span',
+ [('tal:omit-tag', '', 'tal'),
+ ('i18n:name', 'email', 'i18n')]))],
+ [('rawtextBeginScope',
+ ('\n ',
+ 4,
+ (3, 4),
+ 0,
+ {'href': 'mailto:user@example.com',
+ 'tal:content': 'request/submitter'})),
+ ('startTag',
+ ('a',
+ [('href', 'href="mailto:user@example.com"'),
+ ('tal:content', 'request/submitter', 'tal')])),
+ ('insertText',
+ ('$request/submitter$',
+ [('rawtextOffset', ('user@host.com', 13))])),
+ ('endScope', ()),
+ ('rawtextOffset', ('</a>', 4))]))],
+ None,
+ 0)),
+ ('endScope', ()),
+ ('rawtextColumn', ('\n', 0))])),
+ ('endScope', ()),
+ ('rawtextColumn', ('</p>\n', 0))
+ ])
def test_i18n_name_with_tal_content(self):
# input/test27.html
@@ -980,37 +1026,37 @@ translated string</span>
i18n:name="email">user@host.com</a>
</p>
''', [
- ('setPosition', (1, 0)),
- ('beginScope', {'i18n:translate': 'verify'}),
- ('startTag', ('p', [('i18n:translate', 'verify', 'i18n')])),
- ('insertTranslation',
- ('verify',
- [('rawtextBeginScope',
- ('Your contact email address is recorded as\n ',
- 4,
- (2, 4),
- 0,
- {'href': 'mailto:user@example.com',
- 'i18n:name': 'email',
- 'tal:content': 'request/submitter'})),
- ('i18nVariable',
- ('email',
- [('startTag',
- ('a',
- [('href', 'href="mailto:user@example.com"'),
- ('tal:content', 'request/submitter', 'tal'),
- ('i18n:name', 'email', 'i18n')])),
- ('insertText',
- ('$request/submitter$',
- [('rawtextOffset', ('user@host.com', 13))])),
- ('rawtextOffset', ('</a>', 4))],
- None,
- 0)),
- ('endScope', ()),
- ('rawtextColumn', ('\n', 0))])),
- ('endScope', ()),
- ('rawtextColumn', ('</p>\n', 0))
- ])
+ ('setPosition', (1, 0)),
+ ('beginScope', {'i18n:translate': 'verify'}),
+ ('startTag', ('p', [('i18n:translate', 'verify', 'i18n')])),
+ ('insertTranslation',
+ ('verify',
+ [('rawtextBeginScope',
+ ('Your contact email address is recorded as\n ',
+ 4,
+ (2, 4),
+ 0,
+ {'href': 'mailto:user@example.com',
+ 'i18n:name': 'email',
+ 'tal:content': 'request/submitter'})),
+ ('i18nVariable',
+ ('email',
+ [('startTag',
+ ('a',
+ [('href', 'href="mailto:user@example.com"'),
+ ('tal:content', 'request/submitter', 'tal'),
+ ('i18n:name', 'email', 'i18n')])),
+ ('insertText',
+ ('$request/submitter$',
+ [('rawtextOffset', ('user@host.com', 13))])),
+ ('rawtextOffset', ('</a>', 4))],
+ None,
+ 0)),
+ ('endScope', ()),
+ ('rawtextColumn', ('\n', 0))])),
+ ('endScope', ()),
+ ('rawtextColumn', ('</p>\n', 0))
+ ])
def test_suite():
diff --git a/src/zope/tal/tests/test_sourcepos.py b/src/zope/tal/tests/test_sourcepos.py
index c397194..bcbd909 100644
--- a/src/zope/tal/tests/test_sourcepos.py
+++ b/src/zope/tal/tests/test_sourcepos.py
@@ -59,7 +59,6 @@ main_template=main_template (6,14)
</body></html>'''
-
class SourcePosTestCase(unittest.TestCase):
def parse(self, eng, s, fn):
diff --git a/src/zope/tal/tests/test_talgettext.py b/src/zope/tal/tests/test_talgettext.py
index 1e3b3f9..1559e83 100644
--- a/src/zope/tal/tests/test_talgettext.py
+++ b/src/zope/tal/tests/test_talgettext.py
@@ -31,6 +31,7 @@ from zope.tal.htmltalparser import HTMLTALParser
from zope.tal.talgettext import POTALInterpreter
from zope.tal.talgettext import POEngine
+
class test_POEngine(unittest.TestCase):
"""Test the PO engine functionality, which simply adds items to a catalog
as .translate is called
diff --git a/src/zope/tal/tests/test_talinterpreter.py b/src/zope/tal/tests/test_talinterpreter.py
index dd6b4df..26c35cf 100644
--- a/src/zope/tal/tests/test_talinterpreter.py
+++ b/src/zope/tal/tests/test_talinterpreter.py
@@ -135,13 +135,19 @@ class I18NCornerTestCaseMessage(TestCaseBase):
interpreter = None
def factory(self, msgid, default=None, mapping=None, domain=None):
- return Message(msgid, domain=domain, default=default, mapping=mapping or {})
+ return Message(
+ msgid,
+ domain=domain,
+ default=default,
+ mapping=mapping or {})
def setUp(self):
self.engine = DummyEngine()
# Make sure we'll translate the msgid not its unicode representation
- self.engine.setLocal('foo',
- self.factory('FoOvAlUe${empty}', 'default', {'empty': ''}))
+ self.engine.setLocal(
+ 'foo', self.factory(
+ 'FoOvAlUe${empty}', 'default', {
+ 'empty': ''}))
self.engine.setLocal('bar', 'BaRvAlUe')
def _check(self, program, expected):
@@ -336,7 +342,9 @@ class I18NCornerTestCaseMessage(TestCaseBase):
[('rawtextOffset', ('This is text for ', 17)),
('setPosition', (1, 40)),
('beginScope',
- {'tal:content': 'bar', 'i18n:name': 'bar_name', 'i18n:translate': ''}),
+ {'tal:content': 'bar',
+ 'i18n:name': 'bar_name',
+ 'i18n:translate': ''}),
('i18nVariable',
('bar_name',
[('startTag',
@@ -361,10 +369,10 @@ class I18NCornerTestCaseMessage(TestCaseBase):
def test_for_correct_msgids(self):
self.engine.translationDomain.clearMsgids()
result = StringIO()
- #GChapelle:
- #I have the feeling the i18n:translate with the i18n:name is wrong
+ # GChapelle:
+ # I have the feeling the i18n:translate with the i18n:name is wrong
#
- #program, macros = self._compile(
+ # program, macros = self._compile(
# '<div i18n:translate="">This is text for '
# '<span i18n:translate="" tal:content="bar" '
# 'i18n:name="bar_name"/>.</div>')
@@ -375,8 +383,7 @@ class I18NCornerTestCaseMessage(TestCaseBase):
self.interpreter = TALInterpreter(program, {}, self.engine,
stream=result)
self.interpreter()
- msgids = self.engine.translationDomain.getMsgids('default')
- msgids.sort()
+ msgids = sorted(self.engine.translationDomain.getMsgids('default'))
self.assertEqual(1, len(msgids))
self.assertEqual('This is text for ${bar_name}.', msgids[0][0])
self.assertEqual({'bar_name': '<span>BaRvAlUe</span>'}, msgids[0][1])
@@ -394,8 +401,7 @@ class I18NCornerTestCaseMessage(TestCaseBase):
self.interpreter = TALInterpreter(program, {}, self.engine,
stream=result)
self.interpreter()
- msgids = self.engine.translationDomain.getMsgids('default')
- msgids.sort()
+ msgids = sorted(self.engine.translationDomain.getMsgids('default'))
self.assertEqual(2, len(msgids))
self.assertEqual('This is text for ${bar_name}.', msgids[1][0])
self.assertEqual({'bar_name': '<span>BARVALUE</span>'}, msgids[1][1])
@@ -415,8 +421,7 @@ class I18NCornerTestCaseMessage(TestCaseBase):
self.interpreter = TALInterpreter(program, {}, self.engine,
stream=result)
self.interpreter()
- msgids = self.engine.translationDomain.getMsgids('default')
- msgids.sort()
+ msgids = sorted(self.engine.translationDomain.getMsgids('default'))
self.assertEqual(2, len(msgids))
self.assertEqual('Some static text and a ${link}.', msgids[0][0])
self.assertEqual({'link': '<a href="url">LINK TEXT</a>'}, msgids[0][1])
@@ -439,8 +444,7 @@ class I18NCornerTestCaseMessage(TestCaseBase):
self.interpreter = TALInterpreter(program, {}, self.engine,
stream=result)
self.interpreter()
- msgids = self.engine.translationDomain.getMsgids('default')
- msgids.sort()
+ msgids = sorted(self.engine.translationDomain.getMsgids('default'))
self.assertEqual(2, len(msgids))
self.assertEqual(' This is text\n <b>\tfor</b>\n pre. ', msgids[0][0])
self.assertEqual('This is text for div.', msgids[1][0])
@@ -480,8 +484,7 @@ class I18NCornerTestCaseMessage(TestCaseBase):
self.interpreter = TALInterpreter(program, {}, self.engine,
stream=result)
self.interpreter()
- msgids = self.engine.translationDomain.getMsgids('default')
- msgids.sort()
+ msgids = sorted(self.engine.translationDomain.getMsgids('default'))
self.assertEqual(2, len(msgids))
self.assertEqual(' \tbar\n ', msgids[0][0])
self.assertEqual('This is text for ${bar}.', msgids[1][0])
@@ -505,16 +508,23 @@ class UnusedExplicitDomainTestCase(I18NCornerTestCaseMessage):
# MultipleDomainsDummyEngine is a Engine
# where default domain transforms to uppercase
self.engine = MultipleDomainsDummyEngine()
- self.engine.setLocal('foo',
- self.factory('FoOvAlUe${empty}', 'default', {'empty': ''}))
+ self.engine.setLocal(
+ 'foo', self.factory(
+ 'FoOvAlUe${empty}', 'default', {
+ 'empty': ''}))
self.engine.setLocal('bar', 'BaRvAlUe')
self.engine.setLocal('baz',
self.factory('BaZvAlUe', 'default', {}))
# Message ids with different domains
self.engine.setLocal('toupper',
self.factory('ToUpper', 'default', {}))
- self.engine.setLocal('tolower',
- self.factory('ToLower', 'default', {}, domain='lower'))
+ self.engine.setLocal(
+ 'tolower',
+ self.factory(
+ 'ToLower',
+ 'default',
+ {},
+ domain='lower'))
def test_multiple_domains(self):
program, _macros = self._compile(
@@ -547,31 +557,33 @@ class UnusedExplicitDomainTestCase(I18NCornerTestCaseMessage):
self._check(program, '<div>tolower</div>')
def test_unused_explicit_domain(self):
- #a_very_explicit_domain_setup_by_template_developer_that_wont_be_taken_into_account_by_the_ZPT_engine
- #is a domain that transforms to lowercase
+ # a_very_explicit_domain_setup_by_template_developer_that_wont_be_taken_into_account_by_the_ZPT_engine
+ # is a domain that transforms to lowercase
self.engine.setLocal(
'othertolower',
- self.factory('OtherToLower',
- 'a_very_explicit_domain_setup_by_template_developer_that_wont_be_taken_into_account_by_the_ZPT_engine',
- {},
- domain='lower'))
+ self.factory(
+ 'OtherToLower',
+ 'a_very_explicit_domain_setup_by_template_developer_that_wont_be_taken_into_account_by_the_ZPT_engine', # noqa: E501 line too long
+ {},
+ domain='lower'))
program, _macros = self._compile(
'<div i18n:translate=""'
' tal:content="othertolower" />')
self._check(program, '<div>othertolower</div>')
- #takes domain into account for strings
+ # takes domain into account for strings
program, _macros = self._compile(
'<div i18n:translate=""'
- ' i18n:domain="a_very_explicit_domain_setup_by_template_developer_that_wont_be_taken_into_account_by_the_ZPT_engine"'
+ ' i18n:domain="a_very_explicit_domain_setup_by_template_developer_that_wont_be_taken_into_account_by_the_ZPT_engine"' # noqa: E501 line too long
' tal:content="string:ToLower" />')
self._check(program, '<div>tolower</div>')
- #but not for messageids
+ # but not for messageids
program, _macros = self._compile(
'<div i18n:translate=""'
- ' i18n:domain="a_very_explicit_domain_setup_by_template_developer_that_wont_be_taken_into_account_by_the_ZPT_engine"'
+ ' i18n:domain="a_very_explicit_domain_setup_by_template_developer_that_wont_be_taken_into_account_by_the_ZPT_engine"' # noqa: E501 line too long
' tal:content="baz" />')
self._check(program, '<div>BAZVALUE</div>')
+
class ScriptTestCase(TestCaseBase):
interpreter = None
@@ -677,6 +689,7 @@ class I18NErrorsTestCase(TestCaseBase):
"expected attribute being both part of tal:attributes" +
" and having a msgid in i18n:attributes to be denied")
+
class OutputPresentationTestCase(TestCaseBase):
def test_attribute_wrapping(self):
@@ -854,6 +867,5 @@ class TestErrorTracebacks(TestCaseBase):
self.assertEqual(engine.position, (5, 14))
-
def test_suite():
return unittest.defaultTestLoader.loadTestsFromName(__name__)
diff --git a/src/zope/tal/tests/test_xmlparser.py b/src/zope/tal/tests/test_xmlparser.py
index 5d66ff9..437d68f 100644
--- a/src/zope/tal/tests/test_xmlparser.py
+++ b/src/zope/tal/tests/test_xmlparser.py
@@ -96,6 +96,7 @@ class SegmentedFile(object):
s = b''
return s
+
@unittest.skipIf(utils.skipxml, "Skip XML defined")
class XMLParserTestCase(unittest.TestCase):
@@ -121,7 +122,7 @@ class XMLParserTestCase(unittest.TestCase):
("pi", "processing", "instruction"),
("starttag", "a", []),
("endtag", "a"),
- ])
+ ])
def _check_simple_html(self):
self._run_check("""\
@@ -136,20 +137,21 @@ text
<!--comment2a- -comment2b-->
</html>
""", [
- ("decl", "1.0", "iso-8859-1", -1),
- ("doctype", "html", "foo", "bar", 0),
- ("starttag", "html", []),
- # ("entityref", "entity"),
- ("data", " \n"),
- ("comment", "comment1a\n-></foo><bar>&lt;<?pi?></foo<bar\ncomment1b"),
- ("data", "\n"),
- ("starttag", "img", ["src", "Bar", "ismap", ""]),
- ("endtag", "img"),
- ("data", "sample\ntext\n"),
- ("comment", "comment2a- -comment2b"),
- ("data", "\n"),
- ("endtag", "html"),
- ])
+ ("decl", "1.0", "iso-8859-1", -1),
+ ("doctype", "html", "foo", "bar", 0),
+ ("starttag", "html", []),
+ # ("entityref", "entity"),
+ ("data", " \n"),
+ ("comment",
+ "comment1a\n-></foo><bar>&lt;<?pi?></foo<bar\ncomment1b"),
+ ("data", "\n"),
+ ("starttag", "img", ["src", "Bar", "ismap", ""]),
+ ("endtag", "img"),
+ ("data", "sample\ntext\n"),
+ ("comment", "comment2a- -comment2b"),
+ ("data", "\n"),
+ ("endtag", "html"),
+ ])
def test_bad_nesting(self):
with self.assertRaises(Exception) as e:
@@ -158,7 +160,7 @@ text
("starttag", "b", []),
("endtag", "a"),
("endtag", "b"),
- ])
+ ])
e = e.exception
self.assertEqual(e.lineno, 1,
@@ -181,34 +183,34 @@ text
"c", "yyy yyy",
"d", " xyz "]),
("endtag", "a"),
- ]
+ ]
)
self._run_check("""<a b='' c="" d=''/>""", [
("starttag", "a", ["b", "", "c", "", "d", ""]),
("endtag", "a"),
- ])
+ ])
def test_attr_entity_replacement(self):
self._run_check("""<a b='&amp;&gt;&lt;&quot;&apos;'/>""", [
("starttag", "a", ["b", "&><\"'"]),
("endtag", "a"),
- ])
+ ])
def test_attr_funky_names(self):
self._run_check("""<a a.b='v' e-f='v'/>""", [
("starttag", "a", ["a.b", "v", "e-f", "v"]),
("endtag", "a"),
- ])
+ ])
def test_starttag_end_boundary(self):
self._run_check("""<a b='&lt;'/>""", [
("starttag", "a", ["b", "<"]),
("endtag", "a"),
- ])
+ ])
self._run_check("""<a b='&gt;'/>""", [
("starttag", "a", ["b", ">"]),
("endtag", "a"),
- ])
+ ])
def test_buffer_artefacts(self):
output = [("starttag", "a", ["b", "<"]), ("endtag", "a")]
diff --git a/src/zope/tal/tests/utils.py b/src/zope/tal/tests/utils.py
index 384a756..b8d384d 100644
--- a/src/zope/tal/tests/utils.py
+++ b/src/zope/tal/tests/utils.py
@@ -13,6 +13,7 @@
##############################################################################
"""Helper functions for the test suite.
"""
+import unittest
import os
import sys
@@ -22,13 +23,11 @@ codedir = os.path.dirname(os.path.dirname(os.path.dirname(mydir)))
if codedir not in sys.path:
sys.path.append(codedir)
-import unittest
-
# Set skipxml to true if an XML parser could not be found.
skipxml = 0
try:
- import xml.parsers.expat
+ import xml.parsers.expat # noqa: F401 imported but unused
except ImportError:
skipxml = 1
@@ -39,15 +38,6 @@ def run_suite(suite, outf=None, errf=None):
runner = unittest.TextTestRunner(outf)
result = runner.run(suite)
-## print "\n\n"
-## if result.errors:
-## print "Errors (unexpected exceptions):"
-## map(print_error, result.errors)
-## print
-## if result.failures:
-## print "Failures (assertion failures):"
-## map(print_error, result.failures)
-## print
newerrs = len(result.errors) + len(result.failures)
if newerrs:
print("'Errors' indicate exceptions other than AssertionError.")
diff --git a/src/zope/tal/timer.py b/src/zope/tal/timer.py
index e4fad56..f64654f 100644
--- a/src/zope/tal/timer.py
+++ b/src/zope/tal/timer.py
@@ -41,6 +41,7 @@ def main():
it = timefunc(count, compilefile, file)
timefunc(count, interpretit, it, None, dummyfile)
+
def timefunc(count, func, *args):
sys.stderr.write("%-14s: " % func.__name__)
sys.stderr.flush()
@@ -49,8 +50,9 @@ def timefunc(count, func, *args):
result = func(*args)
t1 = time.clock()
sys.stderr.write("%6.3f secs for %d calls, i.e. %4.0f msecs per call\n"
- % ((t1-t0), count, 1000*(t1-t0)/count))
+ % ((t1 - t0), count, 1000 * (t1 - t0) / count))
return result
+
if __name__ == "__main__":
main()
diff --git a/src/zope/tal/translationcontext.py b/src/zope/tal/translationcontext.py
index 5aa68a2..e515628 100644
--- a/src/zope/tal/translationcontext.py
+++ b/src/zope/tal/translationcontext.py
@@ -18,6 +18,7 @@ needed to perform translation of a marked string from a page template.
"""
DEFAULT_DOMAIN = "default"
+
class TranslationContext(object):
"""Information about the I18N settings of a TAL processor."""
diff --git a/src/zope/tal/xmlparser.py b/src/zope/tal/xmlparser.py
index ca5c216..7ebee73 100644
--- a/src/zope/tal/xmlparser.py
+++ b/src/zope/tal/xmlparser.py
@@ -28,7 +28,7 @@ except ImportError:
try:
unicode
except NameError:
- unicode = str # Python 3.x
+ unicode = str # Python 3.x
class XMLParser(object):
@@ -59,7 +59,7 @@ class XMLParser(object):
"EndDoctypeDeclHandler",
"ElementDeclHandler",
"AttlistDeclHandler"
- ]
+ ]
def __init__(self, encoding=None):
self.parser = p = self.createParser(encoding)