Skip to content

Commit

Permalink
Drop python 2, Django<1.11 support (carltongibson#797)
Browse files Browse the repository at this point in the history
* Remove old compat code

* Move remote_queryset fn out of compat

* Drop Django<1.11 support

* Drop Django<1.11 checks in tests

* Remove python 2 compat imports

* Drop python 2 support

* Remove 'six' compat code
  • Loading branch information
Ryan P Kilby authored and carltongibson committed Oct 24, 2017
1 parent 46e0ddc commit ace6df2
Show file tree
Hide file tree
Showing 29 changed files with 43 additions and 199 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ sudo: false

language: python
python:
- "2.7"
- "3.4"
- "3.5"
- "3.6"
Expand Down
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ Full documentation on `read the docs`_.
Requirements
------------

* **Python**: 2.7, 3.4, 3.5, 3.6
* **Django**: 1.8, 1.10, 1.11
* **Python**: 3.4, 3.5, 3.6
* **Django**: 1.11, 2.0b
* **DRF**: 3.7

Installation
Expand Down
2 changes: 0 additions & 2 deletions django_filters/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# flake8: noqa
from __future__ import absolute_import

import pkgutil

from .constants import STRICTNESS
Expand Down
46 changes: 0 additions & 46 deletions django_filters/compat.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,4 @@

from __future__ import absolute_import

import django
from django.conf import settings
from django.utils.timezone import make_aware as make_aware_orig

try:
from django.forms.utils import pretty_name
except ImportError: # Django 1.8
from django.forms.forms import pretty_name

# django-crispy-forms is optional
try:
Expand All @@ -33,39 +23,3 @@ def is_crispy():
import coreschema
except ImportError:
coreschema = None

def remote_field(field):
"""
https://docs.djangoproject.com/en/1.9/releases/1.9/#field-rel-changes
"""
if django.VERSION >= (1, 9):
return field.remote_field
return field.rel


def remote_model(field):
if django.VERSION >= (1, 9):
return remote_field(field).model
return remote_field(field).to


def remote_queryset(field):
model = remote_model(field)
limit_choices_to = field.get_limit_choices_to()

return model._default_manager.complex_filter(limit_choices_to)


def format_value(widget, value):
if django.VERSION >= (1, 10):
return widget.format_value(value)
return widget._format_value(value)



def make_aware(value, timezone, is_dst):
"""is_dst was added for 1.9"""
if django.VERSION >= (1, 9):
return make_aware_orig(value, timezone, is_dst)
else:
return make_aware_orig(value, timezone)
3 changes: 0 additions & 3 deletions django_filters/conf.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@

from __future__ import absolute_import

from django.conf import settings as dj_settings
from django.core.signals import setting_changed
from django.utils.translation import ugettext_lazy as _
Expand Down
12 changes: 1 addition & 11 deletions django_filters/fields.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
from __future__ import absolute_import, unicode_literals

from collections import namedtuple
from datetime import datetime, time

import django
from django import forms
from django.utils.dateparse import parse_datetime
from django.utils.encoding import force_str
Expand Down Expand Up @@ -237,14 +234,7 @@ def __init__(self, *args, **kwargs):
super(ChoiceIteratorMixin, self).__init__(*args, **kwargs)

def _get_choices(self):
if django.VERSION >= (1, 11):
return super(ChoiceIteratorMixin, self)._get_choices()

# HACK: Django < 1.11 does not allow a custom iterator to be provided.
# This code only executes for Model*ChoiceFields.
if hasattr(self, '_choices'):
return self._choices
return self.iterator(self)
return super(ChoiceIteratorMixin, self)._get_choices()

def _set_choices(self, value):
super(ChoiceIteratorMixin, self)._set_choices(value)
Expand Down
13 changes: 5 additions & 8 deletions django_filters/filters.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
from __future__ import absolute_import, unicode_literals

from collections import OrderedDict
from datetime import timedelta

from django import forms
from django.db.models import Q
from django.db.models.constants import LOOKUP_SEP
from django.db.models.sql.constants import QUERY_TERMS
from django.utils import six
from django.forms.utils import pretty_name
from django.utils.itercompat import is_iterable
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _

from .compat import pretty_name
from .conf import settings
from .constants import EMPTY_VALUES
from .fields import (
Expand Down Expand Up @@ -186,7 +183,7 @@ def field(self):

def filter(self, qs, value):
if isinstance(value, Lookup):
lookup = six.text_type(value.lookup_type)
lookup = str(value.lookup_type)
value = value.value
else:
lookup = self.lookup_expr
Expand Down Expand Up @@ -475,7 +472,7 @@ class DateRangeFilter(ChoiceFilter):

def __init__(self, *args, **kwargs):
kwargs['choices'] = [
(key, value[0]) for key, value in six.iteritems(self.options)]
(key, value[0]) for key, value in self.options.items()]

# empty/null choices not relevant
kwargs.setdefault('empty_label', None)
Expand Down Expand Up @@ -660,13 +657,13 @@ def normalize_fields(cls, fields):
"'fields' must be an iterable (e.g., a list, tuple, or mapping)."

# fields is an iterable of field names
assert all(isinstance(field, six.string_types) or
assert all(isinstance(field, str) or
is_iterable(field) and len(field) == 2 # may need to be wrapped in parens
for field in fields), \
"'fields' must contain strings or (field name, param name) pairs."

return OrderedDict([
(f, f) if isinstance(f, six.string_types) else f for f in fields
(f, f) if isinstance(f, str) else f for f in fields
])

def build_choices(self, fields, labels):
Expand Down
23 changes: 13 additions & 10 deletions django_filters/filterset.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
from __future__ import absolute_import, unicode_literals

import copy
from collections import OrderedDict

from django import forms
from django.db import models
from django.db.models.constants import LOOKUP_SEP
from django.db.models.fields.related import ForeignObjectRel
from django.utils import six

from .compat import remote_field, remote_queryset
from .conf import settings
from .constants import ALL_FIELDS, STRICTNESS
from .filters import (
Expand All @@ -36,6 +32,13 @@
)


def remote_queryset(field):
model = field.remote_field.model
limit_choices_to = field.get_limit_choices_to()

return model._default_manager.complex_filter(limit_choices_to)


class FilterSetOptions(object):
def __init__(self, options=None):
self.model = getattr(options, 'model', None)
Expand Down Expand Up @@ -113,15 +116,15 @@ def get_declared_filters(cls, bases, attrs):
'filter_class': ModelChoiceFilter,
'extra': lambda f: {
'queryset': remote_queryset(f),
'to_field_name': remote_field(f).field_name,
'to_field_name': f.remote_field.field_name,
'null_label': settings.NULL_CHOICE_LABEL if f.null else None,
}
},
models.ForeignKey: {
'filter_class': ModelChoiceFilter,
'extra': lambda f: {
'queryset': remote_queryset(f),
'to_field_name': remote_field(f).field_name,
'to_field_name': f.remote_field.field_name,
'null_label': settings.NULL_CHOICE_LABEL if f.null else None,
}
},
Expand Down Expand Up @@ -181,7 +184,7 @@ def qs(self):

# start with all the results and filter from there
qs = self.queryset.all()
for name, filter_ in six.iteritems(self.filters):
for name, filter_ in self.filters.items():
value = self.form.cleaned_data.get(name)

if value is not None: # valid & clean data
Expand All @@ -196,7 +199,7 @@ def form(self):
if not hasattr(self, '_form'):
fields = OrderedDict([
(name, filter_.field)
for name, filter_ in six.iteritems(self.filters)])
for name, filter_ in self.filters.items()])

