Ejemplo n.º 1
0
class DjangoCompatTest(SimpleTestCase):
    classes = ['DjangoCsrf', 'DjangoI18n', 'DjangoStatic', 'DjangoUrl']

    class CalledParse(Exception):
        pass

    @classmethod
    def make_side_effect(cls, cls_name):
        def parse(self, parser):
            raise cls.CalledParse(cls_name)
        return parse

    def setUp(self):
        for class_name in self.classes:
            patcher = mock.patch(
                'jdj_tags.extensions.{}.parse'.format(class_name),
                side_effect=self.make_side_effect(class_name)
            )
            patcher.start()
            self.addCleanup(patcher.stop)

        self.env = Environment(extensions=[DjangoCompat])

    def test_compat(self):
        tags = [
            ('csrf_token', 'DjangoCsrf'),
            ('trans', 'DjangoI18n'),
            ('blocktrans', 'DjangoI18n'),
            ('static', 'DjangoStatic'),
            ('url', 'DjangoUrl'),
        ]

        for tag, class_name in tags:
            with self.assertRaisesMessage(self.CalledParse, class_name):
                self.env.from_string('{% ' + tag + ' %}')
Ejemplo n.º 2
0
def test_with_extension():
    env = Environment(extensions=[WithExtension])
    t = env.from_string('{{ a }}{% with 2 as a %}{{ a }}{% endwith %}{{ a }}')
    assert t.render(a=1) == '121'

    t = env.from_string('{% with 2 as a %}{{ a }}{% endwith %}{{ a }}')
    assert t.render(a=3) == '23'
Ejemplo n.º 3
0
    def process(self, **context):
        """
        Process handler request. Before executing requests render templates with context
        
        :param context: Processing context
        :returns: Requests response `<http://docs.python-requests.org/en/master/api/#requests.Response>` _.
        """
        env = Environment(extensions=['jinja2_time.TimeExtension'])
        
        url_template = env.from_string(self.url_template)
        url = url_template.render(**context).replace(" ", "")
        logger.debug("Request %s generates url %s" % (self, url))        
        params = self._url_params(**context)
        logger.debug("Request %s generates params %s" % (self, params))
        headers = self._header_params(**context)
        logger.debug("Request %s generates header %s" % (self, headers))
        
        if self.data_required():
            data_template = env.from_string(self.data)
            data = data_template.render(**context)
            logger.debug("Request %s generates data %s" % (self, data))
            r = self._get_method()(url, data=json.loads(data), headers=headers, params=params)
        else:
            r = self._get_method()(url, headers=headers, params=params)

        return r
Ejemplo n.º 4
0
 def test_replace(self):
     env = Environment()
     tmpl = env.from_string('{{ string|replace("o", 42) }}')
     env = Environment(autoescape=True)
     tmpl = env.from_string('{{ string|replace("o", 42) }}')
     tmpl = env.from_string('{{ string|replace("<", 42) }}')
     tmpl = env.from_string('{{ string|replace("o", ">x<") }}')
Ejemplo n.º 5
0
def test_spaceless():
    from coffin.template.defaulttags import SpacelessExtension

    env = Environment(extensions=[SpacelessExtension])

    assert (
        env.from_string(
            """{% spaceless %}
<p>
    <a href="foo/">Foo</a>
</p>
{% endspaceless %}"""
        ).render()
        == '<p><a href="foo/">Foo</a></p>'
    )
    assert (
        env.from_string(
            """{% spaceless %}
    <strong>
        Hello
    </strong>
{% endspaceless %}"""
        ).render()
        == "<strong>\n        Hello\n    </strong>"
    )
Ejemplo n.º 6
0
class MacrosTestCase(JinjaTestCase):
    env = Environment(trim_blocks=True)

    def test_simple(self):
        tmpl = self.env.from_string("{% macro say_hello(name) %}Hello {{ name }}!{% endmacro %}\n{{ say_hello('Peter') }}")

    def test_scoping(self):
        tmpl = self.env.from_string("{% macro level1(data1) %}\n{% macro level2(data2) %}{{ data1 }}|{{ data2 }}{% endmacro %}\n{{ level2('bar') }}{% endmacro %}\n{{ level1('foo') }}")

    def test_arguments(self):
        tmpl = self.env.from_string("{% macro m(a, b, c='c', d='d') %}{{ a }}|{{ b }}|{{ c }}|{{ d }}{% endmacro %}\n{{ m() }}|{{ m('a') }}|{{ m('a', 'b') }}|{{ m(1, 2, 3) }}")

    def test_varargs(self):
        tmpl = self.env.from_string("{% macro test() %}{{ varargs|join('|') }}{% endmacro %}{{ test(1, 2, 3) }}")

    def test_simple_call(self):
        tmpl = self.env.from_string('{% macro test() %}[[{{ caller() }}]]{% endmacro %}{% call test() %}data{% endcall %}')

    def test_complex_call(self):
        tmpl = self.env.from_string("{% macro test() %}[[{{ caller('data') }}]]{% endmacro %}{% call(data) test() %}{{ data }}{% endcall %}")

    def test_caller_undefined(self):
        tmpl = self.env.from_string('{% set caller = 42 %}{% macro test() %}{{ caller is not defined }}{% endmacro %}{{ test() }}')

    def test_include(self):
        self.env = Environment(loader=DictLoader({'include': '{% macro test(foo) %}[{{ foo }}]{% endmacro %}'}))
        tmpl = self.env.from_string('{% from "include" import test %}{{ test("foo") }}')

    def test_macro_api(self):
        tmpl = self.env.from_string('{% macro foo(a, b) %}{% endmacro %}{% macro bar() %}{{ varargs }}{{ kwargs }}{% endmacro %}{% macro baz() %}{{ caller() }}{% endmacro %}')

    def test_callself(self):
        tmpl = self.env.from_string('{% macro foo(x) %}{{ x }}{% if x > 1 %}|{{ foo(x - 1) }}{% endif %}{% endmacro %}{{ foo(5) }}')
Ejemplo n.º 7
0
def fill_template(player_data, lang, fundamental, yaku):
    """Build long text which shows the statistics of the target
    player(s).
    """

    target_games = player_data[0]['games'] if player_data else None
    if not target_games:
        return 'NO DATA\n'

    env = Environment(autoescape=False)
    env.filters.update(
        format_float=format_float,
        format_percentage=format_percentage,)

    output_text = env.from_string(lang.tmpl_summary).render(
        count_games=len(target_games),
        started_at=target_games[0]['started_at'],
        finished_at=target_games[-1]['finished_at'],
        data=player_data)

    if fundamental:
        output_text += env.from_string(lang.tmpl_fundamental).render(
            data=player_data)

    if yaku:
        yaku_name_map = {y:lang.yaku_names[i]
                         for i, y in enumerate(YakuTable)}
        output_text += env.from_string(lang.tmpl_yaku_freq).render(
            data=player_data,
            YakuTable=YakuTable,
            yaku_name_map=yaku_name_map)

    return output_text
    def test_cache(self):
        from django_cofingo.extensions import CacheExtension
        env = Environment(extensions=[CacheExtension])

        x = 0
        result = env.from_string(
            '{%cache 500 "ab"%}{{x}}{%endcache%}').render({'x': x})
        self.assertEqual(result, '0')

        # cache is used; Jinja2 expressions work
        x += 1
        result = env.from_string(
            '{%cache 50*10 "a"+"b"%}{{x}}{%endcache%}').render({'x': x})
        self.assertEqual(result, '0')

        # vary-arguments can be used
        x += 1
        result = env.from_string(
            '{%cache 50*10 "ab" x "foo"%}{{x}}{%endcache%}').render({'x': x})
        self.assertEqual(result, '2')

        x += 1
        result = env.from_string(
            '{%cache 50*10 "ab" x "foo"%}{{x}}{%endcache%}').render({'x': x})
        self.assertEqual(result, '3')
Ejemplo n.º 9
0
def main():
    '''main function'''
    args = get_parser().parse_args()

    ec2 = boto3.resource('ec2')

    print 'Instances:', list(i.id for i in ec2.instances.all())

    env = Environment()
    hosts = env.from_string(hosts_template)
    ssh_config = env.from_string(ssh_config_template)

    head_public_ip = get_head_public_ip(ec2)
    worker_private_ips = get_work_private_ips(ec2)

    hosts_rendered = hosts.render(head_public_ip=head_public_ip,
                                  worker_private_ips=worker_private_ips)

    ssh_config_rendered = ssh_config.render(head_public_ip=head_public_ip,
                                            private_key=KEY_NAME)

    if args.dry_run:
        print '{:*^30}'.format(' Hosts ')
        print hosts_rendered
        print '{:*^30}'.format(' ssh_config ')
        print ssh_config_rendered
    else:
        with open('hosts', 'w') as fd:
            fd.write(hosts_rendered)
        with open('amazon_ssh_config', 'w') as fd:
            fd.write(ssh_config_rendered)
