Hello community, here is the log from the commit of package python-Kajiki for openSUSE:Factory checked in at 2019-03-12 09:52:01 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-Kajiki (Old) and /work/SRC/openSUSE:Factory/.python-Kajiki.new.28833 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-Kajiki" Tue Mar 12 09:52:01 2019 rev:9 rq:681852 version:0.7.2 Changes: -------- --- /work/SRC/openSUSE:Factory/python-Kajiki/python-Kajiki.changes 2019-01-24 14:02:30.680113386 +0100 +++ /work/SRC/openSUSE:Factory/.python-Kajiki.new.28833/python-Kajiki.changes 2019-03-12 09:52:11.283552732 +0100 @@ -1,0 +2,8 @@ +Tue Mar 5 16:35:50 UTC 2019 - Tomáš Chvátal <[email protected]> + +- Update to 0.7.2: + * Allow to replace gettext function by providing it in the template context or through base_globals in Loader + * Improve parsing of ${} expressions and fix syntax errors reporting in braced expressions. + * Improve parsing of documents with comments before the root element + +------------------------------------------------------------------- Old: ---- Kajiki-0.7.0.tar.gz New: ---- Kajiki-0.7.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-Kajiki.spec ++++++ --- /var/tmp/diff_new_pack.tb9RpI/_old 2019-03-12 09:52:11.867552616 +0100 +++ /var/tmp/diff_new_pack.tb9RpI/_new 2019-03-12 09:52:11.867552616 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-Kajiki # -# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,16 +18,18 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-Kajiki -Version: 0.7.0 +Version: 0.7.2 Release: 0 Summary: Compiler for Genshi syntax outputting Python bytecode License: MIT Group: Development/Languages/Python -URL: http://sourceforge.net/p/kajiki/home/ +URL: https://github.com/nandoflorestan/kajiki Source: https://files.pythonhosted.org/packages/source/K/Kajiki/Kajiki-%{version}.tar.gz BuildRequires: %{python_module Babel} BuildRequires: %{python_module nine} +BuildRequires: %{python_module nose} BuildRequires: %{python_module setuptools} +BuildRequires: fdupes BuildRequires: python-rpm-macros Requires: python-nine BuildArch: noarch @@ -47,6 +49,8 @@ %install %python_install +%python_expand rm -r %{buildroot}%{$python_sitelib}/kajiki/tests +%python_expand %fdupes %{buildroot}%{$python_sitelib} %check %python_exec setup.py test ++++++ Kajiki-0.7.0.tar.gz -> Kajiki-0.7.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Kajiki-0.7.0/CHANGES.rst new/Kajiki-0.7.2/CHANGES.rst --- old/Kajiki-0.7.0/CHANGES.rst 2017-06-27 12:11:50.000000000 +0200 +++ new/Kajiki-0.7.2/CHANGES.rst 2018-04-16 22:53:18.000000000 +0200 @@ -1,6 +1,17 @@ CHANGES ======= +0.7.2 (2018-04-16) +------------------ + +* Improve parsing of ``${}`` expressions and fix syntax errors reporting in braced expressions. +* Improve parsing of documents with comments before the root element + +0.7.1 (2017-09-11) +------------------ + +* Allow to replace ``gettext`` function by providing it in the template context or through ``base_globals`` in Loader + 0.7.0 (2017-06-27) ------------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Kajiki-0.7.0/Kajiki.egg-info/PKG-INFO new/Kajiki-0.7.2/Kajiki.egg-info/PKG-INFO --- old/Kajiki-0.7.0/Kajiki.egg-info/PKG-INFO 2017-06-27 12:42:59.000000000 +0200 +++ new/Kajiki-0.7.2/Kajiki.egg-info/PKG-INFO 2018-04-16 22:54:38.000000000 +0200 @@ -1,11 +1,12 @@ Metadata-Version: 1.1 Name: Kajiki -Version: 0.7.0 +Version: 0.7.2 Summary: Fast XML-based template engine with Genshi syntax and Jinja blocks Home-page: https://github.com/nandoflorestan/kajiki Author: Nando Florestan Author-email: [email protected] License: MIT +Description-Content-Type: UNKNOWN Description: Kajiki provides fast well-formed XML templates ============================================== @@ -78,6 +79,17 @@ CHANGES ======= + 0.7.2 (2018-04-16) + ------------------ + + * Improve parsing of ``${}`` expressions and fix syntax errors reporting in braced expressions. + * Improve parsing of documents with comments before the root element + + 0.7.1 (2017-09-11) + ------------------ + + * Allow to replace ``gettext`` function by providing it in the template context or through ``base_globals`` in Loader + 0.7.0 (2017-06-27) ------------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Kajiki-0.7.0/Kajiki.egg-info/SOURCES.txt new/Kajiki-0.7.2/Kajiki.egg-info/SOURCES.txt --- old/Kajiki-0.7.0/Kajiki.egg-info/SOURCES.txt 2017-06-27 12:42:59.000000000 +0200 +++ new/Kajiki-0.7.2/Kajiki.egg-info/SOURCES.txt 2018-04-16 22:54:38.000000000 +0200 @@ -60,4 +60,6 @@ kajiki/tests/data/debug.html kajiki/tests/data/debug.txt kajiki/tests/data/error.html +kajiki/tests/data/file_child.html +kajiki/tests/data/file_parent.html kajiki/tests/data/simple.html \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Kajiki-0.7.0/Kajiki.egg-info/requires.txt new/Kajiki-0.7.2/Kajiki.egg-info/requires.txt --- old/Kajiki-0.7.0/Kajiki.egg-info/requires.txt 2017-06-27 12:42:59.000000000 +0200 +++ new/Kajiki-0.7.2/Kajiki.egg-info/requires.txt 2018-04-16 22:54:38.000000000 +0200 @@ -2,4 +2,4 @@ [testing] babel -nose \ No newline at end of file +nose diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Kajiki-0.7.0/PKG-INFO new/Kajiki-0.7.2/PKG-INFO --- old/Kajiki-0.7.0/PKG-INFO 2017-06-27 12:42:59.000000000 +0200 +++ new/Kajiki-0.7.2/PKG-INFO 2018-04-16 22:54:38.000000000 +0200 @@ -1,11 +1,12 @@ Metadata-Version: 1.1 Name: Kajiki -Version: 0.7.0 +Version: 0.7.2 Summary: Fast XML-based template engine with Genshi syntax and Jinja blocks Home-page: https://github.com/nandoflorestan/kajiki Author: Nando Florestan Author-email: [email protected] License: MIT +Description-Content-Type: UNKNOWN Description: Kajiki provides fast well-formed XML templates ============================================== @@ -78,6 +79,17 @@ CHANGES ======= + 0.7.2 (2018-04-16) + ------------------ + + * Improve parsing of ``${}`` expressions and fix syntax errors reporting in braced expressions. + * Improve parsing of documents with comments before the root element + + 0.7.1 (2017-09-11) + ------------------ + + * Allow to replace ``gettext`` function by providing it in the template context or through ``base_globals`` in Loader + 0.7.0 (2017-06-27) ------------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Kajiki-0.7.0/docs/conf.py new/Kajiki-0.7.2/docs/conf.py --- old/Kajiki-0.7.0/docs/conf.py 2016-10-28 22:12:06.000000000 +0200 +++ new/Kajiki-0.7.2/docs/conf.py 2018-04-16 22:54:13.000000000 +0200 @@ -42,7 +42,7 @@ # General information about the project. project = u'Kajiki' -copyright = u'2010-2016, Rick Copeland, Nando Florestan and Alessandro Molina' +copyright = u'2010-2018, Rick Copeland, Nando Florestan and Alessandro Molina' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Kajiki-0.7.0/kajiki/i18n.py new/Kajiki-0.7.2/kajiki/i18n.py --- old/Kajiki-0.7.0/kajiki/i18n.py 2017-06-27 10:02:35.000000000 +0200 +++ new/Kajiki-0.7.2/kajiki/i18n.py 2018-04-16 19:00:57.000000000 +0200 @@ -43,4 +43,4 @@ keywords, comment_tags, options): yield (node.lineno, e[1], e[2], e[3]) except (TokenError, SyntaxError) as e: - raise KajikiSyntaxError(e, source, '<string>', node.lineno, 0) \ No newline at end of file + raise KajikiSyntaxError(e, source, '<string>', node.lineno, 0) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Kajiki-0.7.0/kajiki/template.py new/Kajiki-0.7.2/kajiki/template.py --- old/Kajiki-0.7.0/kajiki/template.py 2017-06-27 10:02:35.000000000 +0200 +++ new/Kajiki-0.7.2/kajiki/template.py 2017-09-11 13:50:13.000000000 +0200 @@ -64,11 +64,11 @@ context = {} self._context = context base_globals = self.base_globals or {} - self.__globals__ = dict(base_globals, local=self, self=self, + self.__globals__ = dict(local=self, self=self, defined=lambda x: x in self.__globals__, - literal=literal, Markup=literal, _=i18n.gettext, + literal=literal, Markup=literal, gettext=i18n.gettext, __builtins__=__builtins__, __kj__=kajiki) - self.__globals__['value_of'] = self.__globals__.get + self.__globals__.update(base_globals) for k, v in self.__methods__: v = v.bind_instance(self) setattr(self, k, v) @@ -80,7 +80,7 @@ case=self._case, import_=self._import, escape=self._escape, - gettext=i18n.gettext, + gettext=self._gettext, render_attrs=self._render_attrs, push_with=self._push_with, pop_with=self._pop_with, @@ -89,6 +89,8 @@ self._switch_stack = [] self._with_stack = [] self.__globals__.update(context) + self.__globals__['_'] = self.__globals__['gettext'] + self.__globals__['value_of'] = self.__globals__.get def __iter__(self): """We convert the chunk to string because it can be of any type @@ -102,6 +104,10 @@ """Render the template to a string.""" return ''.join(self) + def _gettext(self, s): + """Used by the code generated by the template to translate static text""" + return self.__globals__['gettext'](s) + def _push_with(self, locals_, vars): """Enter a ``py:with`` block. @@ -122,6 +128,11 @@ return self._with_stack.pop() def _extend(self, parent): + """ + Called when a child template extends a parent template + the first thing it does is asking the loader of the + child template to load the parent template + """ if isinstance(parent, basestring): parent = self.loader.import_(parent) p_inst = parent(self._context) @@ -279,13 +290,18 @@ return type(ns.__name__, (_Template,), dct) -def from_ir(ir_node): +def from_ir(ir_node, base_globals=None): """Creates a template class from Intermediate Representation TemplateNode. This actually creates the class defined by the TemplateNode by executing its code and returns a subclass of it. The returned class is a subclass of :class:`kajiki.template._Template`. + + It is possible to use `base_globals` to set context values + or replace default ones """ + if base_globals is None: + base_globals = dict() py_lines = list(generate_python(ir_node)) py_text = '\n'.join(map(str, py_lines)) py_linenos = [] @@ -300,7 +316,8 @@ except (SyntaxError, IndentationError) as e: # pragma no cover raise KajikiSyntaxError(e.msg, py_text, e.filename, e.lineno, e.offset) tpl = dct['template'] - tpl.base_globals = dct + tpl.base_globals = base_globals.copy() + tpl.base_globals.update(dct) tpl.py_text = py_text tpl.filename = ir_node.filename tpl.annotate_lnotab(py_linenos) @@ -438,4 +455,4 @@ try: return source.splitlines()[linen] except: - return '' \ No newline at end of file + return '' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Kajiki-0.7.0/kajiki/tests/data/file_child.html new/Kajiki-0.7.2/kajiki/tests/data/file_child.html --- old/Kajiki-0.7.0/kajiki/tests/data/file_child.html 1970-01-01 01:00:00.000000000 +0100 +++ new/Kajiki-0.7.2/kajiki/tests/data/file_child.html 2017-09-11 13:50:13.000000000 +0200 @@ -0,0 +1 @@ +<py:extends href="file_parent.html"><div>child</div></py:extends> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Kajiki-0.7.0/kajiki/tests/data/file_parent.html new/Kajiki-0.7.2/kajiki/tests/data/file_parent.html --- old/Kajiki-0.7.0/kajiki/tests/data/file_parent.html 1970-01-01 01:00:00.000000000 +0100 +++ new/Kajiki-0.7.2/kajiki/tests/data/file_parent.html 2017-09-11 13:50:13.000000000 +0200 @@ -0,0 +1 @@ +<div>parent</div> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Kajiki-0.7.0/kajiki/tests/test_xml.py new/Kajiki-0.7.2/kajiki/tests/test_xml.py --- old/Kajiki-0.7.0/kajiki/tests/test_xml.py 2017-06-27 10:14:59.000000000 +0200 +++ new/Kajiki-0.7.2/kajiki/tests/test_xml.py 2018-04-16 22:29:29.000000000 +0200 @@ -9,6 +9,7 @@ import xml.dom.minidom from io import BytesIO from unittest import TestCase, main +from nose import SkipTest from kajiki import i18n from kajiki.template import KajikiSyntaxError @@ -16,7 +17,7 @@ import kajiki from kajiki import MockLoader, XMLTemplate, FileLoader, PackageLoader from kajiki.ir import TranslatableTextNode -from kajiki.xml_template import _Compiler, _Parser, XMLTemplateCompileError +from kajiki.xml_template import _Compiler, _Parser, XMLTemplateCompileError, XMLTemplateParseError DATA = os.path.join(os.path.dirname(__file__), 'data') @@ -182,6 +183,15 @@ 'age': 26}['name']}</div>""", '<div>Hello, Rick</div>') + def test_expr_multiline_and_IndentationError(self): + try: + XMLTemplate("""<div>Hello, ${ 'pippo' + + 'baudo'}</div>""")().render() + except XMLTemplateCompileError as e: + assert "`'pippo' +\n 'baudo'`" in str(e), str(e) + assert 'Hello' in str(e) + assert 'baudo' in str(e) + def test_expr_multiline_cdata(self): perform("""<script><![CDATA[Hello, ${{'name': 'Rick', 'age': 26}['name']}]]></script>""", @@ -872,16 +882,57 @@ i18n.gettext = default_gettext def test_extract_python_inside_invalid(self): - src = '''<xml><div>${_('hi' +}</div></xml>''' + src = '''<xml><div>${_('hi' +)}</div></xml>''' try: x = list(i18n.extract(BytesIO(src.encode('utf-8')), [], None, { 'extract_python': True })) - except KajikiSyntaxError as e: - assert "${_('hi' +" in str(e) + except XMLTemplateCompileError as e: + assert "_('hi' +)" in str(e) else: assert False, 'Should have raised' + def test_substituting_gettext_with_lambda(self): + src = '''<xml>hi</xml>''' + expected = '''<xml>spam</xml>''' + + perform(src, expected, context=dict(gettext=lambda x: 'spam')) + + def test_substituting_gettext_with_lambda_extending(self): + gettext = lambda x: 'egg' + loader = MockLoader({ + 'parent.html': XMLTemplate('''<div>parent</div>'''), + 'child.html': XMLTemplate('''<py:extends href="parent.html"><div>child</div></py:extends>''')}) + tpl = loader.import_('child.html') + rsp = tpl(dict(gettext=gettext)).render() + assert rsp == '''<div>egg</div><div>egg</div>''', rsp + + def test_substituting_gettext_with_lambda_extending_twice(self): + gettext = lambda x: 'egg' + loader = MockLoader({ + 'parent.html': XMLTemplate('''<div>parent</div>'''), + 'mid.html': XMLTemplate('''<py:extends href="parent.html"><div>${variable}</div></py:extends>'''), + 'child.html': XMLTemplate('''<py:extends href="mid.html"><div>child</div></py:extends>''')}) + tpl = loader.import_('child.html') + rsp = tpl(dict(variable='spam', gettext=gettext)).render() + # variables must not be translated + assert rsp == '''<div>egg</div><div>spam</div><div>egg</div>''', rsp + + def test_substituting_gettext_with_lambda_extending_file(self): + loader = FileLoader(path=os.path.join(os.path.dirname(__file__), + 'data'), base_globals=dict(gettext=lambda x: 'egg')) + tpl = loader.import_('file_child.html') + rsp = tpl(dict()).render() + assert rsp == '''<div>egg</div><div>egg</div>''', rsp + + def test_without_substituting_gettext_with_lambda_extending_file(self): + # this should use i18n.gettext + loader = FileLoader(path=os.path.join(os.path.dirname(__file__), + 'data')) + tpl = loader.import_('file_child.html') + rsp = tpl(dict()).render() + assert rsp == '''<div>parent</div><div>child</div>''', rsp + class TestDOMTransformations(TestCase): def test_empty_text_extraction(self): @@ -927,5 +978,93 @@ assert False +class TestBracketsInExpression(TestCase): + def test_simple(self): + perform('<x>${\'ok\'}</x>', '<x>ok</x>') + + def test_some_brackets(self): + perform('<x>${\'{ok}\'}</x>', '<x>{ok}</x>') + + def test_brackets_asymmetric(self): + perform('<x>${\'{o{k}k { \'}</x>', '<x>{o{k}k { </x>') + + def test_complex(self): + perform(u"<xml><div>${'ciao { } {' + \"a {} b {{{{} w}}rar\"}${'sd{}'} ${1+1}</div></xml>", + u"<xml><div>ciao { } {a {} b {{{{} w}}rarsd{} 2</div></xml>") + + def test_with_padding_space(self): + perform('<x y="${ 1 + 1}"> ${ "hello" + "world" } </x>', + '<x y="2"> helloworld </x>') + + def test_raise_unclosed_string(self): + try: + XMLTemplate('<x>${"ciao}</x>') + assert False, 'must raise' + except XMLTemplateCompileError as e: + # assert "can't compile" in str(e), e # different between pypy and cpython + assert '"ciao' in str(e), e + + def test_raise_plus_with_an_operand(self): + try: + XMLTemplate('<x>${"ciao" + }</x>') + assert False, 'must raise' + except XMLTemplateCompileError as e: + assert 'detected an invalid python expression' in str(e), e + assert '"ciao" +' in str(e), e + + def test_unclosed_braced(self): + try: + XMLTemplate('<x>${"ciao"</x>') + assert False, 'must raise' + except XMLTemplateCompileError as e: + assert 'Braced expression not terminated' in str(e), e + + def test_leading_opening_brace(self): + if sys.version_info[:2] == (2, 6): + raise SkipTest('Python 2.6 compiler raises a different kind of error') + + try: + XMLTemplate('<x>${{"a", "b"}</x>') + assert False, 'must raise' + except XMLTemplateCompileError as e: + assert 'Braced expression not terminated' in str(e), e + + +class TestMultipleChildrenInDOM(TestCase): + def test_ok(self): + XMLTemplate('<xml><!-- a --><x>${1+1}</x></xml>') + + def test_comment(self): + res = XMLTemplate('<!-- a --><x>${1+1}</x>')().render() + assert res == '<x>2</x>' + + def test_multiple_nodes(self): + try: + XMLTemplate('<!-- a --><x>${1+1}</x><y>${1+1}</y>') + except XMLTemplateParseError as e: + assert 'junk after document element' in str(e), e + else: + assert False, 'should have raised' + + def test_only_comment(self): + try: + XMLTemplate('<!-- a -->') + except XMLTemplateParseError as e: + assert 'no element found' in str(e), e + else: + assert False, 'should have raised' + + +class TestSyntaxErrorCallingWithTrailingParenthesis(TestCase): + def test_raise(self): + try: + XMLTemplate(u'''<div py:strip="True" +><py:def function="echo(x)">$x</py:def +>${echo('hello'))}</div>''') + assert False, 'should raise' + except XMLTemplateCompileError as e: + pass + + if __name__ == '__main__': main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Kajiki-0.7.0/kajiki/version.py new/Kajiki-0.7.2/kajiki/version.py --- old/Kajiki-0.7.0/kajiki/version.py 2017-06-27 12:42:56.000000000 +0200 +++ new/Kajiki-0.7.2/kajiki/version.py 2018-04-16 22:53:36.000000000 +0200 @@ -2,5 +2,5 @@ from __future__ import (absolute_import, division, print_function, unicode_literals) -__version__ = '0.6' -__release__ = '0.7.0' +__version__ = '0.7' +__release__ = '0.7.2' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Kajiki-0.7.0/kajiki/xml_template.py new/Kajiki-0.7.2/kajiki/xml_template.py --- old/Kajiki-0.7.0/kajiki/xml_template.py 2017-05-28 14:43:48.000000000 +0200 +++ new/Kajiki-0.7.2/kajiki/xml_template.py 2018-04-16 22:29:55.000000000 +0200 @@ -29,7 +29,7 @@ def XMLTemplate(source=None, filename=None, mode=None, is_fragment=False, encoding='utf-8', autoblocks=None, cdata_scripts=True, - strip_text=False): + strip_text=False, base_globals=None): """Given XML source code of a Kajiki Templates parses and returns a template class. The source code is parsed to its DOM representation by :class:`._Parser`, @@ -53,7 +53,8 @@ doc = _DomTransformer(doc, strip_text=strip_text).transform() ir_ = _Compiler(filename, doc, mode=mode, is_fragment=is_fragment, autoblocks=autoblocks, cdata_scripts=cdata_scripts).compile() - return template.from_ir(ir_) + t = template.from_ir(ir_, base_globals=base_globals) + return t def annotate(gen): @@ -114,7 +115,12 @@ registries of the compiler ``compile`` should never be called twice or might lead to unexpected results. """ - body = list(self._compile_node(self.doc.firstChild)) + templateNodes = [n for n in self.doc.childNodes if not isinstance(n, dom.Comment)] + if len(templateNodes) != 1: + raise XMLTemplateCompileError('expected a single root node in document', + self.doc, self.filename, 0) + + body = list(self._compile_node(templateNodes[0])) # Never emit doctypes on fragments if not self.is_fragment and not self.is_child: if self.doc._dtd: @@ -218,7 +224,7 @@ yield ir.TextNode('<%s' % node.tagName, guard) for k, v in sorted(node.attributes.items()): tc = _TextCompiler(self.filename, v, node.lineno, - ir.TextNode, in_html_attr=True) + ir.TextNode, in_html_attr=True, compiler_instance=self) v = list(tc) if k == 'py:content': content = node.getAttribute('py:content') @@ -373,7 +379,7 @@ # script and style should always be untranslatable. kwargs['node_type'] = ir.TextNode - tc = _TextCompiler(self.filename, node.data, node.lineno, **kwargs) + tc = _TextCompiler(self.filename, node.data, node.lineno, compiler_instance=self, **kwargs) for x in tc: yield x @@ -465,7 +471,7 @@ instances and :class:`.ir.TextNode` instances accordingly. """ def __init__(self, filename, source, lineno, - node_type=make_text_node, in_html_attr=False): + node_type=make_text_node, in_html_attr=False, compiler_instance=None): self.filename = filename self.source = source self.orig_lineno = lineno @@ -473,6 +479,8 @@ self.pos = 0 self.node_type = node_type self.in_html_attr = in_html_attr + self.compiler_instance = compiler_instance + self.doc = self.compiler_instance.doc def text(self, text): node = self.node_type(text) @@ -524,15 +532,44 @@ yield self.text(source[self.pos:]) def _get_braced_expr(self): + # see https://github.com/nandoflorestan/kajiki/pull/38 + # Trying to get the position of a closing } in braced expressions + # So, self.source can be something like `1+1=${1+1} ahah` + # in this case this function gets called only once with self.pos equal to 6 + # this function must return the result of self.expr('1+1') and must set self.pos to 9 + def py_expr(end=None): + return self.source[self.pos:end] try: - compile(self.source[self.pos:], '', 'eval') + self.pos += len(py_expr()) - len(py_expr().lstrip()) + compile(py_expr(), 'find_}', 'eval') except SyntaxError as se: - end = self.pos + sum([se.offset] + [len(line) + 1 - for idx, line in enumerate(self.source[self.pos:].splitlines()) - if idx < se.lineno - 1]) - text = self.source[self.pos:end - 1] + end = sum( + [self.pos, se.offset] + + [len(line) + 1 + for idx, line in enumerate(py_expr().splitlines()) + if idx < se.lineno - 1] + ) + if py_expr(end)[-1] != '}': + # for example unclosed strings + raise XMLTemplateCompileError( + "Kajiki can't compile the python expression `%s`" % py_expr()[:-1], + doc=self.doc, filename=self.filename, linen=self.lineno) + else: + # if the expression ends in a } then it may be valid + try: + compile(py_expr(end-1), 'check_validity', 'eval') + except SyntaxError as se: + # for example + operators with a single operand + raise XMLTemplateCompileError( + "Kajiki detected an invalid python expression `%s`" % py_expr()[:-1], + doc=self.doc, filename=self.filename, linen=self.lineno) + + py_text = py_expr(end - 1) self.pos = end - return self.expr(text) + return self.expr(py_text) + else: + raise XMLTemplateCompileError("Braced expression not terminated", + doc=self.doc, filename=self.filename, linen=self.lineno) class _Parser(sax.ContentHandler): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Kajiki-0.7.0/setup.cfg new/Kajiki-0.7.2/setup.cfg --- old/Kajiki-0.7.0/setup.cfg 2017-06-27 12:42:59.000000000 +0200 +++ new/Kajiki-0.7.2/setup.cfg 2018-04-16 22:54:38.000000000 +0200 @@ -1,5 +1,4 @@ [egg_info] tag_build = tag_date = 0 -tag_svn_revision = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Kajiki-0.7.0/setup.py new/Kajiki-0.7.2/setup.py --- old/Kajiki-0.7.0/setup.py 2017-06-27 10:02:35.000000000 +0200 +++ new/Kajiki-0.7.2/setup.py 2018-04-16 19:00:57.000000000 +0200 @@ -70,7 +70,7 @@ extras_require = { 'testing': TEST_DEPENDENCIES, }, - test_suite='kajiki.tests', + test_suite='nose.collector', entry_points=""" [babel.extractors] kajiki = kajiki.i18n:extract
