Repository: carltongibson/django-filter

Issue:
test doesn't fail for python3
Python3.4 and Python3.5

```
python3.4 ./runtests.py -v2                     
Creating test database for alias 'default' (':memory:')...
Operations to perform:
  Synchronize unmigrated apps: django_filters, tests
  Apply all migrations: auth, contenttypes
Synchronizing apps without migrations:
  Creating tables...
    Creating table tests_user_favorite_books
    Creating table tests_user
    Creating table tests_comment
    Creating table tests_article
    Creating table tests_book
    Creating table tests_restaurant
    Creating table tests_networksetting
    Creating table tests_company
    Creating table tests_location
    Creating table tests_account
    Creating table tests_profile
    Creating table tests_bankaccount
    Creating table tests_node_adjacents
    Creating table tests_node
    Creating table tests_directednode_outbound_nodes
    Creating table tests_directednode
    Creating table tests_worker
    Creating table tests_hiredworker
    Creating table tests_business
  Installing custom SQL...
  Installing indexes...
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
...
test_filtering_skipped_with_empty_list_value_and_some_choices (tests.test_filters.MultipleChoiceFilterTests) ... unexpected success
...
----------------------------------------------------------------------
Ran 245 tests in 0.463s

FAILED (skipped=13, expected failures=8, unexpected successes=1)
Destroying test database for alias 'default' (':memory:')...
```

Also disturbing is that it exits with a 0 status, indicating success, for this case.



Discussion:
Just noticed it also reports successes=1 under Python 2.7. Curiously Python2.7 reports OK, not FAILED.

Looking at the test seems to suggest that the test is suppose to pass, however it is decorated with @unittest.expectedFailure - which doesn't make a lot of sense to me.

Yep, so #79 was a huge overhaul of the tests and introduced quite a few new ones, including several expected failures. Since then, the [original](https://github.com/carltongibson/django-filter/blob/a152e2ed2ce4129c9d8dcdbb7c880773f25879c7/django_filters/filters.py#L96-L109) implementation has been [updated](https://github.com/carltongibson/django-filter/blob/v0.13/django_filters/filters.py#L208-L210) and passes, but the test was never updated.


Resolving patch:
diff --git a/django_filters/filters.py b/django_filters/filters.py
--- a/django_filters/filters.py
+++ b/django_filters/filters.py
@@ -297,12 +297,12 @@ def filter(self, qs, value):
 
 
 def _truncate(dt):