Ejemplo n.º 10
0
    def test_nested_structures(self):
        env = Environment(extensions=[SerializerExtension])
        rendered = env.from_string('{{ data }}').render(data="foo")
        self.assertEqual(rendered, u"foo")

        data = OrderedDict([
            ('foo', OrderedDict([
                        ('bar', 'baz'),
                        ('qux', 42)
                    ])
            )
        ])

        rendered = env.from_string('{{ data }}').render(data=data)
        self.assertEqual(rendered, u"{'foo': {'bar': 'baz', 'qux': 42}}")

        rendered = env.from_string('{{ data }}').render(data=[
                                                            OrderedDict(
                                                                foo='bar',
                                                            ),
                                                            OrderedDict(
                                                                baz=42,
                                                            )
                                                        ])
        self.assertEqual(rendered, u"[{'foo': 'bar'}, {'baz': 42}]")
Ejemplo n.º 11
0
class ExtensionTest(TestCase):
    def setUp(self):
        self.env = Environment(extensions=[PipelineExtension], loader=
            PackageLoader('pipeline', 'templates'))

    def test_no_package(self):
        template = self.env.from_string(u"""{% compressed_css "unknow" %}""")
        self.assertEqual(u'', template.render())
        template = self.env.from_string(u"""{% compressed_js "unknow" %}""")
        self.assertEqual(u'', template.render())

    def test_package_css(self):
        template = self.env.from_string(u"""{% compressed_css "screen" %}""")
        self.assertEqual(u'<link href="/static/screen.css" rel="stylesheet" type="text/css" />', template.render())

    def test_package_css_debug(self):
        with pipeline_settings(PIPELINE=False):
            template = self.env.from_string(u"""{% compressed_css "screen" %}""")
            self.assertEqual(u'''<link href="/static/pipeline/css/first.css" rel="stylesheet" type="text/css" />
<link href="/static/pipeline/css/second.css" rel="stylesheet" type="text/css" />
<link href="/static/pipeline/css/urls.css" rel="stylesheet" type="text/css" />''', template.render())

    def test_package_js(self):
        template = self.env.from_string(u"""{% compressed_js "scripts" %}""")
        self.assertEqual(u'<script   type="text/css" src="/static/scripts.css" charset="utf-8"></script>', template.render())
Ejemplo n.º 12
0
class DjangoStaticTest(SimpleTestCase):
    @staticmethod
    def _static(path):
        return 'Static: {}'.format(path)

    def setUp(self):
        patcher = mock.patch('jdj_tags.extensions.django_static', side_effect=self._static)
        self.static = patcher.start()
        self.addCleanup(patcher.stop)

        self.env = Environment(extensions=[DjangoStatic])

    def test_simple(self):
        template = self.env.from_string("{% static 'static.png' %}")

        self.assertEqual('Static: static.png', template.render())
        self.static.assert_called_with('static.png')

    def test_as_var(self):
        template = self.env.from_string(
            "{% static 'static.png' as my_url %}My url is: {{ my_url }}!"
        )

        self.assertEqual('My url is: Static: static.png!', template.render())
        self.static.assert_called_with('static.png')
def test():
    from jinja2 import Environment
    env = Environment(extensions=[HTMLCompress])
    tmpl = env.from_string('''
        <html>
          <head>
            <title>{{ title }}</title>
          </head>
          <script type=text/javascript>
            if (foo < 42) {
              document.write('Foo < Bar');
            }
          </script>
          <body>
            <li><a href="{{ href }}">{{ title }}</a><br>Test   Foo
            <li><a href="{{ href }}">{{ title }}</a><img src=test.png>
          </body>
        </html>
    ''')
    print "-" * 30, "HTMLCompress"
    print tmpl.render(title=42, href='index.html')
    

    env = Environment(extensions=[SelectiveHTMLCompress])
    tmpl = env.from_string('''
        Normal   <span>    unchanged </span>   stuff
        {% strip %}Stripped <span class=foo  >   test   </span>
        <a href="foo">  test </a> {{ foo }}
        Normal <stuff>   again {{ foo }}  </stuff>
        <p>
          Foo<br>Bar
          Baz
        <p>
          Moep    <span>Test</span>    Moep
        </p>
        {% endstrip %}
    ''')
    print "-" * 30, "SelectiveHTMLCompress"
    print tmpl.render(foo=42)
    

    env = Environment(extensions=[InvertedSelectiveHTMLCompress])
    tmpl = env.from_string('''
        {% unstrip %}
        Normal   <span>    unchanged </span>   stuff
        {% endunstrip %}

        Stripped <span class=foo  >   test   </span>
        <a href="foo">  test </a> {{ foo }}
        Normal <stuff>   again {{ foo }}  </stuff>
        <p>
          Foo<br>Bar
          Baz
        <p>
          Moep    <span>Test</span>    Moep
        </p>
    ''')
    print "-" * 30, "InvertedSelectiveHTMLCompress"
    print tmpl.render(foo=42)
Ejemplo n.º 14
0
 def test_strict_undefined(self):
     env = Environment(undefined=StrictUndefined)
     self.assert_raises(UndefinedError, env.from_string('{{ missing }}').render)
     self.assert_raises(UndefinedError, env.from_string('{{ missing.attribute }}').render)
     self.assert_raises(UndefinedError, env.from_string('{{ missing|list }}').render)
     self.assert_equal(env.from_string('{{ missing is not defined }}').render(), 'True')
     self.assert_raises(UndefinedError, env.from_string('{{ foo.missing }}').render, foo=42)
     self.assert_raises(UndefinedError, env.from_string('{{ not missing }}').render)
Ejemplo n.º 15
0
 def test_nonvolatile(self):
     env = Environment(extensions=['jinja2.ext.autoescape'],
                       autoescape=True)
     tmpl = env.from_string('{{ {"foo": "<test>"}|xmlattr|escape }}')
     assert tmpl.render() == ' foo="&lt;test&gt;"'
     tmpl = env.from_string('{% autoescape false %}{{ {"foo": "<test>"}'
                            '|xmlattr|escape }}{% endautoescape %}')
     assert tmpl.render() == ' foo=&#34;&amp;lt;test&amp;gt;&#34;'
Ejemplo n.º 16
0
    def test_load_json_template(self):
        loader = DictLoader({'foo': '{"bar": "my god is blue", "foo": [1, 2, 3]}'})
        env = Environment(extensions=[SerializerExtension], loader=loader)
        rendered = env.from_string('{% import_json "foo" as doc %}{{ doc.bar }}').render()
        self.assertEqual(rendered, u"my god is blue")

        with self.assertRaises(exceptions.TemplateNotFound):
            env.from_string('{% import_json "does not exists" as doc %}').render()
Ejemplo n.º 17
0
def test_line_syntax_priority():
    # XXX: why is the whitespace there in front of the newline?
    env = Environment('{%', '%}', '${', '}', '/*', '*/', '##', '#')
    tmpl = env.from_string(LINE_SYNTAX_PRIORITY1)
    assert tmpl.render(seq=[1, 2]).strip() == '* 1\n* 2'
    env = Environment('{%', '%}', '${', '}', '/*', '*/', '#', '##')
    tmpl = env.from_string(LINE_SYNTAX_PRIORITY2)
    assert tmpl.render(seq=[1, 2]).strip() == '* 1\n\n* 2'
 def test_pluralize_as_filter(self):
     """ Tests pluralize as a Jinja2 filter. """
     env = Environment()
     env.filters['pluralize'] = pluralize
     tmpl = env.from_string("{{ 'vote'|pluralize }}")
     assert tmpl.render() == 'votes'
     tmpl = env.from_string("{{ 'goose'|pluralize }}")
     assert tmpl.render() == 'geese'
Ejemplo n.º 19
0
    def test_load_text_template(self):
        loader = DictLoader({'foo': 'Foo!'})
        env = Environment(extensions=[SerializerExtension], loader=loader)

        rendered = env.from_string('{% import_text "foo" as doc %}{{ doc }}').render()
        self.assertEqual(rendered, u"Foo!")

        with self.assertRaises(exceptions.TemplateNotFound):
            env.from_string('{% import_text "does not exists" as doc %}').render()
