Skip to content

Commit

Permalink
normalize render attribute names consistently
Browse files Browse the repository at this point in the history
  • Loading branch information
azmeuk authored and davidism committed May 31, 2020
1 parent 3149b38 commit d9ad60c
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 5 deletions.
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ Unreleased
*extra_filters* parameter. :issue:`128` :pr:`592`
- Fields can be passed the ``name`` argument to use a HTML name
different than their Python name. :issue:`205`, :pr:`601`
- Render attribute names like ``for_`` and ``class_`` are normalized
consistently so later values override those specified earlier.
:issue:`449`, :pr:`596`


Version 2.3.1
Expand Down
5 changes: 5 additions & 0 deletions src/wtforms/meta.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from wtforms import i18n
from wtforms.utils import WebobInputWrapper
from wtforms.widgets.core import clean_key


class DefaultMeta:
Expand Down Expand Up @@ -53,8 +54,12 @@ def render_field(self, field, render_kw):
The default implementation calls ``field.widget(field, **render_kw)``
"""

render_kw = {clean_key(k): v for k, v in render_kw.items()}

other_kw = getattr(field, "render_kw", None)
if other_kw is not None:
other_kw = {clean_key(k): v for k, v in other_kw.items()}
render_kw = dict(other_kw, **render_kw)
return field.widget(field, **render_kw)

Expand Down
12 changes: 8 additions & 4 deletions src/wtforms/widgets/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@
)


def clean_key(key):
key = key.rstrip("_")
if key.startswith("data_") or key.startswith("aria_"):
key = key.replace("_", "-")
return key


def html_params(**kwargs):
"""
Generate HTML attribute syntax from inputted keyword arguments.
Expand Down Expand Up @@ -53,10 +60,7 @@ def html_params(**kwargs):
"""
params = []
for k, v in sorted(kwargs.items()):
if k in ("class_", "class__", "for_"):
k = k[:-1]
elif k.startswith("data_") or k.startswith("aria_"):
k = k.replace("_", "-")
k = clean_key(k)
if v is True:
params.append(k)
elif v is False:
Expand Down
36 changes: 36 additions & 0 deletions tests/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,42 @@ def test_render_kw(self):
'type="text" value="hello">'
)

def test_render_special(self):
class F(Form):
s = StringField(render_kw={"class_": "foo"})

assert F().s() == '<input class="foo" id="s" name="s" type="text" value="">'
assert (
F().s(**{"class": "bar"})
== '<input class="bar" id="s" name="s" type="text" value="">'
)
assert (
F().s(**{"class_": "bar"})
== '<input class="bar" id="s" name="s" type="text" value="">'
)

class G(Form):
s = StringField(render_kw={"class__": "foo"})

assert G().s() == '<input class="foo" id="s" name="s" type="text" value="">'
assert (
G().s(**{"class__": "bar"})
== '<input class="bar" id="s" name="s" type="text" value="">'
)

class H(Form):
s = StringField(render_kw={"for_": "foo"})

assert H().s() == '<input for="foo" id="s" name="s" type="text" value="">'
assert (
H().s(**{"for": "bar"})
== '<input for="bar" id="s" name="s" type="text" value="">'
)
assert (
H().s(**{"for_": "bar"})
== '<input for="bar" id="s" name="s" type="text" value="">'
)

def test_select_field_copies_choices(self):
class F(Form):
items = SelectField(choices=[])
Expand Down
2 changes: 1 addition & 1 deletion tests/test_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class TestHTMLParams:
def test_basic(self):
assert html_params(foo=9, k="wuuu") == 'foo="9" k="wuuu"'
assert html_params(class_="foo") == 'class="foo"'
assert html_params(class__="foo") == 'class_="foo"'
assert html_params(class__="foo") == 'class="foo"'
assert html_params(for_="foo") == 'for="foo"'
assert html_params(readonly=False, foo=9) == 'foo="9"'
assert (
Expand Down

0 comments on commit d9ad60c

Please sign in to comment.