Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/wtforms/fields/form.py: 32%

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

57 statements  

1from wtforms.utils import unset_value 

2 

3from .. import widgets 

4from .core import Field 

5 

6__all__ = ("FormField",) 

7 

8 

9class FormField(Field): 

10 """ 

11 Encapsulate a form as a field in another form. 

12 

13 :param form_class: 

14 A subclass of Form that will be encapsulated. 

15 :param separator: 

16 A string which will be suffixed to this field's name to create the 

17 prefix to enclosed fields. The default is fine for most uses. 

18 """ 

19 

20 widget = widgets.TableWidget() 

21 

22 def __init__( 

23 self, form_class, label=None, validators=None, separator="-", **kwargs 

24 ): 

25 super().__init__(label, validators, **kwargs) 

26 self.form_class = form_class 

27 self.separator = separator 

28 self._obj = None 

29 if self.filters: 

30 raise TypeError( 

31 "FormField cannot take filters, as the encapsulated" 

32 " data is not mutable." 

33 ) 

34 if validators: 

35 raise TypeError( 

36 "FormField does not accept any validators. Instead," 

37 " define them on the enclosed form." 

38 ) 

39 

40 def process(self, formdata, data=unset_value, extra_filters=None): 

41 if extra_filters: 

42 raise TypeError( 

43 "FormField cannot take filters, as the encapsulateddata is not mutable." 

44 ) 

45 

46 if data is unset_value: 

47 try: 

48 data = self.default() 

49 except TypeError: 

50 data = self.default 

51 self._obj = data 

52 

53 self.object_data = data 

54 

55 prefix = self.name + self.separator 

56 if isinstance(data, dict): 

57 user_meta = data.get("meta") or {} 

58 data_kwargs = {k: v for k, v in data.items() if k != "meta"} 

59 self.form = self.form_class( 

60 formdata=formdata, 

61 prefix=prefix, 

62 meta={**user_meta, "_parent_form": self._form}, 

63 **data_kwargs, 

64 ) 

65 else: 

66 self.form = self.form_class( 

67 formdata=formdata, 

68 obj=data, 

69 prefix=prefix, 

70 meta={"_parent_form": self._form}, 

71 ) 

72 

73 def post_process(self): 

74 self.form.post_process() 

75 

76 def validate(self, form, extra_validators=()): 

77 if extra_validators: 

78 raise TypeError( 

79 "FormField does not accept in-line validators, as it" 

80 " gets errors from the enclosed form." 

81 ) 

82 return self.form.validate() 

83 

84 def populate_obj(self, obj, name): 

85 candidate = getattr(obj, name, None) 

86 if candidate is None: 

87 if self._obj is None: 

88 raise TypeError( 

89 "populate_obj: cannot find a value to populate from" 

90 " the provided obj or input data/defaults" 

91 ) 

92 candidate = self._obj 

93 

94 self.form.populate_obj(candidate) 

95 setattr(obj, name, candidate) 

96 

97 def __iter__(self): 

98 return iter(self.form) 

99 

100 def __getitem__(self, name): 

101 return self.form[name] 

102 

103 def __getattr__(self, name): 

104 return getattr(self.form, name) 

105 

106 @property 

107 def data(self): 

108 return self.form.data 

109 

110 @property 

111 def errors(self): 

112 return self.form.errors