Ejemplo n.º 20
0
	def generate_rst(self, input_dir, output_dir):
		root = self.get_info()
		i = 0
		
		env = Environment(extensions=["jinja2.ext.do",])
		env.filters['firstline'] = first_line
		env.filters['rst_link'] = make_rst_link
		env.filters['rst_table'] = render_rst_table
		env.filters['rst_csvtable'] = render_rst_csv_table
		env.filters['rst_heading'] = render_rst_heading
		env.filters['extract_value'] = extract_value
		env.filters['block_pad'] = block_pad
		env.filters['common_head'] = calculate_common_head
		env.filters['as_text'] = as_text
		
		for (module,minfo) in root.plugins.iteritems():
			out_base_path = '%s/reference/'%output_dir
			sample_base_path = '%s/samples/'%output_dir
			if minfo.namespace:
				out_base_path = '%s/reference/%s/'%(output_dir, minfo.namespace)
			hash = root.get_hash()
			minfo.key = module
			minfo.queries = {}
			for (c,cinfo) in sorted(root.commands.iteritems()):
				if module in cinfo.info.plugin:
					more_info = self.fetch_command(c,cinfo)
					if more_info:
						cinfo = more_info
					sfile = '%s%s_%s_samples.inc'%(sample_base_path, module, c)
					if os.path.exists(sfile):
						cinfo.sample = os.path.basename(sfile)
						#all_samples.append((module, command, sfile))
					cinfo.key = c
					minfo.queries[c] = cinfo
			minfo.aliases = {}
			for (c,cinfo) in sorted(root.aliases.iteritems()):
				if module in cinfo.info.plugin:
					cinfo.key = c
					minfo.aliases[c] = cinfo
					
			minfo.paths = {}
			for (c,cinfo) in sorted(root.paths.iteritems()):
				if module in cinfo.info.plugin:
					cinfo.key = c
					minfo.paths[c] = cinfo

			hash['module'] = minfo
			i=i+1
			log_debug('Processing module: %d of %d [%s]'%(i, len(root.plugins), module))

			template = env.from_string(module_template)
			render_template(hash, template, '%s/%s.rst'%(out_base_path, module))

		log_debug('%s/samples/index.rst'%output_dir)
		hash = root.get_hash()
		template = env.from_string(samples_template)
		render_template(hash, template, '%s/samples/index.rst'%output_dir)
Ejemplo n.º 21
0
def write_templated_output(output_dir, template_dir, title, data, extension):
    """Write out a templated version of the docs"""
    from jinja2 import Environment

    jinja = Environment(trim_blocks=True, lstrip_blocks=True)

    # Make sure we have a valid output_dir
    if not os.path.isdir(output_dir):
        try:
            os.makedirs(output_dir)
        except Exception as error:
            err("Output directory is not a directory, "
                "and/or can't be created: %s" % error)

    # Prepare for writing index.<extensions>
    try:
        outfile = open(output_dir + "/index." + extension, "wb")
    except Exception as error:
        err("Unable to create %s: %s" % (output_dir + "/index." + extension,
            error))

    # Prepare for reading index.j2.<extension>
    try:
        tmplfile = open(template_dir + "/index.j2." + extension, "r")
    except Exception as error:
        err("Unable to open index.j2.%s: %s" % (extension, error))

    if extension == "html":
        # Re-process the doc data to convert Markdown to HTML
        data = process_markdown(data)

    # Render and write index.<extension>
    template = jinja.from_string(tmplfile.read().decode('utf-8'))
    render = template.render(data=data, links=LINKS, title=title)
    outfile.write(render.encode("utf-8"))
    outfile.close()
    tmplfile.close()
    dbg("Wrote index." + extension)

    # Render and write module docs
    try:
        tmplfile = open(template_dir + "/module.j2." + extension, "r")
        template = jinja.from_string(tmplfile.read().decode('utf-8'))
    except Exception as error:
        err("Unable to open module.j2.%s: %s" % (extension, error))

    for module in data:
        with open("%s/%s.%s" % (output_dir,
                                module["name"],
                                extension), "wb") as docfile:
            render = template.render(module=module,
                                     type_order=TYPE_NAMES,
                                     type_desc=TYPE_DESC)
            docfile.write(render.encode("utf-8"))
            dbg("Wrote %s.%s" % (module["name"], extension))

    tmplfile.close()
Ejemplo n.º 22
0
def test_finalizer():
    def finalize_none_empty(value):
        if value is None:
            value = u''
        return value
    env = Environment(finalize=finalize_none_empty)
    tmpl = env.from_string('{% for item in seq %}|{{ item }}{% endfor %}')
    assert tmpl.render(seq=(None, 1, "foo")) == '||1|foo'
    tmpl = env.from_string('<{{ none }}>')
    assert tmpl.render() == '<>'
Ejemplo n.º 23
0
 def test_urlescape(self):
     env = Environment(autoescape=True)
     tmpl = env.from_string('{{ "Hello, world!"|urlescape }}')
     assert tmpl.render() == 'Hello%2C%20world%21'
     tmpl = env.from_string('{{ o|urlescape }}')
     assert tmpl.render(o=u"Hello, world\u203d") == "Hello%2C%20world%E2%80%BD"
     assert tmpl.render(o=(("f", 1),)) == "f=1"
     assert tmpl.render(o=(('f', 1), ("z", 2))) == "f=1&amp;z=2"
     assert tmpl.render(o=((u"\u203d", 1),)) == "%E2%80%BD=1"
     assert tmpl.render(o={u"\u203d": 1}) == "%E2%80%BD=1"
Ejemplo n.º 24
0
    def test_finalizer(self):

        def finalize_none_empty(value):
            if value is None:
                value = u''
            return value

        env = Environment(finalize=finalize_none_empty)
        tmpl = env.from_string('{% for item in seq %}|{{ item }}{% endfor %}')
        tmpl = env.from_string('<{{ none }}>')
Ejemplo n.º 25
0
def test_line_syntax():
    env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%')
    tmpl = env.from_string(MAKO_SYNTAX)
    assert [int(x.strip()) for x in tmpl.render(seq=range(5)).split()] == \
           range(5)

    env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%', '##')
    tmpl = env.from_string(MAKO_SYNTAX_LINECOMMENTS)
    assert [int(x.strip()) for x in tmpl.render(seq=range(5)).split()] == \
            range(5)
Ejemplo n.º 26
0
 def test_replace(self):
     env = Environment()
     tmpl = env.from_string('{{ string|replace("o", 42) }}')
     assert tmpl.render(string='<foo>') == '<f4242>'
     env = Environment(autoescape=True)
     tmpl = env.from_string('{{ string|replace("o", 42) }}')
     assert tmpl.render(string='<foo>') == '&lt;f4242&gt;'
     tmpl = env.from_string('{{ string|replace("<", 42) }}')
     assert tmpl.render(string='<foo>') == '42foo&gt;'
     tmpl = env.from_string('{{ string|replace("o", ">x<") }}')
     assert tmpl.render(string=Markup('foo')) == 'f&gt;x&lt;&gt;x&lt;'
Ejemplo n.º 27
0
def validate_template(value):
    try:
        env = Environment(extensions=['jinja2_time.TimeExtension'])
        env.from_string(value)
    except TemplateSyntaxError:
        exctype, value = sys.exc_info()[:2]
        raise ValidationError(_("Jinja error: %(error)s"), params={'error': value})
    except:
        exctype, value = sys.exc_info()[:2]
        logger.error("Unexpected jinja validation: (%s, %s)" % (exctype, value))
        raise ValidationError(_("Jinja template not valid"))
Ejemplo n.º 28
0
 def test_replace(self):
     env = Environment()
     tmpl = env.from_string('{{ string|replace("o", 42) }}')
     assert tmpl.render(string="<foo>") == "<f4242>"
     env = Environment(autoescape=True)
     tmpl = env.from_string('{{ string|replace("o", 42) }}')
     assert tmpl.render(string="<foo>") == "&lt;f4242&gt;"
     tmpl = env.from_string('{{ string|replace("<", 42) }}')
     assert tmpl.render(string="<foo>") == "42foo&gt;"
     tmpl = env.from_string('{{ string|replace("o", ">x<") }}')
     assert tmpl.render(string=Markup("foo")) == "f&gt;x&lt;&gt;x&lt;"
Ejemplo n.º 29
0
def test_load():
    from coffin.template.defaulttags import LoadExtension
    env = Environment(extensions=[LoadExtension])

    # the load tag is a no-op
    assert env.from_string('a{% load %}b').render() == 'ab'
    assert env.from_string('a{% load news.photos %}b').render() == 'ab'
    assert env.from_string('a{% load "news.photos" %}b').render() == 'ab'

    # [bug] invalid code was generated under certain circumstances
    assert env.from_string('{% set x=1 %}{% load "news.photos" %}').render() == ''
Ejemplo n.º 30
0
    def test_finalizer(self):
        def finalize_none_empty(value):
            if value is None:
                value = u""
            return value

        env = Environment(finalize=finalize_none_empty)
        tmpl = env.from_string("{% for item in seq %}|{{ item }}{% endfor %}")
        assert tmpl.render(seq=(None, 1, "foo")) == "||1|foo"
        tmpl = env.from_string("<{{ none }}>")
        assert tmpl.render() == "<>"
Ejemplo n.º 31
0
 def test_normalizing(self, env):
     for seq in '\r', '\r\n', '\n':
         env = Environment(newline_sequence=seq)
         tmpl = env.from_string('1\n2\r\n3\n4\n')
         result = tmpl.render()
         assert result.replace(seq, 'X') == '1X2X3X4'
Ejemplo n.º 32
0
 def test_simple_reject(self, env):
     env = Environment()
     tmpl = env.from_string('{{ [1, 2, 3, 4, 5]|reject("odd")|join("|") }}')
     assert tmpl.render() == '2|4'