-    return dt.replace(hour=0, minute=0, second=0)
+    return dt.date()
 
 
 class DateRangeFilter(ChoiceFilter):
     options = {
-        '': (_('Any date'), lambda qs, name: qs.all()),
+        '': (_('Any date'), lambda qs, name: qs),
         1: (_('Today'), lambda qs, name: qs.filter(**{
             '%s__year' % name: now().year,
             '%s__month' % name: now().month,
@@ -336,6 +336,8 @@ def filter(self, qs, value):
             value = int(value)
         except (ValueError, TypeError):
             value = ''
+
+        assert value in self.options
         qs = self.options[value][1](qs, self.name)
         if self.distinct:
             qs = qs.distinct()
diff --git a/django_filters/filterset.py b/django_filters/filterset.py
--- a/django_filters/filterset.py
+++ b/django_filters/filterset.py
@@ -63,8 +63,11 @@ def filters_for_model(model, fields=None, exclude=None, filter_for_field=None,
     field_dict = OrderedDict()
     opts = model._meta
     if fields is None:
-        fields = [f.name for f in sorted(opts.fields + opts.many_to_many)
-                  if not isinstance(f, models.AutoField)]
+        fields = [
+            f.name for f in sorted(opts.fields + opts.many_to_many)
+            if not isinstance(f, models.AutoField) and
+            not (getattr(remote_field(f), 'parent_link', False))
+        ]
     # Loop through the list of fields.
     for f in fields:
         # Skip the field if excluded.


Test patch:
diff --git a/tests/test_filtering.py b/tests/test_filtering.py
--- a/tests/test_filtering.py
+++ b/tests/test_filtering.py
@@ -653,8 +653,6 @@ class Meta:
                                  lambda o: o.title)
 
 
-
-@unittest.skip('date-range is funky')
 class DateRangeFilterTests(TestCase):
 
     def setUp(self):
@@ -693,7 +691,6 @@ class Meta:
         f = F({'date': '3'})  # this month
         self.assertQuerysetEqual(f.qs, [1, 3, 4], lambda o: o.pk, False)
 
-    @unittest.expectedFailure
     def test_filtering_for_week(self):
         class F(FilterSet):
             date = DateRangeFilter()
diff --git a/tests/test_filters.py b/tests/test_filters.py
--- a/tests/test_filters.py
+++ b/tests/test_filters.py
@@ -283,7 +283,6 @@ def test_filtering_exclude(self):
         qs.exclude.assert_called_once_with(somefield__exact=True)
         self.assertNotEqual(qs, result)
 
-    @unittest.expectedFailure
     def test_filtering_skipped_with_blank_value(self):
         qs = mock.Mock()
         f = BooleanFilter(name='somefield')
@@ -380,7 +379,6 @@ def test_filtering_on_required_skipped_when_len_of_value_is_len_of_field_choices
         result = f.filter(qs, ['other', 'values', 'there'])
         self.assertEqual(qs, result)
 
-    @unittest.expectedFailure
     def test_filtering_skipped_with_empty_list_value_and_some_choices(self):
         qs = mock.Mock(spec=[])
         f = MultipleChoiceFilter(name='somefield')
@@ -576,14 +574,6 @@ def test_field_with_lookup_expr(self):
         f.filter(qs, value)
         qs.filter.assert_called_once_with(None__overlap=(20, 30))
 
-    @unittest.expectedFailure
-    def test_filtering_lower_field_higher_than_upper_field(self):
-        qs = mock.Mock(spec=['filter'])
-        value = mock.Mock(start=35, stop=30)
-        f = NumericRangeFilter()
-        result = f.filter(qs, value)
-        self.assertEqual(qs, result)
-
     def test_zero_to_zero(self):
         qs = mock.Mock(spec=['filter'])
         value = mock.Mock(start=0, stop=0)
@@ -654,25 +644,18 @@ def test_default_field(self):
         self.assertIsInstance(field, forms.ChoiceField)
 
     def test_filtering(self):
-        qs = mock.Mock(spec=['all'])
-        f = DateRangeFilter()
-        f.filter(qs, '')
-        qs.all.assert_called_once_with()
-
-    # the correct behavior fails right now
-    @unittest.expectedFailure
-    def test_filtering_skipped_with_blank_value(self):
+        # skip filtering, as it's an empty value
         qs = mock.Mock(spec=[])
         f = DateRangeFilter()
         result = f.filter(qs, '')
         self.assertEqual(qs, result)
 
-    @unittest.expectedFailure
     def test_filtering_skipped_with_out_of_range_value(self):
+        # Field validation should prevent this from occuring
         qs = mock.Mock(spec=[])
         f = DateRangeFilter()
-        result = f.filter(qs, 999)
-        self.assertEqual(qs, result)
+        with self.assertRaises(AssertionError):
+            f.filter(qs, 999)
 
     def test_filtering_for_this_year(self):
         qs = mock.Mock(spec=['filter'])
@@ -694,18 +677,18 @@ def test_filtering_for_this_month(self):
 
     def test_filtering_for_7_days(self):
         qs = mock.Mock(spec=['filter'])
-        with mock.patch('django_filters.filters.now'):
-            with mock.patch('django_filters.filters.timedelta') as mock_td:
-                with mock.patch(
-                        'django_filters.filters._truncate') as mock_truncate:
-                    mock_dt1, mock_dt2 = mock.MagicMock(), mock.MagicMock()
-                    mock_truncate.side_effect = [mock_dt1, mock_dt2]
-                    f = DateRangeFilter()
-                    f.filter(qs, '2')
-                    self.assertEqual(mock_td.call_args_list,
-                        [mock.call(days=7), mock.call(days=1)])
-                    qs.filter.assert_called_once_with(
-                        None__lt=mock_dt2, None__gte=mock_dt1)
+        with mock.patch('django_filters.filters.now'), \
+                mock.patch('django_filters.filters.timedelta') as mock_td, \
+                mock.patch('django_filters.filters._truncate') as mock_truncate:
+            mock_d1, mock_d2 = mock.MagicMock(), mock.MagicMock()
+            mock_truncate.side_effect = [mock_d1, mock_d2]
+            f = DateRangeFilter()
+            f.filter(qs, '2')
+            self.assertEqual(
+                mock_td.call_args_list,
+                [mock.call(days=7), mock.call(days=1)]
+            )
+            qs.filter.assert_called_once_with(None__lt=mock_d2, None__gte=mock_d1)
 
     def test_filtering_for_today(self):
         qs = mock.Mock(spec=['filter'])
@@ -811,11 +794,11 @@ def test_filtering_skipped_with_none_value(self):
         result = f.filter(qs, None)
         self.assertEqual(qs, result)
 
-    def test_filtering_ignores_lookup_type(self):
+    def test_filtering_ignores_lookup_expr(self):
         qs = mock.Mock()
         value = mock.Mock(
             start=datetime(2015, 4, 7, 8, 30), stop=datetime(2015, 9, 6, 11, 45))
-        f = DateTimeFromToRangeFilter(lookup_type='gte')
+        f = DateTimeFromToRangeFilter(lookup_expr='gte')
         f.filter(qs, value)
         qs.filter.assert_called_once_with(
             None__range=(datetime(2015, 4, 7, 8, 30), datetime(2015, 9, 6, 11, 45)))
diff --git a/tests/test_filterset.py b/tests/test_filterset.py
--- a/tests/test_filterset.py
+++ b/tests/test_filterset.py
@@ -482,7 +482,6 @@ class Meta:
 
         self.assertEqual(list(F.base_filters), list(ProxyF.base_filters))
 
-    @unittest.expectedFailure
     def test_filterset_for_mti_model(self):
         class F(FilterSet):
             class Meta: