Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/wtforms/datalist.py: 37%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import warnings
2from dataclasses import dataclass
3from dataclasses import field
5from wtforms import widgets
6from wtforms._compat import get_signature
7from wtforms.fields.choices import _enum_options
8from wtforms.fields.choices import Choice
10__all__ = ("DataList", "DataListChoice", "enum_datalist")
13@dataclass
14class DataListChoice:
15 """
16 An option declared via :class:`~wtforms.DataList`'s ``choices=``
17 parameter.
19 :param value:
20 The value rendered as the ``<option>``'s ``value`` attribute.
21 :param label:
22 The label of the option. Defaults to ``value`` when omitted.
23 :param render_kw:
24 A dict containing HTML attributes that will be rendered
25 with the option. Defaults to an empty dict when omitted.
26 """
28 value: str
29 label: str | None = None
30 render_kw: dict = field(default_factory=dict)
32 def __post_init__(self):
33 if self.label is None:
34 self.label = self.value
36 def __iter__(self):
37 return iter((self.value, self.label, self.render_kw))
39 @classmethod
40 def from_input(cls, input):
41 """Coerce a value passed by the user into a :class:`DataListChoice`."""
42 if isinstance(input, DataListChoice):
43 return input
45 if isinstance(input, Choice):
46 warnings.warn(
47 "Passing Choice to a DataList is deprecated; Choice is the "
48 "output type returned by iter_choices(). Use DataListChoice "
49 "instead. Support for Choice as input will be removed in "
50 "WTForms 4.0.",
51 DeprecationWarning,
52 stacklevel=4,
53 )
54 return cls(
55 value=input.value,
56 label=input.label,
57 render_kw=input.render_kw,
58 )
60 if isinstance(input, str):
61 return cls(value=input)
63 if isinstance(input, tuple):
64 return cls(*input)
67def enum_datalist(enum_cls, *, by="value", label=None):
68 """Build a list of :class:`DataListChoice` from an :class:`enum.Enum` class.
70 Same semantics as :func:`~wtforms.fields.enum_choices`: ``by`` selects
71 which member attribute becomes the ``<option>`` value (``"value"`` by
72 default, ``"name"`` otherwise) and ``label`` defaults to ``str(member)``
73 when the Enum defines its own ``__str__``, else ``member.name``.
75 A ``<datalist>`` only suggests values for a free-text field, so there is
76 no coercion counterpart — the field stores whatever string is submitted.
77 """
78 return _enum_options(enum_cls, by, label, DataListChoice)
81class DataList:
82 """A ``<datalist>`` of suggestions attached to a single field.
84 Passed to a :class:`~wtforms.Field` via its ``datalist=`` parameter
85 to add an autocomplete-style list of choices. See the WTForms
86 fields documentation for usage.
87 """
89 widget = widgets.DataListWidget()
91 def __init__(self, choices=None, *, render_kw=None, widget=None):
92 self._raw_choices = choices
93 self._choices = None if callable(choices) else choices
94 self.render_kw = render_kw or {}
95 if widget is not None:
96 self.widget = widget
97 self.id = None
99 def _clone(self, id):
100 clone = DataList.__new__(DataList)
101 clone._raw_choices = self._raw_choices
102 clone._choices = None if callable(self._raw_choices) else self._raw_choices
103 clone.render_kw = self.render_kw
104 clone.widget = self.widget
105 clone.id = id
106 return clone
108 def _resolve(self, field):
109 raw = self._raw_choices
110 if not callable(raw):
111 return
112 try:
113 sig = get_signature(raw)
114 sig.bind(field._form, field)
115 except TypeError:
116 self._choices = raw()
117 return
118 self._choices = raw(field._form, field)
120 def iter_choices(self, field=None):
121 raw = self._choices
122 if raw is None:
123 return []
124 if isinstance(raw, dict):
125 return [
126 DataListChoice(value=value, label=label) for value, label in raw.items()
127 ]
128 return [DataListChoice.from_input(item) for item in raw]
130 def __call__(self, field=None, **kwargs):
131 return self.widget(self, field=field, **kwargs)