Ejemplo n.º 33
0
class Jinja2TemplateHandler(TemplateHandler):
    """
    This class implements the :ref:`Template <cement.core.template>` Handler
    interface.  It renders content as template, and supports copying entire
    source template directories using the
    `Jinja2 Templating Language <http://jinja.pocoo.org/>`_.  Please
    see the developer documentation on
    :cement:`Template Handling <dev/template>`.

    **Note** This extension has an external dependency on ``jinja2``.  You
    must include ``jinja2`` in your applications dependencies as Cement
    explicitly does **not** include external dependencies for optional
    extensions.
    """
    class Meta:
        """Handler meta-data."""

        label = 'jinja2'

    def __init__(self, *args, **kw):
        super(Jinja2TemplateHandler, self).__init__(*args, **kw)

        # expose Jinja2 Environment instance so that we can manipulate it
        # higher in application code if necessary
        self.env = Environment(keep_trailing_newline=True)

    def load(self, *args, **kw):
        """
        Loads a template file first from ``self.app._meta.template_dirs`` and
        secondly from ``self.app._meta.template_module``.  The
        ``template_dirs`` have presedence.

        Args:
            template_path (str): The secondary path of the template **after**
                either ``template_module`` or ``template_dirs`` prefix (set via
                ``App.Meta``)

        Returns:
            tuple: The content of the template (``str``), the type of template
            (``str``: ``directory``, or ``module``), and the path (``str``) of
            the directory or module)

        Raises:
            cement.core.exc.FrameworkError: If the template does not exist in
                either the ``template_module`` or ``template_dirs``.
        """
        content, _type, _path = super(Jinja2TemplateHandler,
                                      self).load(*args, **kw)

        if _type == 'directory':
            self.env.loader = FileSystemLoader(self.app._meta.template_dirs)
        elif _type == 'module':
            parts = self.app._meta.template_module.rsplit('.', 1)
            self.env.loader = PackageLoader(parts[0], package_path=parts[1])

        return content, _type, _path

    def render(self, content, data, *args, **kw):
        """
        Render the given ``content`` as template with the ``data`` dictionary.

        Args:
            content (str): The template content to render.
            data (dict): The data dictionary to render.

        Returns:
            str: The rendered template text

        """
        LOG.debug("rendering output as text via %s" % self.__module__)

        if not isinstance(content, str):
            content = content.decode('utf-8')

        tmpl = self.env.from_string(content)
        return tmpl.render(**data)
Ejemplo n.º 34
0
 def test_lstrip_trim(self, env):
     env = Environment(lstrip_blocks=True, trim_blocks=True)
     tmpl = env.from_string('''    {% if True %}\n    {% endif %}''')
     assert tmpl.render() == ""
Ejemplo n.º 35
0
Archivo: ext.py Proyecto: mateid/shout
 def test_streamfilter_extension(self):
     env = Environment(extensions=[StreamFilterExtension])
     env.globals['gettext'] = lambda x: x.upper()
     tmpl = env.from_string('Foo _(bar) Baz')
     out = tmpl.render()
     assert out == 'Foo BAR Baz'
Ejemplo n.º 36
0
 def render_template_keep_undefined(cls, template_str, data):
     env = Environment(loader=BaseLoader, undefined=DebugUndefined)
     env.filters["jsonify"] = partial(json.dumps, default=str)
     rtemplate = env.from_string(template_str)
     return rtemplate.render(data)
Ejemplo n.º 37
0
def auto_report(dag, path, stylesheet=None):
    try:
        from jinja2 import Template, Environment, PackageLoader
    except ImportError as e:
        raise WorkflowError(
            "Python package jinja2 must be installed to create reports.")

    if not path.endswith(".html"):
        raise WorkflowError("Report file does not end with .html")

    custom_stylesheet = None
    if stylesheet is not None:
        try:
            with open(stylesheet) as s:
                custom_stylesheet = s.read()
        except (Exception, BaseException) as e:
            raise WorkflowError("Unable to read custom report stylesheet.", e)

    logger.info("Creating report...")

    env = Environment(
        loader=PackageLoader("snakemake", "report"),
        trim_blocks=True,
        lstrip_blocks=True,
    )
    env.filters["get_resource_as_string"] = get_resource_as_string

    persistence = dag.workflow.persistence
    results = defaultdict(lambda: defaultdict(list))
    records = defaultdict(JobRecord)
    recorded_files = set()
    for job in dag.jobs:
        for f in itertools.chain(job.expanded_output, job.input):
            if is_flagged(f, "report") and f not in recorded_files:
                if not f.exists:
                    raise WorkflowError("File {} marked for report but does "
                                        "not exist.".format(f))
                report_obj = get_flag_value(f, "report")

                def register_file(f, wildcards_overwrite=None):
                    wildcards = wildcards_overwrite or job.wildcards
                    category = Category(report_obj.category,
                                        wildcards=wildcards,
                                        job=job)
                    subcategory = Category(report_obj.subcategory,
                                           wildcards=wildcards,
                                           job=job)

                    results[category][subcategory].append(
                        FileRecord(
                            f,
                            job,
                            report_obj.caption,
                            env,
                            category,
                            wildcards_overwrite=wildcards_overwrite,
                        ))
                    recorded_files.add(f)

                if os.path.isfile(f):
                    register_file(f)
                if os.path.isdir(f):
                    if not isinstance(report_obj.patterns, list):
                        raise WorkflowError(
                            "Invalid patterns given for report. Must be list.",
                            rule=job.rule,
                        )
                    if not report_obj.patterns:
                        raise WorkflowError(
                            "Directory marked for report but no file patterns given via patterns=[...]. "
                            "See report documentation.",
                            rule=job.rule,
                        )
                    for pattern in report_obj.patterns:
                        pattern = os.path.join(f, pattern)
                        wildcards = glob_wildcards(pattern)._asdict()
                        names = wildcards.keys()
                        for w in zip(*wildcards.values()):
                            w = dict(zip(names, w))
                            w.update(job.wildcards_dict)
                            w = Wildcards(fromdict=w)
                            f = apply_wildcards(pattern, w)
                            register_file(f, wildcards_overwrite=w)

        for f in job.expanded_output:
            meta = persistence.metadata(f)
            if not meta:
                logger.warning("Missing metadata for file {}. Maybe metadata "
                               "was deleted or it was created using an older "
                               "version of Snakemake. This is a non critical "
                               "warning.".format(f))
                continue
            try:
                job_hash = meta["job_hash"]
                rule = meta["rule"]
                rec = records[(job_hash, rule)]
                rec.rule = rule
                rec.job = job
                rec.starttime = min(rec.starttime, meta["starttime"])
                rec.endtime = max(rec.endtime, meta["endtime"])
                rec.conda_env_file = None
                rec.conda_env = meta["conda_env"]
                rec.container_img_url = meta["container_img_url"]
                rec.output.append(f)
            except KeyError as e:
                print(e)
                logger.warning("Metadata for file {} was created with a too "
                               "old Snakemake version.".format(f))

    for subcats in results.values():
        for catresults in subcats.values():
            catresults.sort(key=lambda res: res.name)

    # prepare runtimes
    runtimes = [{
        "rule": rec.rule,
        "runtime": rec.endtime - rec.starttime
    } for rec in sorted(records.values(), key=lambda rec: rec.rule)]

    # prepare end times
    timeline = [{
        "rule":
        rec.rule,
        "starttime":
        datetime.datetime.fromtimestamp(rec.starttime).isoformat(),
        "endtime":
        datetime.datetime.fromtimestamp(rec.endtime).isoformat(),
    } for rec in sorted(records.values(), key=lambda rec: rec.rule)]

    # prepare per-rule information
    rules = defaultdict(list)
    for rec in records.values():
        rule = RuleRecord(rec.job, rec)
        if rec.rule not in rules:
            rules[rec.rule].append(rule)
        else:
            merged = False
            for other in rules[rec.rule]:
                if rule == other:
                    other.add(rec)
                    merged = True
                    break
            if not merged:
                rules[rec.rule].append(rule)

    # rulegraph
    rulegraph, xmax, ymax = rulegraph_d3_spec(dag)

    # configfiles
    configfiles = [ConfigfileRecord(f) for f in dag.workflow.configfiles]

    seen = set()
    files = [
        seen.add(res.target) or res for cat in results.values()
        for subcat in cat.values() for res in subcat if res.target not in seen
    ]

    rst_links = textwrap.dedent("""

    .. _Workflow: javascript:show_panel('workflow')
    .. _Statistics: javascript:show_panel('statistics')
    {% for cat, catresults in categories|dictsort %}
    .. _{{ cat.name }}: javascript:show_panel("{{ cat.id }}")
    {% endfor %}
    {% for res in files %}
    .. _{{ res.target }}: javascript:show_panel("{{ res.category.id }}")
    {% endfor %}
    """)
    for cat, subcats in results.items():
        for subcat, catresults in subcats.items():
            for res in catresults:
                res.render(env, rst_links, results, files)

    # global description
    text = ""
    if dag.workflow.report_text:
        with open(dag.workflow.report_text) as f:

            class Snakemake:
                config = dag.workflow.config

            text = f.read() + rst_links
            text = publish_parts(
                env.from_string(text).render(snakemake=Snakemake,
                                             categories=results,
                                             files=files),
                writer_name="html",
            )["body"]

    # record time
    now = "{} {}".format(datetime.datetime.now().ctime(), time.tzname[0])
    results_size = sum(res.size for cat in results.values()
                       for subcat in cat.values() for res in subcat)

    try:
        from pygments.formatters import HtmlFormatter
    except ImportError:
        raise WorkflowError(
            "Python package pygments must be installed to create reports.")

    # render HTML
    template = env.get_template("report.html")
    with open(path, "w", encoding="utf-8") as out:
        out.write(
            template.render(
                results=results,
                results_size=results_size,
                configfiles=configfiles,
                text=text,
                rulegraph_nodes=rulegraph["nodes"],
                rulegraph_links=rulegraph["links"],
                rulegraph_width=xmax + 20,
                rulegraph_height=ymax + 20,
                runtimes=runtimes,
                timeline=timeline,
                rules=[rec for recs in rules.values() for rec in recs],
                version=__version__,
                now=now,
                pygments_css=HtmlFormatter(
                    style="trac").get_style_defs(".source"),
                custom_stylesheet=custom_stylesheet,
            ))
    logger.info("Report created.")
