Skip to content

Instantly share code, notes, and snippets.

@Kroisse
Forked from yoloseem/htmlfill.py
Last active December 15, 2015 23:59
Show Gist options
  • Save Kroisse/5343856 to your computer and use it in GitHub Desktop.
Save Kroisse/5343856 to your computer and use it in GitHub Desktop.
__pycache__/
*.pyc
"""Jinja2 x htmlfill
Known bugs: Can't skip empty dictionaries when htmlfilling is not needed.
# AUTHOR: HYUNJUN KIM <kim@hyunjun.kr>
# LICENSE: Distributed under MIT License.
"""
import formencode.htmlfill
import jinja2
import jinja2.ext
import jinja2.nodes
class FormFillExtension(jinja2.ext.Extension):
"""Jinja2 Extension for convenient using of HTML ``<form>`` element.
Works with `FormEncode htmlfill`__ ::
{% formfill {'username': 'james'}
with {'username': 'Invalid Username'} %}
<form action="u/signin" method="POST">
<input type="text" name="username" />
<form:error name="username">
<input type="password" name="password" />
</form>
{% endformfill %}
Above code will be rendered like below ::
<form action="u/signin" method="POST">
<input type="text" name="username" class="error" value="james" />
<ul class="errors"><li>Invalid Username</li></ul>
<input type="password" name="password" value="" />
</form>
__ http://www.formencode.org/en/latest/htmlfill.html
.. seealso::
gist --- `formencode htmlfill in jinja2 template`__
__ https://gist.github.com/4595277
"""
tags = set(['formfill'])
def parse(self, parser):
lineno = parser.stream.next().lineno
defaults = parser.parse_expression()
errors = jinja2.nodes.Const({})
name = parser.stream.next_if('name')
if name is not None:
if name.value == 'with':
errors = parser.parse_expression()
if isinstance(defaults, jinja2.nodes.Name):
defaults = jinja2.nodes.Getattr(jinja2.nodes.ContextReference(),
defaults.name, self.environment)
if isinstance(errors, jinja2.nodes.Name):
errors = jinja2.nodes.Getattr(jinja2.nodes.ContextReference(),
errors.name, self.environment)
body = parser.parse_statements(['name:endformfill'], drop_needle=True)
body = [jinja2.nodes.CallBlock(
self.call_method('_htmlfill_support', (defaults, errors)),
[], [], body).set_lineno(lineno)]
return body
def _htmlfill_support(self, defaults, errors, caller):
formatters = {
'default': lambda msg: u'<ul class="errors"><li>{0}</li></ul>' \
.format(msg)
}
return formencode.htmlfill.render(caller(), defaults, errors,
error_formatters=formatters)
import pytest
import jinja2
import htmlfill
@pytest.fixture
def jinja_env():
env = jinja2.Environment(extensions=[htmlfill.FormFillExtension])
return env
def test_formfill(jinja_env):
template = '''
{% formfill {'username': 'james'} with {'username': 'Invalid Username'} -%}
<form action="u/signin" method="POST">
<input type="text" name="username" />
<form:error name="username">
<input type="password" name="password" />
</form>
{%- endformfill %}'''
expected = '''
<form action="u/signin" method="POST">
<input type="text" name="username" class="error" value="james" />
<ul class="errors"><li>Invalid Username</li></ul>
<input type="password" name="password" value="" />
</form>'''
result = jinja_env.from_string(template).render()
assert result == expected
def test_formfill_without_errors(jinja_env):
template = '''
{% formfill {'username': 'james'} -%}
<form action="u/signin" method="POST">
<input type="text" name="username" />
<form:error name="username">
<input type="password" name="password" />
</form>
{%- endformfill %}'''
expected = '''
<form action="u/signin" method="POST">
<input type="text" name="username" value="james" />
<input type="password" name="password" value="" />
</form>'''
result = jinja_env.from_string(template).render()
assert result == expected
def test_formfill_without_args(jinja_env):
template = '''
{% formfill -%}
<form action="u/signin" method="POST">
<input type="text" name="username" />
<input type="password" name="password" />
</form>
{%- endformfill %}'''
template2 = '''
{% formfill {'username': 'james'} with -%}
<form action="u/signin" method="POST">
<input type="text" name="username" />
<input type="password" name="password" />
</form>
{%- endformfill %}'''
with pytest.raises(jinja2.TemplateSyntaxError):
jinja_env.from_string(template).render()
with pytest.raises(jinja2.TemplateSyntaxError):
jinja_env.from_string(template2).render()
def test_formfill_with_wrong_args(jinja_env):
template = '''
{% formfill 'user.signin' -%}
<form action="u/signin" method="POST">
<input type="text" name="username" />
<input type="password" name="password" />
</form>
{%- endformfill %}'''
with pytest.raises(AttributeError) as exc:
jinja_env.from_string(template).render()
assert "'str' object has no attribute 'get'" in str(exc)
template2 = '''
{% formfill {'username': 'james'} with ['Invalid Username'] -%}
<form action="u/signin" method="POST">
<input type="text" name="username" />
<input type="password" name="password" />
</form>
{%- endformfill %}'''
with pytest.raises(AttributeError) as exc:
jinja_env.from_string(template2).render()
assert "'list' object has no attribute 'get'" in str(exc)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment