diff options
author | Michael Howitz <mh@gocept.com> | 2021-05-27 14:20:23 +0200 |
---|---|---|
committer | Michael Howitz <mh@gocept.com> | 2021-05-28 08:03:35 +0200 |
commit | 0f8a8f11cb74b988e947fe20034a76ed1bc7f27e (patch) | |
tree | a267c937426eb4c832f9914b26136a649042eab0 | |
parent | 23529db8a317f3e3cf209349f154eccccbb37e7b (diff) | |
download | zope-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.rst | 4 | ||||
-rw-r--r-- | setup.py | 10 | ||||
-rw-r--r-- | src/zope/__init__.py | 2 | ||||
-rw-r--r-- | src/zope/tal/driver.py | 58 | ||||
-rw-r--r-- | src/zope/tal/dummyengine.py | 43 | ||||
-rw-r--r-- | src/zope/tal/htmltalparser.py | 19 | ||||
-rw-r--r-- | src/zope/tal/interfaces.py | 7 | ||||
-rw-r--r-- | src/zope/tal/runtest.py | 39 | ||||
-rw-r--r-- | src/zope/tal/taldefs.py | 26 | ||||
-rw-r--r-- | src/zope/tal/talgenerator.py | 40 | ||||
-rw-r--r-- | src/zope/tal/talgettext.py | 13 | ||||
-rw-r--r-- | src/zope/tal/talinterpreter.py | 67 | ||||
-rw-r--r-- | src/zope/tal/talparser.py | 10 | ||||
-rw-r--r-- | src/zope/tal/tests/markbench.py | 44 | ||||
-rw-r--r-- | src/zope/tal/tests/run.py | 4 | ||||
-rw-r--r-- | src/zope/tal/tests/test_files.py | 5 | ||||
-rw-r--r-- | src/zope/tal/tests/test_htmltalparser.py | 1130 | ||||
-rw-r--r-- | src/zope/tal/tests/test_sourcepos.py | 1 | ||||
-rw-r--r-- | src/zope/tal/tests/test_talgettext.py | 1 | ||||
-rw-r--r-- | src/zope/tal/tests/test_talinterpreter.py | 76 | ||||
-rw-r--r-- | src/zope/tal/tests/test_xmlparser.py | 46 | ||||
-rw-r--r-- | src/zope/tal/tests/utils.py | 14 | ||||
-rw-r--r-- | src/zope/tal/timer.py | 4 | ||||
-rw-r--r-- | src/zope/tal/translationcontext.py | 1 | ||||
-rw-r--r-- | src/zope/tal/xmlparser.py | 4 |
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) ================ @@ -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('"', '"') return s + def quote(s): - s = s.replace("&", "&") # Must be done first! + s = s.replace("&", "&") # Must be done first! s = s.replace("<", "<") s = s.replace(">", ">") s = s.replace('"', """) 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='&><"''>""", [ rawtext('<a b="&><"\'"></a>'), - ]) + ]) self._run_check("""<a b='\"'>""", [ rawtext('<a b="""></a>'), - ]) + ]) self._run_check("""<a b='&'>""", [ rawtext('<a b="&"></a>'), - ]) + ]) self._run_check("""<a b='<'>""", [ rawtext('<a b="<"></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(""" """, [ rawtext(' '), - ]) + ]) 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><<?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><<?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='&><"''/>""", [ ("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='<'/>""", [ ("starttag", "a", ["b", "<"]), ("endtag", "a"), - ]) + ]) self._run_check("""<a b='>'/>""", [ ("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) |