Ejemplo n.º 38
0
def inline_render(file):
    """Take a file, look for all inline locations that have an associated template and render them inline"""
    def starts_with(s, sub):
        return s[0:len(sub)] == sub

    ishtml = False
    newcontents = []
    env = Environment(loader=FileSystemLoader('.'),
                      line_statement_prefix=line_statement_prefix)
    contents = read_file(file)
    linenr = 0
    laststart = 0
    tpl = []
    mode = 'init'
    typ = ''  # is this a build or autogen block?
    should_render_template = True
    for line in contents.split("\n"):
        linenr += 1
        isstart = re.search(r"^ *(// --) autogen", line)
        isstart2 = re.search(r"^ *(// --) build=(.*)", line)
        isend = re.search(r"^ *(// --) end (build|autogen)", line)
        istpl = re.search(r"^ *(// --) (.*)", line)
        ishtmlcomment = re.search(r"^<!--", line)
        if mode == 'init':
            if isstart is not None:
                typ = "autogen"
                should_render_template = True
                newcontents.append(line)
                laststart = linenr
                mode = 'template'
            elif isstart2 is not None:
                typ = "build"
                should_render_template = isstart2.group(
                    2) == get_context()['build']
                newcontents.append(line)
                laststart = linenr
                mode = 'template'
            else:
                newcontents.append(line)
                if ishtmlcomment is not None:
                    ishtml = True
                else:
                    ishtml = False
        elif mode == 'ignore':
            if isend is not None:
                if isend.group(2) != typ:
                    error("Started a '%s' block, but ended with '%s'" %
                          (typ, isend.group(2)))
                newcontents.append(line)
                mode = 'init'
        elif mode == 'template':
            if istpl is not None and isend is None:
                tpl.append(istpl.group(2))
                newcontents.append(line)
            else:
                tpl = "\n".join(tpl)
                if starts_with(tpl, "c_to_js"):
                    newcontents.append(c_to_js(tpl[8:]))
                else:
                    if should_render_template:
                        template = env.from_string(tpl)
                        if ishtml: newcontents.append('-->')
                        newcontents.append(
                            template.render(get_context()).strip("\n"))
                        if ishtml: newcontents.append('<!--')
                tpl = []
                mode = 'ignore'
                if isend is not None:
                    if isend.group(2) != typ:
                        error("Started a '%s' block, but ended with '%s'" %
                              (typ, isend.group(2)))
                    newcontents.append(line)
                    mode = 'init'

    if mode != 'init':
        error(
            "Unclosed autogen section started on line %d, stopped in mode %s."
            % (laststart, mode))

    newcontents = "\n".join(newcontents)
    if contents != newcontents:
        write_file(file, newcontents)
Ejemplo n.º 39
0
 def test_macro_escaping(self):
     env = Environment(autoescape=lambda x: False,
                       extensions=['jinja2.ext.autoescape'])
     template = "{% macro m() %}<html>{% endmacro %}"
     template += "{% autoescape true %}{{ m() }}{% endautoescape %}"
     assert env.from_string(template).render()
Ejemplo n.º 40
0
 def test_lstrip_nested(self, env):
     env = Environment(lstrip_blocks=True, trim_blocks=False)
     tmpl = env.from_string(
         '''    {% if True %}a {% if True %}b {% endif %}c {% endif %}''')
     assert tmpl.render() == 'a b c '
Ejemplo n.º 41
0
 def test_lstrip_inline(self, env):
     env = Environment(lstrip_blocks=True, trim_blocks=False)
     tmpl = env.from_string('''    {% if True %}hello    {% endif %}''')
     assert tmpl.render() == 'hello    '
Ejemplo n.º 42
0
 def test_lstrip_endline(self, env):
     env = Environment(lstrip_blocks=True, trim_blocks=False)
     tmpl = env.from_string(
         '''    hello{% if True %}\n    goodbye{% endif %}''')
     assert tmpl.render() == "    hello\n    goodbye"
Ejemplo n.º 43
0
 def test_only_module(self):
     env = Environment(extensions=['jinja2_module.ModuleExtension'])
     template = env.from_string('''
             No Fault in my stars
             {% module "wait-stage.module" %}
             ''')
Ejemplo n.º 44
0
def test_comments():
    from jinja2 import Environment
    env = Environment('<!--', '-->', '{', '}')
    tmpl = env.from_string(COMMENTS)
    assert tmpl.render(seq=range(3)) == ("<ul>\n  <li>0</li>\n  "
                                         "<li>1</li>\n  <li>2</li>\n</ul>")
Ejemplo n.º 45
0
def test_balancing():
    from jinja2 import Environment
    env = Environment('{%', '%}', '${', '}')
    tmpl = env.from_string(BALANCING)
    assert tmpl.render(seq=range(3)) == "{'FOO': 0}{'FOO': 1}{'FOO': 2}"
Ejemplo n.º 46
0
def execute_all(meta_cnc, app_dir, context):
    """
    Performs all REST operations defined in this meta-cnc file
    Each 'snippet' in the 'snippets' stanza in the .meta-cnc file will be executed in turn
    each entry in the 'snippets' stanza MUST have at least:
        'name', 'rest_path', and 'rest_operation'
    For a POST operation it must also include a 'payload' key

    * The path can include jinja2 variables as well as the payload file. Both will be interpolated before executing
    This allows things like the hostname, etc to be captured in the variables or target section

    :param meta_cnc: a parsed .meta-cnc.yaml file (self.service in class based Views)
    :param app_dir: which app_dir is this (panhandler, vistoq, etc) defined as self.app_dir on view classes
    :param context: fully populated workflow from the calling view (self.get_workflow() on the view class)
    :return: string suitable for presentation to the user
    """
    if 'snippet_path' in meta_cnc:
        snippets_dir = meta_cnc['snippet_path']
    else:
        # snippets_dir = Path(os.path.join(settings.BASE_DIR, app_dir, 'snippets', meta_cnc['name']))
        raise CCFParserError('Could not locate .meta-cnc for REST execution')

    response = dict()
    response['status'] = 'success'
    response['message'] = 'A-OK'
    response['snippets'] = dict()

    session = requests.Session()

    # create our jinja env and load filters only once
    environment = Environment(loader=BaseLoader())

    for f in jinja_filters.defined_filters:
        if hasattr(jinja_filters, f):
            environment.filters[f] = getattr(jinja_filters, f)

    try:
        # execute our rest call for each item in the 'snippets' stanza of the meta-cnc file
        for snippet in meta_cnc['snippets']:
            if 'path' not in snippet:
                print('Malformed meta-cnc error')
                raise CCFParserError

            name = snippet.get('name', '')

            # allow snippets to be skipped using the 'when' attribute
            if 'when' in snippet:
                when_template = environment.from_string(snippet.get('when', ''))
                when_result = str(when_template.render(context))
                if when_result.lower() == 'false' or when_result.lower() == 'no':
                    print(f'Skipping snippet {name} due to when condition false')
                    continue

            rest_path = snippet.get('path', '/api').strip()
            rest_op = str(snippet.get('operation', 'get')).lower()
            payload_name = snippet.get('payload', '')
            header_dict = snippet.get('headers', dict())

            # fix for issue #42
            if type(header_dict) is not dict:
                header_dict = dict()

            # FIXME - implement this to give some control over what will be sent to rest server
            content_type = snippet.get('content_type', '')
            accepts_type = snippet.get('accepts_type', '')

            headers = dict()
            if content_type:
                headers["Content-Type"] = content_type

            if accepts_type:
                headers['Accepts-Type'] = accepts_type

            path_template = environment.from_string(rest_path)
            # fix for #111 - ensure we strip and replace only after rendering to ensure inline conditionals work
            # as expected.
            url = path_template.render(context).replace('\n', '').replace(' ', '')

            for k, v in header_dict.items():
                v_template = environment.from_string(v)
                v_interpolated = v_template.render(context)
                print(f'adding {k} as {v_interpolated} to headers')
                headers[k] = v_interpolated

            # keep track of response text or json object
            r = ''
            if rest_op == 'post' and payload_name != '':
                payload_path = os.path.join(snippets_dir, payload_name)
                with open(payload_path, 'r') as payload_file:
                    payload_string = payload_file.read()
                    payload_template = environment.from_string(payload_string)
                    payload_interpolated = payload_template.render(context)
                    if 'Content-Type' in headers and 'form' in headers['Content-Type']:
                        print('Loading json data from payload')
                        try:
                            payload = json.loads(payload_interpolated)
                        except ValueError:
                            print('Could not load payload as json data!')
                            payload = payload_interpolated
                    else:
                        payload = payload_interpolated

                    res = session.post(url, data=payload, verify=False, headers=headers)
                    if res.status_code != 200:
                        print('Found a non-200 response status_code!')
                        print(res.status_code)
                        response['snippets'][name] = res.text
                        response['status'] = 'error'
                        response['message'] = res.status_code
                        break

                    if res.headers.get('content-type') == 'application/json':
                        try:
                            r = res.json()
                        except ValueError:
                            print('Could not parse JSON response from request')
                            r = res.text
                    else:
                        r = res.text

            elif rest_op == 'get':
                print(f'Performing REST get for snippet: {name}')
                res = session.get(url, verify=False)
                if res.headers.get('content-type') == 'application/json':
                    try:
                        r = res.json()
                    except ValueError:
                        r = res.text
                else:
                    r = res.text

                if res.status_code != 200:
                    response['status'] = 'error'
                    response['message'] = res.status_code
                    response['snippets'][name] = r
                    break

            else:
                print('Unknown REST operation found')
                response['status'] = 'Error'
                response['message'] = 'Unknown REST operation found'
                return response

            # collect the response text or json and continue
            response['snippets'][name] = dict()
            response['snippets'][name]['results'] = r
            response['snippets'][name]['outputs'] = dict()

            if 'outputs' in snippet:
                outputs = output_utils.parse_outputs(meta_cnc, snippet, r)
                response['snippets'][name]['outputs'] = outputs
                context.update(outputs)

        # return all the collected response
        return response

    except HTTPError as he:
        response['status'] = 'error'
        response['message'] = str(he)
        return response
    except requests.exceptions.ConnectionError as ce:
        response['status'] = 'error'
        response['message'] = str(ce)
        return response
    except MissingSchema as ms:
        response['status'] = 'error'
        response['message'] = ms
        return response
    except RequestException as re:
        response['status'] = 'error'
        response['message'] = re
        return response
