Skip to content

Commit

Permalink
Merge 96dc1a9 into bef134b
Browse files Browse the repository at this point in the history
  • Loading branch information
julianandrews committed Oct 2, 2015
2 parents bef134b + 96dc1a9 commit 80a3365
Show file tree
Hide file tree
Showing 22 changed files with 157 additions and 349 deletions.
2 changes: 2 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[run]
omit = *tests*
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ tests/.coverage
tests/htmlcov/
dist/
.tox/
.cache/
.coverage
31 changes: 16 additions & 15 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
language: python
python:
- "2.7"
- "3.3"
- "3.4"
cache: pip
sudo: false
env:
- DJANGO_PACKAGE=https://github.com/django/django/archive/stable/1.5.x.zip
- DJANGO_PACKAGE=https://github.com/django/django/archive/stable/1.6.x.zip
- DJANGO_PACKAGE=https://github.com/django/django/archive/stable/1.7.x.zip
matrix:
include:
- python: "2.6"
env: DJANGO_PACKAGE=https://github.com/django/django/archive/stable/1.4.x.zip
- python: "2.7"
env: DJANGO_PACKAGE=https://github.com/django/django/archive/stable/1.4.x.zip
matrix:
- TOX_ENV=py27-dj17
- TOX_ENV=py27-dj18
- TOX_ENV=py34-dj17
- TOX_ENV=py34-dj18
install:
- pip install -q $DJANGO_PACKAGE --use-mirrors
- python setup.py install
- pip install mock
- pip install --upgrade pip
- pip install tox
- pip install coveralls
script: make coverage
after_success: cd tests && coveralls
script:
- tox -e $TOX_ENV coverage
after_success:
- coveralls
after_script:
- cat .tox/$TOX_ENV/log/*.log
8 changes: 3 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
TESTS=tests betterforms
SETTINGS=tests.sqlite_test_settings
COVERAGE_COMMAND=
COVERAGE_ARGS=


test: test-builtin

test-builtin:
cd tests && DJANGO_SETTINGS_MODULE=$(SETTINGS) $(COVERAGE_COMMAND) ./manage.py test --traceback $(TESTS) --verbosity=2
DJANGO_SETTINGS_MODULE=$(SETTINGS) py.test $(COVERAGE_ARGS)

coverage:
+make test COVERAGE_COMMAND='coverage run --source=betterforms --omit="*tests*" --branch --parallel-mode'
cd tests && coverage combine && coverage html
+make test COVERAGE_ARGS='--cov-config .coveragerc --cov-report html --cov-report= --cov=betterforms'

docs:
cd docs && $(MAKE) html
Expand Down
6 changes: 1 addition & 5 deletions betterforms/changelist.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@
from django.forms.forms import pretty_name
from django.core.exceptions import ValidationError, ImproperlyConfigured
from django.db.models import Q
try:
from collections import OrderedDict
except ImportError:
# Support for Python < 2.6
from django.utils.datastructures import SortedDict as OrderedDict
from collections import OrderedDict
from django.utils import six
from django.utils.six.moves import reduce
from django.utils.http import urlencode
Expand Down
193 changes: 0 additions & 193 deletions betterforms/collections_compat.py

This file was deleted.

21 changes: 4 additions & 17 deletions betterforms/forms.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,10 @@
import collections
try:
from collections import Counter
except ImportError:
from collections_compat import Counter # NOQA

from django import forms
try:
from django.forms.utils import ErrorDict
except ImportError:
# Support Django < 1.7
from django.forms.util import ErrorDict
from django.forms.utils import ErrorDict
from django.core.exceptions import NON_FIELD_ERRORS
from django.template.loader import render_to_string
try:
from collections import OrderedDict
except ImportError:
# Support for Python < 2.6
from django.utils.datastructures import SortedDict as OrderedDict
import six # Django six is buggy with Django < 1.5
from django.utils import six
from django.utils.encoding import python_2_unicode_compatible


Expand Down Expand Up @@ -98,7 +85,7 @@ def __init__(self, name, fields=[], **kwargs):
self.legend = kwargs.pop("legend", None)
# Check for duplicate names.
names = [str(thing) for thing in self.base_fields]
duplicates = [x for x, y in Counter(names).items() if y > 1]
duplicates = [x for x, y in collections.Counter(names).items() if y > 1]
if duplicates:
raise AttributeError('Name Conflict in fieldset `{0}`. The name(s) `{1}` appear multiple times.'.format(self.name, duplicates))
for key, value in six.iteritems(kwargs):
Expand Down Expand Up @@ -128,7 +115,7 @@ def __init__(self, form, fieldset, name):
self.form = form
self.name = name
self.fieldset = fieldset
self.rows = OrderedDict()
self.rows = collections.OrderedDict()
for row in fieldset:
self.rows[six.text_type(row)] = row

Expand Down
31 changes: 26 additions & 5 deletions betterforms/multiform.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
except ImportError: # Django < 1.7
from django.forms.util import ErrorDict, ErrorList # NOQA

from django.core.exceptions import ValidationError
from django.utils.encoding import python_2_unicode_compatible
from django.utils.safestring import mark_safe
from django.utils.six.moves import reduce
Expand Down Expand Up @@ -38,6 +39,7 @@ def __init__(self, data=None, files=None, *args, **kwargs):
if self.initials is None:
self.initials = {}
self.forms = OrderedDict()
self.crossform_errors = []

for key, form_class in self.form_classes.items():
fargs, fkwargs = self.get_form_args_kwargs(key, args, kwargs)
Expand Down Expand Up @@ -73,13 +75,32 @@ def __iter__(self):
def is_bound(self):
return any(form.is_bound for form in self.forms.values())

def clean(self):
"""
Raises any ValidationErrors required for cross form validation. Should
return a dict of cleaned_data objects for any forms whose data should
be overridden.
"""
return self.cleaned_data

def add_crossform_error(self, e):
self.crossform_errors.append(e)

def is_valid(self):
return all(form.is_valid() for form in self.forms.values())
forms_valid = all(form.is_valid() for form in self.forms.values())
try:
cleaned_data = self.clean()
except ValidationError as e:
self.add_crossform_error(e)
else:
if cleaned_data is not None:
for key, data in cleaned_data.items():
self.forms[key].cleaned_data = data
return forms_valid and not self.crossform_errors

def non_field_errors(self):
return ErrorList(chain.from_iterable(
form.non_field_errors() for form in self.forms.values()
))
form_errors = (form.non_field_errors() for form in self.forms.values())
return ErrorList(chain(self.crossform_errors, *form_errors))

def as_table(self):
return mark_safe(''.join(form.as_table() for form in self.forms.values()))
Expand Down Expand Up @@ -109,7 +130,7 @@ def visible_fields(self):
def cleaned_data(self):
return OrderedDict(
(key, form.cleaned_data)
for key, form in self.forms.items()
for key, form in self.forms.items() if form.is_valid()
)


Expand Down

0 comments on commit 80a3365

Please sign in to comment.