From 3210fc65d74dfa7788141274cab86b592b71cbac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gregor=20M=C3=BCllegger?= Date: Fri, 26 Jul 2013 16:21:06 +0200 Subject: [PATCH] Adding first sample implementation of fieldsets and fieldset objects. But they aren't integrated yet into the admin. --- djadmin2/fieldsets.py | 150 +++++++++++++++++++++++++++ djadmin2/tests/__init__.py | 1 + djadmin2/tests/test_fieldsets.py | 173 +++++++++++++++++++++++++++++++ 3 files changed, 324 insertions(+) create mode 100644 djadmin2/fieldsets.py create mode 100644 djadmin2/tests/test_fieldsets.py diff --git a/djadmin2/fieldsets.py b/djadmin2/fieldsets.py new file mode 100644 index 00000000..cb039bfc --- /dev/null +++ b/djadmin2/fieldsets.py @@ -0,0 +1,150 @@ +''' +Fieldset shall provide a interface that behaves like:: + +.. code-block:: python + + fieldsets = Fieldsets( + Fieldset( + 'information', + _('Information'), + fields=( + 'title', + 'description', + 'links', + ), + classes=('wide',)), + Fieldset( + 'images', + 'video', + 'attribution', + id='media', + name=_('Media'), + classes=('wide',)), + ) + + fieldsets = fieldsets.move_fieldset('information', after='media') + fieldsets = fieldsets.move_field('images', after='video') + fieldsets = fieldsets.move_field('links', after='attribution') + fieldsets = fieldsets.add_field('a_field_that_was_not_yet_listed_in_the_fieldset', before='attribution') + fieldsets = fieldsets.remove_fieldset('media') +''' + + +class Fieldsets(object): + def __init__(self, *fieldsets): + self._fieldsets = [] + for fieldset in fieldsets: + self.append(fieldset) + + def __eq__(self, other): + return self._fieldsets == other._fieldsets + + def __nonzero__(self): + return bool(self._fieldsets) + + def __contains__(self, field): + ''' + Checks if the given field is contained in one of the fieldsets. + ''' + for fieldset in self._fieldsets: + if field in fieldset: + return True + return False + + def __len__(self): + return len(self._fieldsets) + + def __getitem__(self, key): + return self._fieldsets[key] + + def copy(self): + return Fieldsets(*self._fieldsets) + + @property + def fields(self): + fields = [] + for fieldset in self._fieldsets: + fields.extend(fieldset.fields) + return fields + + def append(self, fieldset): + self._fieldsets.append(fieldset) + + def remove_fieldset(self, id): + if type(id) is int: + new = self.copy() + del new._fieldsets[id] + return new + else: + for i, fieldset in enumerate(self._fieldsets): + if fieldset.id == id: + new = self.copy() + del new._fieldsets[i] + return new + raise ValueError('Fieldset with id "{}" does not exist.'.format(id)) + +class Fieldset(object): + def __init__(self, *fields, **kwargs): + self._fields = list(fields) + self.id = kwargs.pop('id', None) + self.name = kwargs.pop('name', None) + + def __eq__(self, other): + return self._fields == other._fields + + def __nonzero__(self): + return bool(self._fields) + + def __contains__(self, field): + return field in self._fields + + def index(self, field): + return self._fields.index(field) + + def copy(self): + return Fieldset(*self._fields) + + @property + def fields(self): + return self._fields[:] + + def _determine_new_index(self, after=None, before=None): + if before is None and after is None: + raise ValueError( + 'Specify either `before` or `after` as argument.') + if before is not None and after is not None: + raise ValueError( + 'You cannot specify `before` and `after` arguments at the ' + 'same time.') + + # determine new index + if after is not None: + new_index = self._fields.index(after) + 1 + elif before is not None: + new_index = self._fields.index(before) + + return new_index + + def add_field(self, field, after=None, before=None): + new_index = self._determine_new_index(after=after, before=before) + new = self.copy() + new._fields.insert(new_index, field) + return new + + def move_field(self, field, after=None, before=None): + current_index = self._fields.index(field) + new_index = self._determine_new_index(after=after, before=before) + new = self.copy() + # insert into new place + new._fields.insert(new_index, field) + # remove current field + if new_index < current_index: + current_index += 1 + del new._fields[current_index] + return new + + def remove_field(self, field): + current_index = self._fields.index(field) + new = self.copy() + del new._fields[current_index] + return new diff --git a/djadmin2/tests/__init__.py b/djadmin2/tests/__init__.py index f0a84117..2bde6bf0 100644 --- a/djadmin2/tests/__init__.py +++ b/djadmin2/tests/__init__.py @@ -6,3 +6,4 @@ from test_actions import * from test_auth_admin import * from test_renderers import * +from test_fieldsets import * diff --git a/djadmin2/tests/test_fieldsets.py b/djadmin2/tests/test_fieldsets.py new file mode 100644 index 00000000..b497901e --- /dev/null +++ b/djadmin2/tests/test_fieldsets.py @@ -0,0 +1,173 @@ +from django.test import TestCase +from ..fieldsets import Fieldsets, Fieldset + + +class FieldsetsTest(TestCase): + def test_contains(self): + fieldsets = Fieldsets() + self.assertFalse('name' in fieldsets) + + fieldsets = Fieldsets(Fieldset()) + self.assertFalse('name' in fieldsets) + + fieldsets = Fieldsets(Fieldset('not_name')) + self.assertFalse('name' in fieldsets) + + fieldsets = Fieldsets(Fieldset('name')) + self.assertTrue('name' in fieldsets) + + fieldsets = Fieldsets(Fieldset('not_name', 'name')) + self.assertTrue('name' in fieldsets) + + def test_empty(self): + fieldsets = Fieldsets() + self.assertFalse(fieldsets) + + fieldsets = Fieldsets(Fieldset()) + self.assertTrue(fieldsets) + + def test_indexing(self): + fs = Fieldsets() + self.assertEqual(len(fs), 0) + + foo = Fieldset('foo') + bar = Fieldset('bar') + spam = Fieldset('spam') + eggs = Fieldset('eggs') + fs = Fieldsets(foo, bar, spam, eggs) + self.assertEqual(len(fs), 4) + self.assertEqual(fs[0], foo) + self.assertEqual(fs[1], bar) + self.assertEqual(fs[2], spam) + self.assertEqual(fs[3], eggs) + self.assertEqual(fs[-1], eggs) + + def test_slicing(self): + foo = Fieldset('foo') + bar = Fieldset('bar') + spam = Fieldset('spam') + eggs = Fieldset('eggs') + fs = Fieldsets(foo, bar, spam, eggs) + + self.assertEqual(fs[0:2], [foo, bar]) + self.assertEqual(fs[::-2], [eggs, bar]) + + def test_append(self): + fs = Fieldsets() + foo = Fieldset('foo') + bar = Fieldset('bar') + fs.append(foo) + fs.append(bar) + self.assertEqual(fs.fields, ['foo', 'bar']) + + def test_copy(self): + foo = Fieldset('foo') + bar = Fieldset('bar') + f1 = Fieldsets(foo, bar) + f2 = f1.copy() + self.assertEqual(f1, f2) + self.assertFalse(f1 is f2) + + f2 = f2.remove_fieldset(0) + self.assertNotEqual(f1, f2) + self.assertFalse(f1 is f2) + + def test_remove_fieldset(self): + foo = Fieldset('foo', id='foo1') + bar = Fieldset('bar', id='foo2') + fs = Fieldsets(foo, bar) + fs.remove_fieldset('foo1') + self.assertEqual(fs.fields, ['foo', 'bar']) + + fs = fs.remove_fieldset('foo1') + self.assertEqual(fs.fields, ['bar']) + + self.assertRaises(ValueError, fs.remove_fieldset, 'foo1') + + +class FieldsetTest(TestCase): + def test_id(self): + f = Fieldset(id='my_id') + self.assertEqual(f.id, 'my_id') + + def test_name(self): + f = Fieldset(name='A beautiful, descriptive name') + self.assertEqual(f.name, 'A beautiful, descriptive name') + + def test_contains(self): + fieldset = Fieldset() + self.assertFalse('name' in fieldset) + + fieldset = Fieldset('not_name') + self.assertFalse('name' in fieldset) + + fieldset = Fieldset('name') + self.assertTrue('name' in fieldset) + + fieldset = Fieldset('not_name', 'name') + self.assertTrue('name' in fieldset) + + def test_empty(self): + fieldset = Fieldset() + self.assertFalse(fieldset) + + fieldset = Fieldset('field_one') + self.assertTrue(fieldset) + + def test_index(self): + f = Fieldset('foo', 'bar') + self.assertEqual(f.index('foo'), 0) + self.assertEqual(f.index('bar'), 1) + self.assertRaises(ValueError, f.index, None) + self.assertRaises(ValueError, f.index, 'non_existent') + + def test_copy(self): + f1 = Fieldset('foo', 'bar') + f2 = f1.copy() + self.assertEqual(f1, f2) + self.assertFalse(f1 is f2) + + f1.move_field('bar', after='foo') + self.assertNotEqual(f1, f2) + + def test_add_field_before(self): + f1 = Fieldset('foo', 'bar') + f1 = f1.add_field('spam', before='bar') + self.assertEqual(f1.fields, ['foo', 'spam', 'bar']) + f1 = f1.add_field('eggs', before='foo') + self.assertEqual(f1.fields, ['eggs', 'foo', 'spam', 'bar']) + + def test_add_field_after(self): + f1 = Fieldset('foo', 'bar') + f1 = f1.add_field('spam', after='foo') + self.assertEqual(f1.fields, ['foo', 'spam', 'bar']) + f1 = f1.add_field('eggs', after='bar') + self.assertEqual(f1.fields, ['foo', 'spam', 'bar', 'eggs']) + + def test_move_field_errors(self): + f1 = Fieldset('foo', 'bar') + + self.assertRaises(ValueError, f1.move_field, 'foo', after='bar', before='bar') + self.assertRaises(ValueError, f1.move_field, 'foo', 'bar', 'bar') + + def test_move_field_before(self): + f1 = Fieldset('foo', 'bar', 'spam', 'eggs') + f1 = f1.move_field('foo', before='eggs') + self.assertEqual(f1.fields, ['bar', 'spam', 'foo', 'eggs']) + + f1 = f1.move_field('spam', before='bar') + self.assertEqual(f1.fields, ['spam', 'bar', 'foo', 'eggs']) + + def test_move_field_after(self): + f1 = Fieldset('foo', 'bar', 'spam', 'eggs') + f1 = f1.move_field('foo', after='bar') + self.assertEqual(f1.fields, ['bar', 'foo', 'spam', 'eggs']) + + f1 = f1.move_field('foo', after='eggs') + self.assertEqual(f1.fields, ['bar', 'spam', 'eggs', 'foo']) + + def test_remove_field(self): + f1 = Fieldset('foo', 'bar', 'spam', 'eggs') + f1 = f1.remove_field('foo') + self.assertEqual(f1.fields, ['bar', 'spam', 'eggs']) + self.assertRaises(ValueError, f1.remove_field, 'foo')