Form = type(str('%sForm' % self.__class__.__name__),
(self._meta.form,), fields)
Expand Down Expand Up @@ -328,7 +331,7 @@ def filter_for_field(cls, f, field_name, lookup_expr='exact'):

@classmethod
def filter_for_reverse_field(cls, f, field_name):
rel = remote_field(f.field)
rel = f.field.remote_field
queryset = f.field.model._default_manager.all()
default = {
'field_name': field_name,
Expand Down Expand Up @@ -410,7 +413,7 @@ def _csv_filter_class_name(cls, filter_class, lookup_type):
return str('%s%sFilter' % (type_name, lookup_name))


class FilterSet(six.with_metaclass(FilterSetMetaclass, BaseFilterSet)):
class FilterSet(BaseFilterSet, metaclass=FilterSetMetaclass):
pass


Expand Down
1 change: 0 additions & 1 deletion django_filters/rest_framework/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# flake8: noqa
from __future__ import absolute_import
from .backends import DjangoFilterBackend
from .filterset import FilterSet
from .filters import *
6 changes: 1 addition & 5 deletions django_filters/rest_framework/backends.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@

from __future__ import absolute_import

import warnings

from django.template import loader
from django.utils import six

from . import filters, filterset
from .. import compat
Expand Down Expand Up @@ -74,7 +70,7 @@ def get_coreschema_field(self, field):
else:
field_cls = compat.coreschema.String
return field_cls(
description=six.text_type(field.extra.get('help_text', ''))
description=str(field.extra.get('help_text', ''))
)

def get_schema_fields(self, view):
Expand Down
3 changes: 0 additions & 3 deletions django_filters/rest_framework/filterset.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@

from __future__ import absolute_import

from copy import deepcopy

from django import forms
Expand Down
13 changes: 6 additions & 7 deletions django_filters/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@
from django.db.models.fields import FieldDoesNotExist
from django.db.models.fields.related import ForeignObjectRel, RelatedField
from django.forms import ValidationError
from django.utils import six, timezone
from django.utils import timezone
from django.utils.encoding import force_text
from django.utils.text import capfirst
from django.utils.translation import ugettext as _

from .compat import make_aware, remote_field, remote_model
from .exceptions import FieldLookupError


Expand Down Expand Up @@ -50,7 +49,7 @@ def get_all_model_fields(model):
return [
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))
not (getattr(f.remote_field, 'parent_link', False))
]


