def test_setattr_path(): assert getattr_path(setattr_path(Struct(a=0), 'a', 1), 'a') == 1 assert getattr_path(setattr_path(Struct(a=Struct(b=0)), 'a__b', 2), 'a__b') == 2 with pytest.raises(AttributeError): setattr_path(Struct(a=1), 'a__b', 1)
def test_order_after_name_last(): sorts_right([ Struct(name='foo', expected_position=0), Struct(name='quux', after='qoox', expected_position=3), Struct(name='qoox', after=LAST, expected_position=2), Struct(name='bar', expected_position=1), ])
def test_getattr_path(): assert getattr_path(Struct(a=1), 'a') == 1 assert getattr_path(Struct(a=Struct(b=2)), 'a__b') == 2 with pytest.raises(AttributeError): getattr_path(Struct(a=2), 'b') assert getattr_path(Struct(a=None), 'a__b__c__d') is None
def test_order_after_0(): sorts_right([ Struct(name='foo', expected_position=1), Struct(name='bar', expected_position=2), Struct(name='quux', after=0, expected_position=0), Struct(name='baz', expected_position=3), ])
def test_parse(): # The spaces in the data are there to check that we strip input form = MyTestForm(request=Struct(method='POST', POST=Data(party='ABC ', username='******', joined=' 2014-12-12 01:02:03 ', staff=' true', admin='false ', manages=['DEF ', 'KTH '], a_date=' 2014-02-12 ', a_time=' 01:02:03 ', **{'-': '-'}))) assert [x.errors for x in form.fields] == [set() for _ in form.fields] assert form.is_valid() assert form.fields_by_name['party'].parsed_data == 'ABC' assert form.fields_by_name['party'].value == 'ABC' assert form.fields_by_name['username'].parsed_data == 'abc_foo' assert form.fields_by_name['username'].value == 'abc_foo' assert form.fields_by_name['joined'].raw_data == '2014-12-12 01:02:03' assert form.fields_by_name['joined'].parsed_data == datetime( 2014, 12, 12, 1, 2, 3) assert form.fields_by_name['joined'].value == datetime( 2014, 12, 12, 1, 2, 3) assert form.fields_by_name['staff'].raw_data == 'true' assert form.fields_by_name['staff'].parsed_data is True assert form.fields_by_name['staff'].value is True assert form.fields_by_name['admin'].raw_data == 'false' assert form.fields_by_name['admin'].parsed_data is False assert form.fields_by_name['admin'].value is False assert form.fields_by_name['manages'].raw_data_list == ['DEF', 'KTH'] assert form.fields_by_name['manages'].parsed_data_list == ['DEF', 'KTH'] assert form.fields_by_name['manages'].value_list == ['DEF', 'KTH'] assert form.fields_by_name['a_date'].raw_data == '2014-02-12' assert form.fields_by_name['a_date'].parsed_data == date(2014, 2, 12) assert form.fields_by_name['a_date'].value == date(2014, 2, 12) assert form.fields_by_name['a_time'].raw_data == '01:02:03' assert form.fields_by_name['a_time'].parsed_data == time(1, 2, 3) assert form.fields_by_name['a_time'].value == time(1, 2, 3) instance = Struct(contact=Struct()) form.apply(instance) assert instance == Struct( contact=Struct(joined=datetime(2014, 12, 12, 1, 2, 3)), party='ABC', staff=True, admin=False, username='******', manages=['DEF', 'KTH'], a_date=date(2014, 2, 12), a_time=time(1, 2, 3), not_editable='Some non-editable text')
def test_bound_field_render_css_classes(): assert BoundField( field=Struct( container_css_classes={'a', 'b'}, required=True, ), form=Struct(style='compact')).render_container_css_classes( ) == ' class="a b key-value required"'
def test_choice_not_required(): class MyForm(Form): foo = Field.choice(required=False, choices=['bar']) assert MyForm( request=Struct(method='POST', POST=Data( foo='bar', **{'-': '-'}))).fields[0].value == 'bar' assert MyForm( request=Struct(method='POST', POST=Data( foo='', **{'-': '-'}))).fields[0].value is None
def test_sort_after_points_to_nothing_plural(): with pytest.raises(KeyError) as e: sort_after([ Struct(name='quux'), Struct(name='foo', after='does-not-exist2'), Struct(name='quux6', after='does-not-exist'), ]) assert "'Tried to order after does-not-exist, does-not-exist2 but those keys do not exist'" == str( e.value).replace("u'", "'")
class ColumnBase(NamedStruct): """ Class that describes a column, i.e. the text of the header, how to get and display the data in the cell, etc. """ name = NamedStructField() """ :type: unicode """ after = NamedStructField() attrs = NamedStructField() attr = NamedStructField(default=lambda table, column: column.name) css_class = NamedStructField(default=set()) url = NamedStructField() title = NamedStructField() show = NamedStructField(default=True) sort_key = NamedStructField(lambda column: column.attr) sort_default_desc = NamedStructField(default=False) display_name = NamedStructField(default=lambda table, column: force_text( column.name).rsplit('__', 1)[-1].replace("_", " ").capitalize()) sortable = NamedStructField(default=True) group = NamedStructField() auto_rowspan = NamedStructField(default=False) cell = NamedStructField() model = NamedStructField() choices = NamedStructField() bulk = NamedStructField() query = NamedStructField() extra = NamedStructField(default=Struct())
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)
def choice_queryset(**kwargs): def choice_queryset_is_valid(form, field, parsed_data): del form return field.choices.filter(pk=parsed_data.pk).exists(), '%s not in available choices' % (field.raw_data or ', '.join(field.raw_data_list)) def choice_queryset_endpoint_dispatch(field, value, **_): limit = 10 result = field.choices.filter(**{field.extra.endpoint_attr + '__icontains': value}).values_list(*['pk', field.extra.endpoint_attr]) return [ dict( id=row[0], text=row[1], ) for row in result[:limit] ] kwargs = setdefaults_path( Struct(), kwargs, parse=lambda form, field, string_value: field.model.objects.get(pk=string_value) if string_value else None, choice_to_option=lambda form, field, choice: (choice, choice.pk, "%s" % choice, choice == field.value), endpoint_path=lambda form, field: '__' + form.endpoint_dispatch_prefix + '__field__' + field.name, endpoint_dispatch=choice_queryset_endpoint_dispatch, extra__endpoint_attr='name', is_valid=choice_queryset_is_valid, ) return Field.choice(**kwargs)
def __init__(self, **kwargs): new_kwargs = setdefaults_path( Struct(), kwargs, bulk__attr=kwargs.get('attr'), query__attr=kwargs.get('attr'), ) super(BoundColumn, self).__init__(**new_kwargs)
class Meta: bulk_filter = {} bulk_exclude = {} sortable = True attrs = Struct() attrs__class__listview = True row__attrs = Struct() row__template = None filter__template = 'tri_query/form.html' header__template = 'tri_table/table_header_rows.html' links__template = 'tri_table/links.html' endpoint__query__ = lambda table, key, value: table.query.endpoint_dispatch( key=key, value=value) if table.query is not None else None endpoint__bulk__ = lambda table, key, value: table.bulk.endpoint_dispatch( key=key, value=value) if table.bulk is not None else None model = None
def test_mode_initials_from_get(): class FooForm(Form): foo = Field(required=True) bar = Field(required=True) baz = Field.boolean(initial=True) # empty GET form = FooForm(request=Struct(method='GET', GET={})) assert form.is_valid() # initials from GET form = FooForm(request=Struct(method='GET', GET={'foo': 'foo_initial'})) assert form.is_valid() assert form.fields_by_name['foo'].value == 'foo_initial' assert form.fields_by_name['foo'].errors == set() assert form.fields_by_name['bar'].errors == set() assert form.fields_by_name['baz'].errors == set()
def test_mode_full_form_from_request(): class FooForm(Form): foo = Field(required=True) bar = Field(required=True) baz = Field.boolean(initial=True) # empty POST form = FooForm(request=Struct(method='POST', POST={'-': '-'})) assert not form.is_valid() assert form.errors == set() assert form.fields_by_name['foo'].errors == {'This field is required'} assert form.fields_by_name['bar'].errors == {'This field is required'} assert form.fields_by_name['baz'].errors == set( ) # not present in POST request means false form = FooForm(request=Struct(method='POST', POST={ '-': '-', 'foo': 'x', 'bar': 'y', 'baz': 'false' })) assert form.is_valid() assert form.fields_by_name['baz'].value is False # all params in GET form = FooForm(request=Struct(method='GET', GET={'-': '-'})) assert not form.is_valid() assert form.fields_by_name['foo'].errors == {'This field is required'} assert form.fields_by_name['bar'].errors == {'This field is required'} assert form.fields_by_name['baz'].errors == set( ) # not present in POST request means false form = FooForm(request=Struct(method='GET', GET={ '-': '-', 'foo': 'x', 'bar': 'y', 'baz': 'on' })) assert not form.errors assert not form.fields[0].errors assert form.is_valid()
def test_setdefaults_path_ordering(): expected = Struct(x=Struct(y=17, z=42)) actual_foo = setdefaults_path( Struct(), OrderedDict([ ('x', { 'z': 42 }), ('x__y', 17), ])) assert actual_foo == expected actual_bar = setdefaults_path( Struct(), OrderedDict([ ('x__y', 17), ('x', { 'z': 42 }), ])) assert actual_bar == expected
def _prepare_headers(self): headers = prepare_headers(self.request, self.shown_bound_columns) # The id(header) and the type(x.display_name) stuff is to make None not be equal to None in the grouping header_groups = [] class HeaderGroup(Struct): def render_css_class(self): return render_class(self.attrs['class']) for group_name, group_iterator in groupby( headers, key=lambda header: header.group or id(header)): header_group = list(group_iterator) header_groups.append( HeaderGroup(display_name=group_name, sortable=False, colspan=len(header_group), attrs=Struct({'class': Struct(superheader=True)}))) for x in header_group: x.attrs['class']['subheader'] = True if x.is_sorting: x.attrs['class']['sorted_column'] = True header_group[0].attrs['class']['first_column'] = True if header_groups: header_groups[0].attrs['class']['first_column'] = True for x in header_groups: if not isinstance(x.display_name, string_types): x.display_name = '' if all([x.display_name == '' for x in header_groups]): header_groups = [] self.header_levels = [header_groups, headers ] if len(header_groups) > 1 else [headers] return headers
def __init__(self, table, row, row_index): self.table = table """ :type : Table """ self.row = row """ :type : object """ self.row_index = row_index args = Struct( evaluate_recursive(extract_subkeys(table.Meta, 'row'), table=table, row=row)) self.template = args.template self.attrs = args.attrs
def get_meta(cls): """ Collect all members of any contained :code:`Meta` class declarations from the given class or any of its base classes. (Sub class values take precedence.) :type cls: class :rtype: Struct """ merged_attributes = Struct() for class_ in reversed(cls.mro()): if hasattr(class_, 'Meta'): for key, value in class_.Meta.__dict__.items(): merged_attributes[key] = value return merged_attributes
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)
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)
def test_file(): class FooForm(Form): foo = Field.file(required=False) form = FooForm(data=Data(foo='1')) instance = Struct(foo=None) assert form.is_valid() form.apply(instance) assert instance.foo == '1' # Non-existent form entry should not overwrite data form = FooForm(data=Data(foo='')) assert form.is_valid(), {x.name: x.errors for x in form.fields} form.apply(instance) assert instance.foo == '1' form = FooForm(data=Data()) assert form.is_valid(), {x.name: x.errors for x in form.fields} form.apply(instance) assert instance.foo == '1'
def test_create_or_edit_object(): # 1. View create form request = Struct(method='GET', META={}, GET={}, user=Struct(is_authenticated=lambda: True)) response = create_object( request=request, model=CreateOrEditObjectTest, form__field__f_int__initial=1, form__field__f_float__initial=lambda form, field: 2, render__context={'foo': 'FOO'}, render=lambda **kwargs: kwargs) assert response['context_instance'][ 'object_name'] == 'create or edit object test' assert response['context_instance']['is_create'] is True form = response['context_instance']['form'] assert response['context_instance']['foo'] == 'FOO' assert form.mode is INITIALS_FROM_GET assert form.fields_by_name['f_int'].initial == 1 assert form.fields_by_name['f_int'].errors == set() assert form.fields_by_name['f_int'].value == 1 assert form.fields_by_name['f_float'].value == 2 assert form.fields_by_name['f_bool'].value is None assert set(form.fields_by_name.keys()) == {'f_int', 'f_float', 'f_bool'} # 2. Create request.method = 'POST' request.POST = { 'f_int': '3', 'f_float': '5.1', 'f_bool': 'True', '-': '-', } create_object(request=request, model=CreateOrEditObjectTest, render=lambda **kwargs: kwargs) assert get_saved_something() is not None assert get_saved_something().f_int == 3 assert get_saved_something().f_float == 5.1 assert get_saved_something().f_bool is True # 3. View edit form request.method = 'GET' del request.POST response = edit_object(request=request, instance=get_saved_something(), render=lambda **kwargs: kwargs) form = response['context_instance']['form'] assert form.get_errors() == {} assert form.fields_by_name['f_int'].value == 3 assert form.fields_by_name['f_float'].value == 5.1 assert form.fields_by_name['f_bool'].value is True # 4. Edit request.method = 'POST' request.POST = { 'f_int': '7', 'f_float': '11.2', '-': '-', # Not sending a parameter in a POST is the same thing as false } response = edit_object( request=request, instance=get_saved_something(), redirect=lambda form, **_: {'context_instance': { 'form': form }}, render=lambda **kwargs: kwargs) form = response['context_instance']['form'] assert form.get_errors() == {} assert form.is_valid() assert get_saved_something() is not None assert get_saved_something().f_int == 7 assert get_saved_something().f_float == 11.2 assert not get_saved_something().f_bool
def evaluate(self): for field in self.fields: field.evaluate() self.fields = [field for field in self.fields if should_show(field)] self.fields_by_name = Struct({field.name: field for field in self.fields})
def test_sort_after_indexes(): sorts_right([ Struct(name='baz', after=1, expected_position=2), Struct(name='foo', after=0, expected_position=1), Struct(name='bar', after=-1, expected_position=0), ])
def data(): for app_name, models in apps.all_models.items(): for name, cls in models.items(): if app.get(app_name, {}).get(name, {}).get('show', True): yield Struct(app_name=app_name, model_name=name, model=cls)
def test_parse_errors(): def post_validation(form): form.add_error('General snafu') form = MyTestForm(data=Data(party='foo', username='******', joined='foo', staff='foo', admin='foo', a_date='fooasd', a_time='asdasd', **{'-': ''}), post_validation=post_validation) assert not form.is_valid() assert form.errors == {'General snafu'} assert form.fields_by_name['party'].parsed_data == 'foo' assert form.fields_by_name['party'].errors == { 'foo not in available choices' } assert form.fields_by_name['party'].value is None assert form.fields_by_name['username'].parsed_data == 'bar_foo' assert form.fields_by_name['username'].errors == { 'Username must begin with "foo_"' } assert form.fields_by_name['username'].value is None assert form.fields_by_name['joined'].raw_data == 'foo' assert_one_error_and_matches_reg_exp( form.fields_by_name['joined'].errors, "time data u?'foo' does not match format u?'%Y-%m-%d %H:%M:%S'") assert form.fields_by_name['joined'].parsed_data is None assert form.fields_by_name['joined'].value is None assert form.fields_by_name['staff'].raw_data == 'foo' assert form.fields_by_name['staff'].parsed_data is None assert form.fields_by_name['staff'].value is None assert form.fields_by_name['admin'].raw_data == 'foo' assert form.fields_by_name['admin'].parsed_data is None assert form.fields_by_name['admin'].value is None assert form.fields_by_name['a_date'].raw_data == 'fooasd' assert_one_error_and_matches_reg_exp( form.fields_by_name['a_date'].errors, "time data u?'fooasd' does not match format u?'%Y-%m-%d'") assert form.fields_by_name['a_date'].parsed_data is None assert form.fields_by_name['a_date'].value is None assert form.fields_by_name['a_time'].raw_data == 'asdasd' assert_one_error_and_matches_reg_exp( form.fields_by_name['a_time'].errors, "time data u?'asdasd' does not match format u?'%H:%M:%S'") assert form.fields_by_name['a_time'].parsed_data is None assert form.fields_by_name['a_time'].value is None with pytest.raises(AssertionError): form.apply(Struct())
def test_initial_from_instance(): assert Form(instance=Struct(a=Struct(b=7)), fields=[Field(name='a__b')]).fields[0].initial == 7
def test_initial_list_from_instance(): assert Form(instance=Struct(a=Struct(b=[7])), fields=[Field(name='a__b', is_list=True)]).fields[0].initial_list == [7]
def test_required(): form = MyTestForm(request=Struct(method='POST', POST=Data({'-': '-'}))) assert form.fields_by_name['a_date'].value is None assert form.fields_by_name['a_date'].errors == {'This field is required'}