class DynamicInventory(object):
    BASESCRIPT = '''#!/usr/bin/python
import json
data = """{{ data }}"""
data = json.loads(data)
print(json.dumps(data, indent=2, sort_keys=True))
'''

    BASEINV = {
        '_meta': {
            'hostvars': {
                'testhost': {}
            }
        }
    }

    def __init__(self, features):
        self.ENV = Environment()
        self.features = features
        self.fpath = None
        self.inventory = self.BASEINV.copy()
        self.build()

    def build(self):
        xhost = 'testhost'
        if 'script_host' in self.features:
            self.inventory['_meta']['hostvars'][xhost]['findme'] = 'script_host'
        else:
            self.inventory['_meta']['hostvars'][xhost] = {}

        if 'script_child' in self.features:
            self.inventory['child'] = {
                'hosts': [xhost],
                'vars': {'findme': 'script_child'}
            }

        if 'script_parent' in self.features:

            self.inventory['parent'] = {
                'vars': {'findme': 'script_parent'}
            }

            if 'script_child' in self.features:
                self.inventory['parent']['children'] = ['child']
            else:
                self.inventory['parent']['hosts'] = [xhost]

        if 'script_all' in self.features:
            self.inventory['all'] = {
                'hosts': [xhost],
                'vars': {
                    'findme': 'script_all'
                },
            }
        else:
            self.inventory['all'] = {
                'hosts': [xhost],
            }

    def write_script(self):
        fdir = os.path.join(TESTDIR, 'inventory')
        if not os.path.isdir(fdir):
            os.makedirs(fdir)
        fpath = os.path.join(fdir, 'hosts')
        # fpath = os.path.join(TESTDIR, 'inventory')
        self.fpath = fpath

        data = json.dumps(self.inventory)
        t = self.ENV.from_string(self.BASESCRIPT)
        fdata = t.render(data=data)
        with open(fpath, 'w') as f:
            f.write(fdata + '\n')
        st = os.stat(fpath)
        os.chmod(fpath, st.st_mode | stat.S_IEXEC)
Ejemplo n.º 48
0
Archivo: ext.py Proyecto: mateid/shout
 def test_extension_nodes(self):
     env = Environment(extensions=[TestExtension])
     tmpl = env.from_string('{% test %}')
     assert tmpl.render() == 'False|42|23|{}'
Ejemplo n.º 49
0
Archivo: ext.py Proyecto: mateid/shout
 def test_scoping(self):
     env = Environment(extensions=['jinja2.ext.autoescape'])
     tmpl = env.from_string(
         '{% autoescape true %}{% set x = "<x>" %}{{ x }}'
         '{% endautoescape %}{{ x }}{{ "<y>" }}')
     assert tmpl.render(x=1) == '&lt;x&gt;1<y>'
Ejemplo n.º 50
0
 def test_safe(self):
     env = Environment(autoescape=True)
     tmpl = env.from_string('{{ "<div>foo</div>"|safe }}')
     assert tmpl.render() == '<div>foo</div>'
     tmpl = env.from_string('{{ "<div>foo</div>" }}')
     assert tmpl.render() == '&lt;div&gt;foo&lt;/div&gt;'
Ejemplo n.º 51
0
Archivo: ext.py Proyecto: mateid/shout
 def test_preprocessor_extension(self):
     env = Environment(extensions=[PreprocessorExtension])
     tmpl = env.from_string('{[[TEST]]}')
     assert tmpl.render(foo=42) == '{(42)}'
Ejemplo n.º 52
0
 def test_call(self, env):
     env = Environment()
     env.globals['foo'] = lambda a, b, c, e, g: a + b + c + e + g
     tmpl = env.from_string(
         "{{ foo('a', c='d', e='f', *['b'], **{'g': 'h'}) }}")
     assert tmpl.render() == 'abdfh'
Ejemplo n.º 53
0
Archivo: ext.py Proyecto: mateid/shout
 def test_extend_late(self):
     env = Environment()
     env.add_extension('jinja2.ext.autoescape')
     t = env.from_string(
         '{% autoescape true %}{{ "<test>" }}{% endautoescape %}')
     assert t.render() == '&lt;test&gt;'
Ejemplo n.º 54
0
 def test_no_finalize_template_data(self):
     e = Environment(finalize=lambda v: type(v).__name__)
     t = e.from_string("<{{ value }}>")
     # If template data was finalized, it would print "strintstr".
     assert t.render(value=123) == "<int>"
Ejemplo n.º 55
0
class Renderer(object):
    """
        Main engine to convert and ODT document into a jinja
        compatible template.

        Basic use example:
            engine = Renderer('template')
            result = engine.render()


        Renderer provides an enviroment variable which can be used
        to provide custom filters to the ODF render.

            engine = Renderer('template.odt')
            engine.environment.filters['custom_filer'] = filter_function
            result = engine.render()
    """

    def __init__(self, environment=None, **kwargs):
        """
        Create a Renderer instance.

        args:
            environment: Use this jinja2 enviroment. If not specified, we
                         create a new environment for this class instance.

        returns:
            None
        """
        self.log = logging.getLogger(__name__)
        self.log.debug('Initing a Renderer instance\nTemplate')

        if environment:
            self.environment = environment
        else:
            self.environment = Environment(undefined=UndefinedSilently,
                                           autoescape=True)
            # Register filters
            self.environment.filters['pad'] = pad_string
            self.environment.filters['markdown'] = self.markdown_filter
            self.environment.filters['image'] = self.image_filter

        self.media_path = kwargs.pop('media_path', '')
        self.media_callback = self.fs_loader


    def media_loader(self, callback):
        """This sets the the media loader. A user defined function which
        loads media. The function should take a template value, optionals
        args and kwargs. Is media exists should return a tuple whose first
        element if a file object type representing the media and its second
        elements is the media mimetype.

        See Renderer.fs_loader funcion for an example"""
        self.media_callback = callback
        return callback

    def _unpack_template(self, template):
        # And Open/libreOffice is just a ZIP file. Here we unarchive the file
        # and return a dict with every file in the archive
        self.log.debug('Unpacking template file')
        
        archive_files = {}
        archive = zipfile.ZipFile(template, 'r')
        for zfile in archive.filelist:
            archive_files[zfile.filename] = archive.read(zfile.filename)

        return archive_files

        self.log.debug('Unpack completed')

    def _pack_document(self, files):
        # Store to a zip files in files
        self.log.debug('packing document')
        zip_file = io.BytesIO()

        zipdoc = zipfile.ZipFile(zip_file, 'a')
        for fname, content in files.items():
            if sys.version_info >= (2, 7):
                zipdoc.writestr(fname, content, zipfile.ZIP_DEFLATED)
            else:
                zipdoc.writestr(fname, content)

        self.log.debug('Document packing completed')

        return zip_file

    def _prepare_template_tags(self, xml_document):
        """ Here we search for every field node present in xml_document.
        For each field we found we do:
        * if field is a print field ({{ field }}), we replace it with a
          <text:span> node.
        
        * if field is a control flow ({% %}), then we find immediate node of
          type indicated in field's `text:description` attribute and replace
          the whole node and its childrens with field's content.
        
          If `text:description` attribute starts with `before::` or `after::`,
          then we move field content before or after the node in description.
        
          If no `text:description` is available, find the immediate common
          parent of this and any other field and replace its child and 
          original parent of field with the field content.
        
          e.g.: original
          <table>
              <table:row>
                  <field>{% for bar in bars %}</field>
              </table:row>
              <paragraph>
                  <field>{{ bar }}</field>
              </paragraph>
              <table:row>
                  <field>{% endfor %}</field>
              </table:row>
          </table>
          
          After processing:
          <table>
              {% for bar in bars %}
              <paragraph>
                  <text:span>{{ bar }}</text:span>
              </paragraph>
              {% endfor %}
          </table>
        """

        self.log.debug('Preparing template tags')
        fields = xml_document.getElementsByTagName('text:text-input')

        # First, count secretary fields
        for field in fields:
            if not field.hasChildNodes():
                continue

            field_content = field.childNodes[0].data.strip()

            if not re.findall(r'(?is)^{[{|%].*[%|}]}$', field_content):
                # Field does not contains jinja template tags
                continue

            is_block_tag = re.findall(r'(?is)^{%[^{}]*%}$', field_content)
            self.inc_node_fields_count(field.parentNode,
                    'block' if is_block_tag else 'variable')

        # Do field replacement and moving
        for field in fields:
            if not field.hasChildNodes():
                continue

            field_content = field.childNodes[0].data.strip()

            if not re.findall(r'(?is)^{[{|%].*[%|}]}$', field_content):
                # Field does not contains jinja template tags
                continue

            is_block_tag = re.findall(r'(?is)^{%[^{}]*%}$', field_content)
            discard = field
            field_reference = field.getAttribute('text:description').strip().lower()

            if re.findall(r'\|markdown', field_content):
                # a markdown field should take the whole paragraph
                field_reference = 'text:p'

            if field_reference:
                # User especified a reference. Replace immediate parent node
                # of type indicated in reference with this field's content.
                node_type = FLOW_REFERENCES.get(field_reference, False)
                if node_type:
                    discard = self._parent_of_type(field, node_type)

                jinja_node = self.create_text_node(xml_document, field_content)

            elif is_block_tag:
                # Find the common immediate parent of this and any other field.
                while discard.parentNode.secretary_field_count <= 1:
                    discard = discard.parentNode

                if discard is not None:
                    jinja_node = self.create_text_node(xml_document,
                                                       field_content)

            else:
                jinja_node = self.create_text_span_node(xml_document,
                                                        field_content)

            parent = discard.parentNode
            if not field_reference.startswith('after::'):
                parent.insertBefore(jinja_node, discard)
            else:
                if discard.isSameNode(parent.lastChild):
                    parent.appendChild(jinja_node)
                else:
                    parent.insertBefore(jinja_node,
                                        discard.nextSibling)

            if field_reference.startswith(('after::', 'before::')):
                # Do not remove whole field container. Just remove the
                # <text:text-input> parent node if field has it.
                discard = self._parent_of_type(field, 'text:p')
                parent = discard.parentNode

            parent.removeChild(discard)


    @staticmethod
    def _unescape_entities(xml_text):
        """
        Strips tags of the form <text:span ...> from inside Jinja elements
        and unescapes HTML codes for >, <, & and "
        """
        unescape_rules = {
            r'(?is)({([{%])[^%}]*?)(</?text:s.*?>)(.*?[%}]})': r'\1 \4',
            r'(?is)({([{%])[^%}]*?)(&gt;)(.*?[%}]})'         : r'\1>\4',
            r'(?is)({([{%])[^%}]*?)(&lt;)(.*?[%}]})'         : r'\1<\4',
            r'(?is)({([{%])[^%}]*?)(&amp;)(.*?[%}]})'        : r'\1&\4',
            r'(?is)({([{%])[^%}]*?)(&quot;)(.*?[%}]})'       : r'\1"\4',
        }

        for regexp, replacement in unescape_rules.items():
            subs_made = True
            while subs_made:
                xml_text, subs_made = re.subn(regexp, replacement, xml_text)

        return xml_text

    @staticmethod
    def _encode_escape_chars(xml_text):
        # Replace line feed and/or tabs within text span entities.
        find_pattern = r'(?is)<text:([\S]+?)>([^>]*?([\n|\t])[^<]*?)</text:\1>'
        for m in re.findall(find_pattern, xml_text):
            replacement = m[1].replace('\n', '<text:line-break/>')
            replacement = replacement.replace('\t', '<text:tab/>')
            xml_text = xml_text.replace(m[1], replacement)

        return xml_text


    def add_media_to_archive(self, media, mime, name=''):
        """Adds to "Pictures" archive folder the file in `media` and register
        it into manifest file."""
        extension = None
        if hasattr(media, 'name') and not name:
            extension = path.splitext(media.name)
            name      = extension[0]
            extension = extension[1]

        if not extension:
            extension = guess_extension(mime)

        media_path = 'Pictures/%s%s' % (name, extension)
        media.seek(0)
        self.files[media_path] = media.read(-1)
        if hasattr(media, 'close'):
            media.close()

        files_node = self.manifest.getElementsByTagName('manifest:manifest')[0]
        node = self.create_node(self.manifest, 'manifest:file-entry', files_node)
        node.setAttribute('manifest:full-path', media_path)
        node.setAttribute('manifest:media-type', mime)

        return media_path


    def fs_loader(self, media, *args, **kwargs):
        """Loads a file from the file system.
        :param media: A file object or a relative or absolute path of a file.
        :type media: unicode
        """
        if hasattr(media, 'seek') and hasattr(media, 'read'):
            return (media, 'image/jpeg')
        elif path.isfile(media):
            filename = media
        else:
            if not self.media_path:
                self.log.debug('media_path property not specified to load images from.')
                return

            filename = path.join(self.media_path, media)
            if not path.isfile(filename):
                self.log.debug('Media file "%s" does not exists.' % filename)
                return

        mime = guess_type(filename)
        return (open(filename, 'rb'), mime[0] if mime else None)


    def replace_images(self, xml_document):
        """Perform images replacements"""
        self.log.debug('Inserting images')
        frames = xml_document.getElementsByTagName('draw:frame')

        for frame in frames:
            if not frame.hasChildNodes():
                continue

            key = frame.getAttribute('draw:name')
            if key not in self.template_images:
                continue

            # Get frame attributes
            frame_attrs = dict()
            for i in xrange(frame.attributes.length):
                attr = frame.attributes.item(i)
                frame_attrs[attr.name] = attr.value 

            # Get child draw:image node and its attrs
            image_node = frame.childNodes[0]
            image_attrs = dict()
            for i in xrange(image_node.attributes.length):
                attr = image_node.attributes.item(i)
                image_attrs[attr.name] = attr.value 

            # Request to media loader the image to use
            image = self.media_callback(self.template_images[key]['value'],
                                        *self.template_images[key]['args'],
                                        frame_attrs=frame_attrs,
                                        image_attrs=image_attrs,
                                        **self.template_images[key]['kwargs'])

            # Update frame and image node attrs (if they where updated in
            # media_callback call)
            for k, v in frame_attrs.items():
                frame.setAttribute(k, v)
                
            for k, v in image_attrs.items():
                image_node.setAttribute(k, v)

            # Keep original image reference value
            if isinstance(self.template_images[key]['value'], basestring):
                frame.setAttribute('draw:name',
                                   self.template_images[key]['value'])

            # Does the madia loader returned something?
            if not image:
                continue

            mname = self.add_media_to_archive(media=image[0], mime=image[1],
                                              name=key)
            if mname:
                image_node.setAttribute('xlink:href', mname)

    def _render_xml(self, xml_document, **kwargs):
        # Prepare the xml object to be processed by jinja2
        self.log.debug('Rendering XML object')

        try:
            self.template_images = dict()
            self._prepare_template_tags(xml_document)
            template_string = self._unescape_entities(xml_document.toxml())
            jinja_template = self.environment.from_string(template_string)

            result = jinja_template.render(**kwargs)
            result = self._encode_escape_chars(result)

            final_xml = parseString(result.encode('ascii', 'xmlcharrefreplace'))
            if self.template_images:
                self.replace_images(final_xml)

            return final_xml
        except ExpatError as e:
            near = result.split('\n')[e.lineno -1][e.offset-50:e.offset+50]
            raise ExpatError('ExpatError "%s" at line %d, column %d\nNear of: "[...]%s[...]"' % \
                             (ErrorString(e.code), e.lineno, e.offset, near))
        except:
            self.log.error('Error rendering template:\n%s',
                           xml_document.toprettyxml(), exc_info=True)

            self.log.error('Unescaped template was:\n{}'.format(template_string))
            raise
        finally:
            self.log.debug('Rendering xml object finished')


    def render(self, template, **kwargs):
        """
            Render a template

            args:
                template: A template file. Could be a string or a file instance
                **kwargs: Template variables. Similar to jinja2

            returns:
                A binary stream which contains the rendered document.
        """

        self.log.debug('Initing a template rendering')
        self.files = self._unpack_template(template)
        self.render_vars = {}

        # Keep content and styles object since many functions or
        # filters may work with then
        self.content  = parseString(self.files['content.xml']) 
        self.styles   = parseString(self.files['styles.xml'])
        self.manifest = parseString(self.files['META-INF/manifest.xml'])
        
        # Render content.xml keeping just 'office:body' node.
        rendered_content = self._render_xml(self.content, **kwargs)
        self.content.getElementsByTagName('office:document-content')[0].replaceChild(
            rendered_content.getElementsByTagName('office:body')[0],
            self.content.getElementsByTagName('office:body')[0]
        )

        # Render styles.xml
        self.styles = self._render_xml(self.styles, **kwargs)

        self.log.debug('Template rendering finished')

        self.files['content.xml']           = self.content.toxml().encode('ascii', 'xmlcharrefreplace')
        self.files['styles.xml']            = self.styles.toxml().encode('ascii', 'xmlcharrefreplace')
        self.files['META-INF/manifest.xml'] = self.manifest.toxml().encode('ascii', 'xmlcharrefreplace')
        
        document = self._pack_document(self.files)
        return document.getvalue()


    def _parent_of_type(self, node, of_type):
        # Returns the first immediate parent of type `of_type`.
        # Returns None if nothing is found.

        if hasattr(node, 'parentNode'):
            if node.parentNode.nodeName.lower() == of_type:
                return node.parentNode
            else:
                return self._parent_of_type(node.parentNode, of_type)
        else:
            return None

    def create_node(self, xml_document, node_type, parent=None):
        """Creates a node in `xml_document` of type `node_type` and specified,
        as child of `parent`."""
        node = xml_document.createElement(node_type)
        if parent:
            parent.appendChild(node)

        return node

    def create_text_span_node(self, xml_document, content):
        span = xml_document.createElement('text:span')
        text_node = self.create_text_node(xml_document, content)
        span.appendChild(text_node)

        return span

    def create_text_node(self, xml_document, text):
        """
        Creates a text node
        """
        return xml_document.createTextNode(text)

    def inc_node_fields_count(self, node, field_type='variable'):
        """ Increase field count of node and its parents """

        if node is None:
            return

        if not hasattr(node, 'secretary_field_count'):
            setattr(node, 'secretary_field_count', 0)

        if not hasattr(node, 'secretary_variable_count'):
            setattr(node, 'secretary_variable_count', 0)

        if not hasattr(node, 'secretary_block_count'):
            setattr(node, 'secretary_block_count', 0)

        node.secretary_field_count += 1
        if field_type == 'variable':
            node.secretary_variable_count += 1
        else:
            node.secretary_block_count += 1

        self.inc_node_fields_count(node.parentNode, field_type)

    
    def get_style_by_name(self, style_name):
        """
            Search in <office:automatic-styles> for style_name.
            Return None if style_name is not found. Otherwise
            return the style node
        """

        auto_styles = self.content.getElementsByTagName(
            'office:automatic-styles')[0]

        if not auto_styles.hasChildNodes():
            return None

        for style_node in auto_styles.childNodes:
            if style_node.hasAttribute('style:name') and \
               (style_node.getAttribute('style:name') == style_name):
               return style_node

        return None

    def insert_style_in_content(self, style_name, attributes=None,
        **style_properties):
        """
            Insert a new style into content.xml's <office:automatic-styles> node.
            Returns a reference to the newly created node
        """

        auto_styles = self.content.getElementsByTagName('office:automatic-styles')[0]
        style_node = self.content.createElement('style:style')

        style_node.setAttribute('style:name', style_name)
        style_node.setAttribute('style:family', 'text')
        style_node.setAttribute('style:parent-style-name', 'Standard')

        if attributes:
            for k, v in attributes.items():
                style_node.setAttribute('style:%s' % k, v)

        if style_properties:
            style_prop = self.content.createElement('style:text-properties')
            for k, v in style_properties.items():
                style_prop.setAttribute('%s' % k, v)

            style_node.appendChild(style_prop)

        return auto_styles.appendChild(style_node)

    def markdown_filter(self, markdown_text):
        """
            Convert a markdown text into a ODT formated text
        """

        if not isinstance(markdown_text, basestring):
            return ''

        from xml.dom import Node
        from markdown_map import transform_map

        try:
            from markdown2 import markdown
        except ImportError:
            raise SecretaryError('Could not import markdown2 library. Install it using "pip install markdown2"')

        styles_cache = {}   # cache styles searching
        html_text = markdown(markdown_text)
        xml_object = parseString('<html>%s</html>' % html_text.encode('ascii', 'xmlcharrefreplace'))

        # Transform HTML tags as specified in transform_map
        # Some tags may require extra attributes in ODT.
        # Additional attributes are indicated in the 'attributes' property

        for tag in transform_map:
            html_nodes = xml_object.getElementsByTagName(tag)
            for html_node in html_nodes:
                odt_node = xml_object.createElement(transform_map[tag]['replace_with'])

                # Transfer child nodes
                if html_node.hasChildNodes():
                    for child_node in html_node.childNodes:
                        odt_node.appendChild(child_node.cloneNode(True))

                # Add style-attributes defined in transform_map
                if 'style_attributes' in transform_map[tag]:
                    for k, v in transform_map[tag]['style_attributes'].items():
                        odt_node.setAttribute('text:%s' % k, v)

                # Add defined attributes
                if 'attributes' in transform_map[tag]:
                    for k, v in transform_map[tag]['attributes'].items():
                        odt_node.setAttribute(k, v)

                    # copy original href attribute in <a> tag
                    if tag == 'a':
                        if html_node.hasAttribute('href'):
                            odt_node.setAttribute('xlink:href',
                                html_node.getAttribute('href'))

                # Does the node need to create an style?
                if 'style' in transform_map[tag]:
                    name = transform_map[tag]['style']['name']
                    if not name in styles_cache:
                        style_node = self.get_style_by_name(name)

                        if style_node is None:
                            # Create and cache the style node
                            style_node = self.insert_style_in_content(
                                name, transform_map[tag]['style'].get('attributes', None),
                                **transform_map[tag]['style']['properties'])
                            styles_cache[name] = style_node

                html_node.parentNode.replaceChild(odt_node, html_node)

        def node_to_string(node):
            result = node.toxml()

            # linebreaks in preformated nodes should be converted to <text:line-break/>
            if (node.__class__.__name__ != 'Text') and \
                (node.getAttribute('text:style-name') == 'Preformatted_20_Text'):
                result = result.replace('\n', '<text:line-break/>')

            # All double linebreak should be replaced with an empty paragraph
            return result.replace('\n\n', '<text:p text:style-name="Standard"/>')


        return ''.join(node_as_str for node_as_str in map(node_to_string,
                xml_object.getElementsByTagName('html')[0].childNodes))

    def image_filter(self, value, *args, **kwargs):
        """Store value into template_images and return the key name where this
        method stored it. The value returned it later used to load the image
        from media loader and finally inserted into the final ODT document."""
        key = uuid4().hex
        self.template_images[key] = {
            'value': value,
            'args': args,
            'kwargs': kwargs
        }

        return key