Expand Down Expand Up @@ -93,7 +92,7 @@ def get_field_parts(model, field_name):

fields.append(field)
if isinstance(field, RelatedField):
opts = remote_model(field)._meta
opts = field.remote_field.model._meta
elif isinstance(field, ForeignObjectRel):
opts = field.related_model._meta

Expand Down Expand Up @@ -141,12 +140,12 @@ def resolve_field(model_field, lookup_expr):
lhs = query.try_transform(*args)
lookups = lookups[1:]
except FieldError as e:
six.raise_from(FieldLookupError(model_field, lookup_expr), e)
raise FieldLookupError(model_field, lookup_expr) from e


def handle_timezone(value, is_dst=None):
if settings.USE_TZ and timezone.is_naive(value):
return make_aware(value, timezone.get_current_timezone(), is_dst)
return timezone.make_aware(value, timezone.get_current_timezone(), is_dst)
elif not settings.USE_TZ and timezone.is_aware(value):
return timezone.make_naive(value, timezone.utc)
return value
Expand Down Expand Up @@ -225,7 +224,7 @@ def label_for_filter(model, field_name, lookup_expr, exclude=False):
verbose_expression = [_('exclude'), name] if exclude else [name]

# iterable lookups indicate a LookupTypeField, which should not be verbose
if isinstance(lookup_expr, six.string_types):
if isinstance(lookup_expr, str):
verbose_expression += [verbose_lookup_expr(lookup_expr)]

verbose_expression = [force_text(part) for part in verbose_expression if part]
Expand Down
2 changes: 0 additions & 2 deletions django_filters/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from __future__ import absolute_import, unicode_literals

from django.core.exceptions import ImproperlyConfigured
from django.views.generic import View
from django.views.generic.list import (
Expand Down
Loading

0 comments on commit ace6df2

Please sign in to comment.