Hello community, here is the log from the commit of package python-pybars3 for openSUSE:Factory checked in at 2020-03-20 23:55:07 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-pybars3 (Old) and /work/SRC/openSUSE:Factory/.python-pybars3.new.3160 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pybars3" Fri Mar 20 23:55:07 2020 rev:2 rq:786490 version:0.9.7 Changes: -------- --- /work/SRC/openSUSE:Factory/python-pybars3/python-pybars3.changes 2019-02-02 21:49:17.983978196 +0100 +++ /work/SRC/openSUSE:Factory/.python-pybars3.new.3160/python-pybars3.changes 2020-03-20 23:59:16.417017207 +0100 @@ -1,0 +2,7 @@ +Thu Mar 19 10:26:50 UTC 2020 - Marketa Calabkova <[email protected]> + +- Update to 0.9.7 + * Add support for whitespace control, `{{var~}}` (Handlebars 1.1) + * Add "list.length" support + +------------------------------------------------------------------- Old: ---- 0.9.6.tar.gz New: ---- 0.9.7.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-pybars3.spec ++++++ --- /var/tmp/diff_new_pack.zFnQqO/_old 2020-03-20 23:59:18.225018353 +0100 +++ /var/tmp/diff_new_pack.zFnQqO/_new 2020-03-20 23:59:18.237018361 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-pybars3 # -# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2020 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -12,23 +12,25 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# Please submit bugfixes or comments via https://bugs.opensuse.org/ +# + %define base_name pybars3 %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-%{base_name} -Version: 0.9.6 +Version: 0.9.7 Release: 0 -License: LGPL-3.0 Summary: Handlebarsjs templating for Python 3 and 2 -Url: https://github.com/wbond/%{base_name} +License: LGPL-3.0-only Group: Development/Languages/Python +URL: https://github.com/wbond/%{base_name} Source: https://github.com/wbond/%{base_name}/archive/%{version}.tar.gz -BuildRequires: python-rpm-macros -BuildRequires: %{python_module setuptools} BuildRequires: %{python_module PyMeta3 >= 0.5.1} +BuildRequires: %{python_module setuptools} BuildRequires: fdupes +BuildRequires: python-rpm-macros Requires: python-PyMeta3 >= 0.5.1 BuildArch: noarch ++++++ 0.9.6.tar.gz -> 0.9.7.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pybars3-0.9.6/.travis.yml new/pybars3-0.9.7/.travis.yml --- old/pybars3-0.9.6/.travis.yml 2018-10-10 21:14:39.000000000 +0200 +++ new/pybars3-0.9.7/.travis.yml 2019-11-05 10:37:13.000000000 +0100 @@ -10,12 +10,12 @@ python: - "2.7" - - "3.3" - "3.4" - "3.5" - - "3.5-dev" # 3.5 development branch - - "3.6-dev" # 3.6 development branch - - "nightly" # currently points to 3.7-dev + - "3.5" + - "3.6" + - "3.7" + - "nightly" - "pypy" install: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pybars3-0.9.6/MANIFEST.in new/pybars3-0.9.7/MANIFEST.in --- old/pybars3-0.9.6/MANIFEST.in 1970-01-01 01:00:00.000000000 +0100 +++ new/pybars3-0.9.7/MANIFEST.in 2019-11-05 10:37:13.000000000 +0100 @@ -0,0 +1,3 @@ +include LICENSE *.md +include tests.py +recursive-include tests *.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pybars3-0.9.6/changelog.md new/pybars3-0.9.7/changelog.md --- old/pybars3-0.9.6/changelog.md 2018-10-10 21:14:39.000000000 +0200 +++ new/pybars3-0.9.7/changelog.md 2019-11-05 10:37:13.000000000 +0100 @@ -1,5 +1,10 @@ # changelog +## 0.9.7 + +- Add support for whitespace control, `{{var~}}` (Handlebars 1.1) +- Add "list.length" support + ## 0.9.6 - Add `template` method which creates a renderer from precompiled code. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pybars3-0.9.6/pybars/__init__.py new/pybars3-0.9.7/pybars/__init__.py --- old/pybars3-0.9.6/pybars/__init__.py 2018-10-10 21:14:39.000000000 +0200 +++ new/pybars3-0.9.7/pybars/__init__.py 2019-11-05 10:37:13.000000000 +0100 @@ -34,8 +34,8 @@ PybarsError ) -__version__ = '0.9.6' -__version_info__ = (0, 9, 6, 'final', 0) +__version__ = '0.9.7' +__version_info__ = (0, 9, 7, 'final', 0) __all__ = [ 'Compiler', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pybars3-0.9.6/pybars/_compiler.py new/pybars3-0.9.7/pybars/_compiler.py --- old/pybars3-0.9.6/pybars/_compiler.py 2018-10-10 21:14:39.000000000 +0200 +++ new/pybars3-0.9.7/pybars/_compiler.py 2019-11-05 10:37:13.000000000 +0100 @@ -312,6 +312,8 @@ if segment in (None, ""): continue if type(context) in (list, tuple): + if segment == 'length': + return len(context) offset = int(segment) context = context[offset] elif isinstance(context, Scope): @@ -732,7 +734,7 @@ positional_args = 0 if arguments: for argument in arguments: - kwmatch = re.match('(\w+)=(.+)$', argument) + kwmatch = re.match(r'(\w+)=(.+)$', argument) if kwmatch: if not overrides: overrides = {} @@ -788,10 +790,10 @@ :return: The word """ - boundry = re.search('{{|{|\s|$', source[:position][::-1]) + boundry = re.search(r'{{|{|\s|$', source[:position][::-1]) start_offset = boundry.end() if boundry.group(0).startswith('{') else boundry.start() - boundry = re.search('}}|}|\s|$', source[position:]) + boundry = re.search(r'}}|}|\s|$', source[position:]) end_offset = boundry.end() if boundry.group(0).startswith('}') else boundry.start() return source[position - start_offset:position + end_offset] @@ -810,9 +812,9 @@ if not isinstance(source, str_class): raise PybarsError("Template source must be a unicode string") - tree, (position, _) = self._handlebars(source).apply('template') + source = self.whitespace_control(source) - self.clean_whitespace(tree) + tree, (position, _) = self._handlebars(source).apply('template') if debug: print('\nAST') @@ -836,6 +838,34 @@ output = self._compiler(tree).apply('compile')[0] return output + def whitespace_control(self, source): + """ + Preprocess source to handle whitespace control and remove extra block + whitespaces. + + :param source: + The template source as a unicode string + :return: + The processed template source as a unicode string + """ + cleanup_sub = re.compile( + # Clean-up whitespace control marks and spaces between blocks tags + r'(?<={{)~|~(?=}})|(?<=}})[ \t]+(?={{)').sub + + return re.sub( + # Whitespace control using "~" mark + r'~}}\s*|\s*{{~|' + + # Whitespace around alone blocks tags that in a line + r'(?<=\n)([ \t]*{{(#[^{}]+|/[^{}]+|![^{}]+|else|else if [^{}]+)}}[ \t]*)+\r?\n|' + + # Whitespace aroud alone blocks tag on the first line + r'^([ \t]*{{(#[^{}]+|![^{}]+)}}[ \t]*)+\r?\n|' + + # Whitespace aroud alone blocks tag on the last line + r'\r?\n([ \t]*{{(/[^{}]+|![^{}]+)}}[ \t]*)+$', + lambda match: cleanup_sub('', match.group(0).strip()), source) + def precompile(self, source): """ Generates python source code that can be saved to a file for caching @@ -874,8 +904,7 @@ path = path.replace('\\', '/') path = path.replace('/', '_') mod_name = make_module_name(path) - if mod_name in sys.modules: - generate_name = True + generate_name = mod_name in sys.modules if generate_name: mod_name = make_module_name(path, self.template_counter) @@ -902,84 +931,3 @@ exec(code + '\nresult = render(context, helpers=helpers, partials=partials, root=root)', ns) return ns['result'] return _render - - def clean_whitespace(self, tree): - """ - Cleans up whitespace around block open and close tags if they are the - only thing on the line - - :param tree: - The AST - will be modified in place - """ - - pointer = 0 - end = len(tree) - - while pointer < end: - piece = tree[pointer] - if piece[0] == 'block': - child_tree = piece[3] - - # Look at open tag, if the only other thing on the line is whitespace - # then delete it so we don't introduce extra newlines to the output - open_pre_whitespace = False - open_pre_content = True - if pointer > 1 and tree[pointer - 1][0] == 'whitespace' and (tree[pointer - 2][0] == 'newline' or tree[pointer - 2] == 'template'): - open_pre_whitespace = True - open_pre_content = False - elif pointer > 0 and (tree[pointer - 1][0] == 'newline' or tree[pointer - 1] == 'template'): - open_pre_content = False - - open_post_whitespace = False - open_post_content = True - child_len = len(child_tree) - if child_len > 2 and child_tree[1][0] == 'whitespace' and child_tree[2][0] == 'newline': - open_post_whitespace = True - open_post_content = False - elif child_len > 1 and child_tree[1][0] == 'newline': - open_post_content = False - - if not open_pre_content and not open_post_content: - if open_pre_whitespace: - tree.pop(pointer - 1) - pointer -= 1 - end -= 1 - if open_post_whitespace: - child_tree.pop(1) - child_tree.pop(1) # trailing newline - - # Do the same thing, but for the close tag - close_pre_whitespace = False - close_pre_content = True - child_len = len(child_tree) - if child_len > 2 and child_tree[child_len - 1][0] == 'whitespace' and child_tree[child_len - 2][0] == 'newline': - close_pre_whitespace = True - close_pre_content = False - elif child_len > 1 and child_tree[child_len - 1][0] == 'newline': - close_pre_content = False - - close_post_whitespace = False - close_post_content = True - tree_len = len(tree) - if tree_len > pointer + 2 and tree[pointer + 1][0] == 'whitespace' and tree[pointer + 2][0] == 'newline': - close_post_whitespace = True - close_post_content = False - elif tree_len == pointer + 2 and tree[pointer + 1][0] == 'whitespace': - close_post_whitespace = True - close_post_content = False - elif tree_len > pointer + 1 and tree[pointer + 1][0] == 'newline': - close_post_content = False - elif tree_len == pointer + 1: - close_post_content = False - - if not close_pre_content and not close_post_content: - if close_pre_whitespace: - child_tree.pop() - child_tree.pop() # preceeding newline - if close_post_whitespace: - tree.pop(pointer + 1) - end -= 1 - - self.clean_whitespace(child_tree) - - pointer += 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pybars3-0.9.6/readme.md new/pybars3-0.9.7/readme.md --- old/pybars3-0.9.6/readme.md 2018-10-10 21:14:39.000000000 +0200 +++ new/pybars3-0.9.7/readme.md 2019-11-05 10:37:13.000000000 +0100 @@ -41,9 +41,6 @@ - `pybars.Compiler().precompile()` that is equivalent to `Handlebars.precompile()` - `{{> (whichPartial) }}` dynamic partials (Handlebars 3.0) - `{{{{raw}}}}{{escaped}}{{{{/raw}}}}` raw blocks (Handlebars 2.0) - -Features not currently implemented: - - Whitespace control, `{{var~}}` (Handlebars 1.1) Feel free to jump in with issues or pull requests. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pybars3-0.9.6/setup.cfg new/pybars3-0.9.7/setup.cfg --- old/pybars3-0.9.6/setup.cfg 2018-10-10 21:14:39.000000000 +0200 +++ new/pybars3-0.9.7/setup.cfg 2019-11-05 10:37:13.000000000 +0100 @@ -3,7 +3,7 @@ # E128 continuation line under-indented for visual indent # E131 continuation line unaligned for hanging indent # E123 closing bracket does not match indentation of opening bracket's line -ignore = E123, E128, E131 +ignore = E123, E128, E131, W503 exclude = libs max-line-length = 160 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pybars3-0.9.6/setup.py new/pybars3-0.9.7/setup.py --- old/pybars3-0.9.6/setup.py 2018-10-10 21:14:39.000000000 +0200 +++ new/pybars3-0.9.7/setup.py 2019-11-05 10:37:13.000000000 +0100 @@ -20,7 +20,7 @@ setup(name='pybars3', - version='0.9.6', + version='0.9.7', description='Handlebars.js templating for Python 3 and 2', long_description='Documentation is maintained at https://github.com/wbond/pybars3#readme', author='wbond, mjumbewu', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pybars3-0.9.6/tests/test__compiler.py new/pybars3-0.9.7/tests/test__compiler.py --- old/pybars3-0.9.6/tests/test__compiler.py 2018-10-10 21:14:39.000000000 +0200 +++ new/pybars3-0.9.7/tests/test__compiler.py 2019-11-05 10:37:13.000000000 +0100 @@ -21,6 +21,8 @@ # Python 3 support str_class = str +import sys + from unittest import TestCase from pybars import Compiler @@ -114,3 +116,21 @@ result = u"""hello""" self.assertEqual(result, render(template, context)) + + def test_compile_with_path(self): + template = u"Hi {{name}}!" + context = { + 'name': 'Ahmed' + } + result = u"Hi Ahmed!" + path = '/project/widgets/templates' + + compiler = Compiler() + + # compile and check that speficified path is used + self.assertEqual(result, compiler.compile(template, path=path)(context)) + self.assertTrue(sys.modules.get('pybars._templates._project_widgets_templates') is not None) + + # recompile and check that a new path is used + self.assertEqual(result, compiler.compile(template, path=path)(context)) + self.assertTrue(sys.modules.get('pybars._templates._project_widgets_templates_1') is not None) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pybars3-0.9.6/tests/test_acceptance.py new/pybars3-0.9.7/tests/test_acceptance.py --- old/pybars3-0.9.6/tests/test_acceptance.py 2018-10-10 21:14:39.000000000 +0200 +++ new/pybars3-0.9.7/tests/test_acceptance.py 2019-11-05 10:37:13.000000000 +0100 @@ -74,6 +74,16 @@ result = u"وداعا أيها العالم القاسي!" self.assertRender(template, context, result) + def test_whitespace_control(self): + template = u"Goodbye\n \n \t{{~cruel~}} \n \t {{world}}!" + context = { + 'cruel': "cruel", + 'world': "world" + } + result = u"Goodbyecruelworld!" + + self.assertRender(template, context, result) + def test_comments_ignored(self): template = u"{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!" context = { @@ -643,6 +653,16 @@ self.assertRender(template, context, result) + def test_array_length(self): + template = u"{{array.length}}" + + context = { + 'array': ['1', '2', '3'] + } + result = u"3" + + self.assertRender(template, context, result) + def test_unicode_array_iteration(self): template = u"{{#سلامات}}{{النص}}! {{/سلامات}}cruel {{world}}!" @@ -724,9 +744,9 @@ def test_helper_with_complex_lookup(self): def link(this, prefix): - return (u"<a href='" + prefix + u"/" + - this.get('url') + u"'>" + - this.get('text') + u"</a>") + return (u"<a href='" + prefix + u"/" + + this.get('url') + u"'>" + + this.get('text') + u"</a>") helpers = {'link': link} @@ -1056,8 +1076,8 @@ def link(this, options): return ( - "<a href='" + this['name'] + "'>" + - str_class(options['fn'](this)) + "</a>") + "<a href='" + this['name'] + "'>" + + str_class(options['fn'](this)) + "</a>") def form(this, options, context): return "<form>" + str_class(options['fn'](context)) + "</form>" @@ -1510,8 +1530,8 @@ self.assertEqual(True, bool1) self.assertEqual(False, bool2) self.assertEqual(12, times) - return ("Hello " + param + " " + str_class(times) + " times: " + - str_class(bool1) + " " + str_class(bool2)) + return ("Hello " + param + " " + str_class(times) + " times: " + + str_class(bool1) + " " + str_class(bool2)) helpers = {'hello': hello} @@ -1631,6 +1651,12 @@ self.assertRender(template, context, result) + template = u" {{#if var}}{{#if var}} \n {{var}}\n {{/if}} {{/if}}" \ + u"\n {{#if var}} {{#if var}} \n {{var}}\n {{/if}}{{/if}} " + result = u" Hello\n Hello" + + self.assertRender(template, context, result) + def test_using_a_quote_in_the_middle_of_a_parameter_raises_an_error(self): template = u'Message: {{hello wo"a"}}' context = None @@ -2458,7 +2484,7 @@ ], 'hasThings': lambda this: True } - result = u"<strong>This is a slightly more complicated blah.</strong>.\n\nCheck this out:\n\n<ul>\n\n<li class=one>@fat</li>\n\n<li class=two>@dhg</li>\n\n<li class=three>@sayrer</li>\n</ul>.\n\n" # noqa: E501 + result = u"<strong>This is a slightly more complicated blah.</strong>.\nCheck this out:\n<ul>\n<li class=one>@fat</li>\n<li class=two>@dhg</li>\n<li class=three>@sayrer</li>\n</ul>.\n" # noqa: E501 self.assertRender(template, context, result)
