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

68 statements  

1import warnings 

2from dataclasses import dataclass 

3from dataclasses import field 

4 

5from wtforms import widgets 

6from wtforms._compat import get_signature 

7from wtforms.fields.choices import Choice 

8 

9__all__ = ("DataList", "DataListChoice") 

10 

11 

12@dataclass 

13class DataListChoice: 

14 """ 

15 An option declared via :class:`~wtforms.DataList`'s ``choices=`` 

16 parameter. 

17 

18 :param value: 

19 The value rendered as the ``<option>``'s ``value`` attribute. 

20 :param label: 

21 The label of the option. Defaults to ``value`` when omitted. 

22 :param render_kw: 

23 A dict containing HTML attributes that will be rendered 

24 with the option. Defaults to an empty dict when omitted. 

25 """ 

26 

27 value: str 

28 label: str | None = None 

29 render_kw: dict = field(default_factory=dict) 

30 

31 def __post_init__(self): 

32 if self.label is None: 

33 self.label = self.value 

34 

35 def __iter__(self): 

36 return iter((self.value, self.label, self.render_kw)) 

37 

38 @classmethod 

39 def from_enum(cls, enum_cls, *, label=None): 

40 """Build a list of choices from an :class:`enum.Enum` class. 

41 

42 See :meth:`SelectChoice.from_enum` for details. 

43 """ 

44 if label is None: 

45 label = str if "__str__" in enum_cls.__dict__ else lambda m: m.name 

46 return [cls(value=m.name, label=label(m)) for m in enum_cls] 

47 

48 @classmethod 

49 def from_input(cls, input): 

50 """Coerce a value passed by the user into a :class:`DataListChoice`.""" 

51 if isinstance(input, DataListChoice): 

52 return input 

53 

54 if isinstance(input, Choice): 

55 warnings.warn( 

56 "Passing Choice to a DataList is deprecated; Choice is the " 

57 "output type returned by iter_choices(). Use DataListChoice " 

58 "instead. Support for Choice as input will be removed in " 

59 "WTForms 4.0.", 

60 DeprecationWarning, 

61 stacklevel=4, 

62 ) 

63 return cls( 

64 value=input.value, 

65 label=input.label, 

66 render_kw=input.render_kw, 

67 ) 

68 

69 if isinstance(input, str): 

70 return cls(value=input) 

71 

72 if isinstance(input, tuple): 

73 return cls(*input) 

74 

75 

76class DataList: 

77 """A ``<datalist>`` of suggestions attached to a single field. 

78 

79 Passed to a :class:`~wtforms.Field` via its ``datalist=`` parameter 

80 to add an autocomplete-style list of choices. See the WTForms 

81 fields documentation for usage. 

82 """ 

83 

84 widget = widgets.DataListWidget() 

85 

86 def __init__(self, choices=None, *, render_kw=None, widget=None): 

87 self._raw_choices = choices 

88 self._choices = None if callable(choices) else choices 

89 self.render_kw = render_kw or {} 

90 if widget is not None: 

91 self.widget = widget 

92 self.id = None 

93 

94 def _clone(self, id): 

95 clone = DataList.__new__(DataList) 

96 clone._raw_choices = self._raw_choices 

97 clone._choices = None if callable(self._raw_choices) else self._raw_choices 

98 clone.render_kw = self.render_kw 

99 clone.widget = self.widget 

100 clone.id = id 

101 return clone 

102 

103 def _resolve(self, field): 

104 raw = self._raw_choices 

105 if not callable(raw): 

106 return 

107 try: 

108 sig = get_signature(raw) 

109 sig.bind(field._form, field) 

110 except TypeError: 

111 self._choices = raw() 

112 return 

113 self._choices = raw(field._form, field) 

114 

115 def iter_choices(self, field=None): 

116 raw = self._choices 

117 if raw is None: 

118 return [] 

119 return [DataListChoice.from_input(item) for item in raw] 

120 

121 def __call__(self, field=None, **kwargs): 

122 return self.widget(self, field=field, **kwargs)