def test_email_field(): assert Form(data=Data(foo=' 5 '), fields=[Field.email(name='foo')]).fields[0].errors == { u'Enter a valid email address.' } assert Form(data=Data(foo='*****@*****.**'), fields=[Field.email(name='foo')]).is_valid()
def test_integer_field(): assert Form(data=Data(foo=' 7 '), fields=[Field.integer(name='foo')]).fields[0].parsed_data == 7 actual_errors = Form(data=Data(foo=' foo '), fields=[Field.integer(name='foo')]).fields[0].errors assert_one_error_and_matches_reg_exp( actual_errors, "invalid literal for int\(\) with base 10: u?'foo'")
def test_float_field(): assert Form(data=Data(foo=' 7.3 '), fields=[Field.float(name='foo')]).fields[0].parsed_data == 7.3 assert Form(data=Data(foo=' foo '), fields=[Field.float(name='foo')]).fields[0].errors == { "could not convert string to float: foo" }
def test_comma_separated_errors_on_parse(): def raise_always_value_error(string_value, **_): raise ValueError('foo %s!' % string_value) def raise_always_validation_error(string_value, **_): raise ValidationError( ['foo %s!' % string_value, 'bar %s!' % string_value]) assert Form(data=Data(foo='5, 7'), fields=[ Field.comma_separated( Field(name='foo', parse=raise_always_value_error)) ]).fields[0].errors == { u'Invalid value "5": foo 5!', u'Invalid value "7": foo 7!' } assert Form(data=Data(foo='5, 7'), fields=[ Field.comma_separated( Field(name='foo', parse=raise_always_validation_error)) ]).fields[0].errors == { u'Invalid value "5": foo 5!', u'Invalid value "5": bar 5!', u'Invalid value "7": foo 7!', u'Invalid value "7": bar 7!' }
def form(self): """ Create a form and validate input based on a request. """ if self._form: return self._form fields = [] if any(v.freetext for v in self.variables): fields.append(Field(name=FREETEXT_SEARCH_NAME, label='Search', required=False)) for variable in self.bound_variables: if variable.gui is not None and variable.gui.show: # pass gui__* parameters to the GUI component assert variable.name is not MISSING assert variable.attr is not MISSING params = merged(variable.gui, name=variable.name, attr=variable.attr) fields.append(params.pop('class')(**params)) form = Form( request=self.request, fields=fields, endpoint_dispatch_prefix='__'.join([self.endpoint_dispatch_prefix, 'gui']), **self.gui_kwargs) form.tri_query = self form.tri_query_advanced_value = request_data(self.request).get(ADVANCED_QUERY_PARAM, '') self._form = form return form
def test_show(): assert list( Form(data=Data(), fields=[Field(name='foo', show=False)]).fields_by_name.keys()) == [] assert list( Form(data=Data(), fields=[Field(name='foo', show=lambda form, field: False) ]).fields_by_name.keys()) == []
def test_phone_field(): assert Form( data=Data(foo=' asdasd '), fields=[Field.phone_number(name='foo')] ).fields[0].errors == { u'Please use format +<country code> (XX) XX XX. Example of US number: +1 (212) 123 4567 or +1 212 123 4567' } assert Form(data=Data(foo='+1 (212) 123 4567'), fields=[Field.phone_number(name='foo')]).is_valid() assert Form(data=Data(foo='+46 70 123 123'), fields=[Field.phone_number(name='foo')]).is_valid()
def test_roundtrip_from_initial_to_raw_string(): for raw, initial in raw_and_parsed_data_tuples: form = Form(fields=[shortcut(required=True, name='foo', initial=initial)], data={}) assert not form.get_errors() f = form.fields_by_name['foo'] if f.is_list: assert initial == f.value_list else: assert initial == f.value assert raw == f.rendered_value(), 'Roundtrip failed'
def test_roundtrip_from_raw_string_to_initial(): for raw, initial in raw_and_parsed_data_tuples: form = Form(fields=[shortcut(required=True, name='foo')], data={'foo': raw}) assert not form.get_errors(), 'input: %s' % raw f = form.fields_by_name['foo'] if f.is_list: assert f.raw_data_list == raw assert f.value_list == initial if initial: assert [type(x) for x in f.value_list] == [type(x) for x in initial] else: assert f.raw_data == raw assert f.value == initial assert type(f.value) == type(initial)
def test_render_template_string(): assert Form(data=Data(foo='7'), fields=[ Field(name='foo', template=None, template_string='{{ field.value }} {{ form.style }}') ]).compact() == '7 compact\n' + AVOID_EMPTY_FORM
def test_field_from_model_many_to_one_foreign_key(): assert set( Form.from_model( data={}, model=Bar, field__foo__class=Field.from_model).fields_by_name.keys()) == { 'foo' }
def test_render_datetime_iso(): table = Form(fields=[ Field.datetime(name='foo', initial=datetime(2001, 2, 3, 12, 13, 14, 7777)) ]).table() assert '2001-02-03 12:13:14' in table assert '7777' not in table
def test_render_custom(): sentinel = '!!custom!!' assert sentinel in Form(fields=[ Field(name='foo', initial='not sentinel value', render_value=lambda form, field, value: sentinel), ]).table()
def test_boolean_initial_true(): fields = [ Field.boolean(name='foo', initial=True), Field(name='bar', required=False) ] form = Form(data=Data(), fields=fields) assert form.fields_by_name['foo'].value is True # If there are arguments, but not for key foo it means checkbox for foo has been unchecked. # Field foo should therefore be false. form = Form(data=Data(bar='baz', **{'-': '-'}), fields=fields) assert form.fields_by_name['foo'].value is False form = Form(data=Data(foo='on', bar='baz', **{'-': '-'}), fields=fields) assert form.fields_by_name['foo'].value is True
def test_form_from_model_valid_form(): assert [ x.value for x in Form.from_model( model=FormFromModelTest, include=['f_int', 'f_float', 'f_bool'], data=Data(f_int='1', f_float='1.1', f_bool='true')).fields ] == [1, 1.1, True]
def test_field_from_model_foreign_key2(): form = Form.from_model( data={}, model=FieldFromModelOneToOneTest, field__foo_one_to_one__class=Field.from_model_expand, field__foo_one_to_one__field__foo__label='blaha', ) assert set(form.fields_by_name.keys()) == {'foo_one_to_one__foo'} assert form.fields_by_name['foo_one_to_one__foo'].label == 'blaha'
def test_form_from_model_valid_form(): assert [x.value for x in Form.from_model( model=FormFromModelTest, include=['f_int', 'f_float', 'f_bool'], data=dict(f_int='1', f_float='1.1', f_bool='true') ).fields] == [ 1, 1.1, True ]
def test_comma_separated_errors_on_validation(): assert Form(data=Data(foo='5, 7'), fields=[ Field.comma_separated( Field(name='foo', is_valid=lambda parsed_data, **_: (False, 'foo %s!' % parsed_data))) ]).fields[0].errors == { u'Invalid value "5": foo 5!', u'Invalid value "7": foo 7!' }
def test_form_from_model_invalid_form(): actual_errors = [x.errors for x in Form.from_model( model=FormFromModelTest, exclude=['f_int_excluded'], data=dict(f_int='1.1', f_float='true', f_bool='asd', f_file='foo') ).fields] assert len(actual_errors) == 4 assert {'could not convert string to float: true'} in actual_errors assert {u'asd is not a valid boolean value'} in actual_errors assert {"invalid literal for int() with base 10: '1.1'"} in actual_errors or {"invalid literal for int() with base 10: u'1.1'"} in actual_errors
def form(self, request): """ Create a form and validate input based on a request. """ fields = [] if any(v.freetext for v in self.variables): fields.append(Field(name=FREETEXT_SEARCH_NAME, label='Search', required=False)) for variable in self.variables: if variable.gui.show: # pass gui__* parameters to the GUI component params = merged(variable.gui, name=variable.name) fields.append(params.pop('class')(**params)) form = Form(request=request, fields=fields, **self.gui_kwargs) form.request = request form.tri_query = self form.tri_query_advanced_value = request_data(request).get(ADVANCED_QUERY_PARAM, '') return form
def test_null_field_factory(): class ShouldBeNullField(models.Field): pass class FooModel(models.Model): should_be_null = ShouldBeNullField() foo = models.IntegerField() register_field_factory(ShouldBeNullField, lambda **_: None) form = Form.from_model(data=None, model=FooModel) assert list(form.fields_by_name.keys()) == ['foo']
def test_render_table(): form = Form(data=Data(foo='!!!7!!!'), fields=[ Field( name='foo', input_container_css_classes={'###5###'}, label_container_css_classes={'$$$11$$$'}, help_text='^^^13^^^', label='***17***', ) ]) table = form.table() assert '!!!7!!!' in table assert '###5###' in table assert '$$$11$$$' in table assert '^^^13^^^' in table assert '***17***' in table assert '<tr' in table # Assert that table is the default assert table == "%s" % form
def test_render_table(): form = Form( data=Data(foo='!!!7!!!'), fields=[ Field( name='foo', input_container_css_classes={'###5###'}, label_container_css_classes={'$$$11$$$'}, help_text='^^^13^^^', label='***17***', ) ]).validate() table = form.table() assert '!!!7!!!' in table assert '###5###' in table assert '$$$11$$$' in table assert '^^^13^^^' in table assert '***17***' in table assert '<tr' in table # Assert that table is the default assert table == unicode(form)
def test_form_from_model_invalid_form(): actual_errors = [ x.errors for x in Form.from_model( model=FormFromModelTest, exclude=['f_int_excluded'], data=Data(f_int='1.1', f_float='true', f_bool='asd')).fields ] assert len(actual_errors) == 3 assert {'could not convert string to float: true'} in actual_errors assert {u'asd is not a valid boolean value'} in actual_errors assert {"invalid literal for int() with base 10: '1.1'" } in actual_errors or { "invalid literal for int() with base 10: u'1.1'" } in actual_errors
def test_radio(): choices = [ 'a', 'b', 'c', ] soup = BeautifulSoup( Form(data=Data(foo='a'), fields=[Field.radio(name='foo', choices=choices)]).table()) assert len( soup.find_all('input')) == len(choices) + 1 # +1 for AVOID_EMPTY_FORM assert [ x.attrs['value'] for x in soup.find_all('input') if 'checked' in x.attrs ] == ['a']
def test_empty_data(): f = Form(fields=[shortcut(required=False, name='foo')], data={}) assert not f.get_errors() assert f.fields_by_name['foo'].value is None assert f.fields_by_name['foo'].value_list is None
def test_datetime_not_required(): assert Form(fields=[Field.datetime(required=False, name='foo')], data={ 'foo': '' }).is_valid()
def test_editable_false(): f = Form(fields=[shortcut(required=False, name='foo', initial=SENTINEL, editable=False)], data={'foo': 'asdasasd'}) assert not f.get_errors() assert f.fields_by_name['foo'].value is SENTINEL or f.fields_by_name['foo'].value_list is SENTINEL
def test_normalizing(): for non_normalized, normalized in normalizing: form = Form(fields=[shortcut(required=True, name='foo')], data={'foo': non_normalized}) assert not form.get_errors() assert form.fields_by_name['foo'].rendered_value() == normalized
def test_json_parsing(): # NOTE: Parsing json input requires that any numbers that come in must avoid the string strip f = Form(data={'foo': 1}, fields=[Field.integer(name='foo', strip_input=False)]) assert f.is_valid() assert f.fields_by_name['foo'].value == 1
def test_help_text_from_model(): assert Form(data=Data(foo='1'), fields=[Field.from_model(model=Foo, field_name='foo')], model=Foo).fields[0].help_text == 'foo_help_text'
def test_multi_choice(): soup = BeautifulSoup( Form(data=Data(foo=['0']), fields=[Field.multi_choice(name='foo', choices=['a'])]).table()) assert [x.attrs['multiple'] for x in soup.find_all('select')] == ['']
def test_password(): assert ' type="password" ' in Form(data=Data(foo='1'), fields=[Field.password(name='foo') ]).table()
def test_hidden(): soup = BeautifulSoup( Form(data=Data(foo='1'), fields=[Field.hidden(name='foo')]).table()) assert [(x.attrs['type'], x.attrs['value']) for x in soup.find_all('input')] == [('hidden', '1'), ('hidden', '-')]
def test_info(): form = Form(data={}, fields=[Field.info(value='#foo#')]) assert form.is_valid() assert '#foo#' in form.table()
def test_heading(): assert '<th colspan="2">#foo#</th>' in Form( data={}, fields=[Field.heading(label='#foo#')]).table()
def test_field_from_model_many_to_one_foreign_key(): assert set(Form.from_model( data={}, model=Bar, field__foo__class=Field.from_model ).fields_by_name.keys()) == {'foo'}
def test_render_template(): assert '<form' in Form(request=RequestFactory().get('/'), data=Data(foo='7'), fields=[Field(name='foo')]).render()
def test_field_from_model_foreign_key2(): assert Form.from_model(data={}, model=FieldFromModelOneToOneTest, foo_one_to_one__class=Field.from_model_expand).fields_by_name.keys() == ['foo_one_to_one__foo']
def test_form_from_model(): assert [x.value for x in Form.from_model(model=FormFromModelTest, include=['f_int', 'f_float', 'f_bool'], data=Data(f_int='1', f_float='1.1', f_bool='true')).validate().fields] == [1, 1.1, True] assert [x.errors for x in Form.from_model(model=FormFromModelTest, exclude=['f_int_excluded'], data=Data(f_int='1.1', f_float='true', f_bool='asd')).validate().fields] == [{"invalid literal for int() with base 10: '1.1'"}, {'could not convert string to float: true'}, {u'asd is not a valid boolean value'}]
def test_render_attrs(): assert Form(data=Data(foo='7'), fields=[Field(name='foo', attrs={'foo': '1'}) ]).fields[0].render_attrs() == ' foo="1"' assert Form(data=Data(foo='7'), fields=[Field(name='foo')]).fields[0].render_attrs() == ' '
def prepare(self, request): if self._has_prepared: return self.request = request def bind_columns(): for index, column in enumerate(self.columns): values = evaluate_recursive(Struct(column), table=self, column=column) values = merged(values, column=column, table=self, index=index) yield BoundColumn(**values) self.bound_columns = list(bind_columns()) self.bound_column_by_name = OrderedDict( (bound_column.name, bound_column) for bound_column in self.bound_columns) self._has_prepared = True self._prepare_evaluate_members() self._prepare_sorting() headers = self._prepare_headers() if self.Meta.model: def generate_variables(): for column in self.bound_columns: if column.query.show: query_kwargs = setdefaults_path( Struct(), column.query, dict( name=column.name, gui__label=column.display_name, attr=column.attr, model=column.table.Meta.model, ), { 'class': Variable, }) yield query_kwargs.pop('class')(**query_kwargs) variables = list(generate_variables()) self.query = Query(request=request, variables=variables, **self.query_kwargs) self.query_form = self.query.form( ) if self.query.variables else None self.query_error = '' if self.query_form: try: self.data = self.data.filter(self.query.to_q()) except QueryException as e: self.query_error = str(e) def generate_bulk_fields(): for column in self.bound_columns: if column.bulk.show: bulk_kwargs = setdefaults_path( Struct(), column.bulk, dict( name=column.name, attr=column.attr, required=False, empty_choice_tuple=(None, '', '---', True), model=self.Meta.model, ), { 'class': Field.from_model, }) if bulk_kwargs['class'] == Field.from_model: bulk_kwargs['field_name'] = column.attr yield bulk_kwargs.pop('class')(**bulk_kwargs) bulk_fields = list(generate_bulk_fields()) self.bulk_form = Form(data=request.POST, fields=bulk_fields, endpoint_dispatch_prefix='bulk', **self.bulk_kwargs) if bulk_fields else None self._prepare_auto_rowspan() return headers, self.header_levels
def test_render_attrs_new_style(): assert Form(data=Data(foo='7'), fields=[Field(name='foo', attrs__foo='1') ]).fields[0].render_attrs() == ' foo="1"' assert Form(data=Data(foo='7'), fields=[Field(name='foo')]).fields[0].render_attrs() == ' '
def test_multi_select_with_one_value_only(): assert ['a'] == Form( data=Data(foo=['a']), fields=[Field.multi_choice(name='foo', choices=['a', 'b'])]).fields[0].value_list