Ejemplo n.º 56
0
 def test_finalize_constant_expression(self):
     e = Environment(finalize=lambda v: "" if v is None else v)
     t = e.from_string("<{{ none }}>")
     assert t.render() == "<>"
Ejemplo n.º 57
0
 def test_bool_reject(self, env):
     env = Environment()
     tmpl = env.from_string(
         '{{ [none, false, 0, 1, 2, 3, 4, 5]|reject|join("|") }}')
     assert tmpl.render() == 'None|False|0'
Ejemplo n.º 58
0
 def test_finalize(self):
     e = Environment(finalize=lambda v: "" if v is None else v)
     t = e.from_string("{% for item in seq %}|{{ item }}{% endfor %}")
     assert t.render(seq=(None, 1, "foo")) == "||1|foo"
Ejemplo n.º 59
0
 def test_no_lstrip(self, env):
     env = Environment(lstrip_blocks=True, trim_blocks=False)
     tmpl = env.from_string('''    {%+ if True %}\n    {%+ endif %}''')
     assert tmpl.render() == "    \n    "
Ejemplo n.º 60
0
def test_keyword_folding():
    env = Environment()
    env.filters['testing'] = lambda value, some: value + some
    assert env.from_string("{{ 'test'|testing(some='stuff') }}") \
           .render() == 'teststuff'