Skip to content

Commit

Permalink
Merge pull request #151 from hugovk/rm-eol
Browse files Browse the repository at this point in the history
Drop support for EOL Python and Django
  • Loading branch information
asfaltboy committed Jan 23, 2022
2 parents 985450e + a36aa8a commit dfeb005
Show file tree
Hide file tree
Showing 22 changed files with 80 additions and 194 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Expand Up @@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9]
python-version: [3.6, 3.7, 3.8, 3.9]

steps:
- uses: actions/checkout@v1
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Expand Up @@ -26,7 +26,7 @@ For release notes, see `Changelog <https://raw.githubusercontent.com/modlinltd/d
Requirements
============

- Django >= 1.9 (Django 1.9 - 3.1 on Python 2/3/PyPy3)
- Django 2.2, >= 3.1 on Python 3.6+/PyPy3
- simplejson >= 3.6.5, < 4


Expand Down
46 changes: 23 additions & 23 deletions advanced_filters/admin.py
Expand Up @@ -5,17 +5,11 @@
from django.contrib.admin.utils import unquote
from django.http import HttpResponseRedirect
from django.shortcuts import resolve_url
from django.utils.translation import gettext_lazy as _

from .forms import AdvancedFilterForm
from .models import AdvancedFilter

# django < 1.9 support
from django import VERSION
if VERSION >= (2, 0):
from django.utils.translation import gettext_lazy as _
else:
from django.utils.translation import ugettext_lazy as _


logger = logging.getLogger('advanced_filters.admin')

Expand All @@ -28,16 +22,20 @@ class AdvancedListFilters(admin.SimpleListFilter):

def lookups(self, request, model_admin):
if not model_admin:
raise Exception('Cannot use AdvancedListFilters without a '
'model_admin')
model_name = "%s.%s" % (model_admin.model._meta.app_label,
model_admin.model._meta.object_name)
raise Exception(
"Cannot use AdvancedListFilters without a model_admin"
)
model_name = (
f"{model_admin.model._meta.app_label}."
f"{model_admin.model._meta.object_name}"
)
return AdvancedFilter.objects.filter_by_user(request.user).filter(
model=model_name).values_list('id', 'title')

def queryset(self, request, queryset):
if self.value():
filters = AdvancedFilter.objects.filter(id=self.value())
advfilter = None
if hasattr(filters, 'first'):
advfilter = filters.first()
if not advfilter:
Expand All @@ -49,14 +47,17 @@ def queryset(self, request, queryset):
return queryset


class AdminAdvancedFiltersMixin(object):
class AdminAdvancedFiltersMixin:
""" Generic AdvancedFilters mixin """
advanced_change_list_template = "admin/advanced_filters.html"
advanced_filter_form = AdvancedFilterForm

def __init__(self, *args, **kwargs):
super(AdminAdvancedFiltersMixin, self).__init__(*args, **kwargs)
self.original_change_list_template = "admin/change_list.html"
super().__init__(*args, **kwargs)
if self.change_list_template:
self.original_change_list_template = self.change_list_template
else:
self.original_change_list_template = "admin/change_list.html"
self.change_list_template = self.advanced_change_list_template
# add list filters to filters
self.list_filter = (AdvancedListFilters,) + tuple(self.list_filter)
Expand Down Expand Up @@ -103,8 +104,7 @@ def changelist_view(self, request, extra_context=None):
if response:
return response

return super(AdminAdvancedFiltersMixin, self
).changelist_view(request, extra_context=extra_context)
return super().changelist_view(request, extra_context=extra_context)


class AdvancedFilterAdmin(admin.ModelAdmin):
Expand All @@ -123,20 +123,20 @@ def save_model(self, request, new_object, *args, **kwargs):
if new_object and not new_object.pk:
new_object.created_by = request.user

super(AdvancedFilterAdmin, self).save_model(
super().save_model(
request, new_object, *args, **kwargs)

def change_view(self, request, object_id, form_url='', extra_context=None):
orig_response = super(AdvancedFilterAdmin, self).change_view(
orig_response = super().change_view(
request, object_id, form_url, extra_context)
if '_save_goto' in request.POST:
obj = self.get_object(request, unquote(object_id))
if obj:
app, model = obj.model.split('.')
path = resolve_url('admin:%s_%s_changelist' % (
path = resolve_url('admin:{}_{}_changelist'.format(
app, model.lower()))
url = "{path}{qparams}".format(
path=path, qparams="?_afilter={id}".format(id=object_id))
path=path, qparams=f"?_afilter={object_id}")
return HttpResponseRedirect(url)
return orig_response

Expand All @@ -147,18 +147,18 @@ def user_has_permission(user):

def get_queryset(self, request):
if self.user_has_permission(request.user):
return super(AdvancedFilterAdmin, self).get_queryset(request)
return super().get_queryset(request)
else:
return self.model.objects.filter_by_user(request.user)

def has_change_permission(self, request, obj=None):
if obj is None:
return super(AdvancedFilterAdmin, self).has_change_permission(request)
return super().has_change_permission(request)
return self.user_has_permission(request.user) or obj in self.model.objects.filter_by_user(request.user)

def has_delete_permission(self, request, obj=None):
if obj is None:
return super(AdvancedFilterAdmin, self).has_delete_permission(request)
return super().has_delete_permission(request)
return self.user_has_permission(request.user) or obj in self.model.objects.filter_by_user(request.user)


Expand Down
10 changes: 4 additions & 6 deletions advanced_filters/form_helpers.py
Expand Up @@ -3,8 +3,6 @@

from django import forms

import six

logger = logging.getLogger('advanced_filters.form_helpers')

extra_spaces_pattern = re.compile(r'\s+')
Expand All @@ -29,7 +27,7 @@ def to_python(self, value):
>>> assert field.to_python('and,me') == '(and|me)'
>>> assert field.to_python('and,me;too') == '(and|me;too)'
"""
res = super(VaryingTypeCharField, self).to_python(value)
res = super().to_python(value)
split_res = res.split(self._default_separator)
if not res or len(split_res) < 2:
return res.strip()
Expand All @@ -40,7 +38,7 @@ def to_python(self, value):
return res


class CleanWhiteSpacesMixin(object):
class CleanWhiteSpacesMixin:
"""
This mixin, when added to any form subclass, adds a clean method which
strips repeating spaces in and around each string value of "clean_data".
Expand All @@ -55,9 +53,9 @@ def clean(self):
>>> assert form.is_valid()
>>> assert form.cleaned_data == {'some_field': 'a weird value'}
"""
cleaned_data = super(CleanWhiteSpacesMixin, self).clean()
cleaned_data = super().clean()
for k in self.cleaned_data:
if isinstance(self.cleaned_data[k], six.string_types):
if isinstance(self.cleaned_data[k], str):
cleaned_data[k] = re.sub(extra_spaces_pattern, ' ',
self.cleaned_data[k] or '').strip()
return cleaned_data
34 changes: 13 additions & 21 deletions advanced_filters/forms.py
Expand Up @@ -15,22 +15,14 @@
from django.db.models.fields import DateField
from django.forms.formsets import formset_factory, BaseFormSet
from django.utils.functional import cached_property
from six.moves import range, reduce
from functools import reduce
from django.utils.text import capfirst
from django.utils.translation import gettext_lazy as _

from .models import AdvancedFilter
from .form_helpers import CleanWhiteSpacesMixin, VaryingTypeCharField

# django < 1.9 support
from django import VERSION
if VERSION >= (2, 0):
from django.utils.translation import gettext_lazy as _
else:
from django.utils.translation import ugettext_lazy as _


# django < 1.9 support
USE_VENDOR_DIR = VERSION >= (1, 9)
logger = logging.getLogger('advanced_filters.forms')

# select2 location can be modified via settings
Expand Down Expand Up @@ -84,7 +76,7 @@ def _build_field_choices(self, fields):
Iterate over passed model fields tuple and update initial choices.
"""
return tuple(sorted(
[(fquery, capfirst(fname)) for fquery, fname in fields.items()],
((fquery, capfirst(fname)) for fquery, fname in fields.items()),
key=lambda f: f[1].lower())
) + self.FIELD_CHOICES

Expand Down Expand Up @@ -166,7 +158,7 @@ def set_range_value(self, data):
data['value'] = (dtfrom, dtto)

def clean(self):
cleaned_data = super(AdvancedFilterQueryForm, self).clean()
cleaned_data = super().clean()
if cleaned_data.get('operator') == "range":
if ('value_from' in cleaned_data and
'value_to' in cleaned_data):
Expand All @@ -184,7 +176,7 @@ def make_query(self, *args, **kwargs):
return query

def __init__(self, model_fields={}, *args, **kwargs):
super(AdvancedFilterQueryForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.FIELD_CHOICES = self._build_field_choices(model_fields)
self.fields['field'].choices = self.FIELD_CHOICES
if not self.fields['field'].initial:
Expand All @@ -198,13 +190,13 @@ class AdvancedFilterFormSet(BaseFormSet):

def __init__(self, *args, **kwargs):
self.model_fields = kwargs.pop('model_fields', {})
super(AdvancedFilterFormSet, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
if self.forms:
form = self.forms[0]
self.fields = form.visible_fields()

def get_form_kwargs(self, index):
kwargs = super(AdvancedFilterFormSet, self).get_form_kwargs(index)
kwargs = super().get_form_kwargs(index)
kwargs['model_fields'] = self.model_fields
return kwargs

Expand Down Expand Up @@ -234,7 +226,7 @@ class Meta:

class Media:
required_js = [
'admin/js/%sjquery.min.js' % ('vendor/jquery/' if USE_VENDOR_DIR else ''),
'admin/js/vendor/jquery/jquery.min.js',
'advanced-filters/jquery_adder.js',
'orig_inlines%s.js' % ('' if settings.DEBUG else '.min'),
'magnific-popup/jquery.magnific-popup.js',
Expand Down Expand Up @@ -294,7 +286,7 @@ def __init__(self, *args, **kwargs):
self._filter_fields = filter_fields or getattr(
model_admin, 'advanced_filter_fields', ())

super(AdvancedFilterForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)

# populate existing or empty forms formset
data = None
Expand All @@ -305,15 +297,15 @@ def __init__(self, *args, **kwargs):
self.initialize_form(instance, self._model, data, extra_form)

def clean(self):
cleaned_data = super(AdvancedFilterForm, self).clean()
cleaned_data = super().clean()
if not self.fields_formset.is_valid():
logger.debug(
"Errors validating advanced query filters: %s",
pformat([(f.errors, f.non_field_errors())
for f in self.fields_formset.forms]))
raise forms.ValidationError("Error validating filter forms")
cleaned_data['model'] = "%s.%s" % (self._model._meta.app_label,
self._model._meta.object_name)
cleaned_data['model'] = "{}.{}".format(self._model._meta.app_label,
self._model._meta.object_name)
return cleaned_data

@property
Expand Down Expand Up @@ -364,4 +356,4 @@ def initialize_form(self, instance, model, data=None, extra=None):
def save(self, commit=True):
self.instance.query = self.generate_query()
self.instance.model = self.cleaned_data.get('model')
return super(AdvancedFilterForm, self).save(commit)
return super().save(commit)
2 changes: 0 additions & 2 deletions advanced_filters/migrations/0001_initial.py
@@ -1,6 +1,4 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-03-07 23:02
from __future__ import unicode_literals

from django.conf import settings
from django.db import migrations, models
Expand Down
3 changes: 0 additions & 3 deletions advanced_filters/migrations/0002_advancedfilter_created_at.py
@@ -1,6 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


Expand Down
17 changes: 6 additions & 11 deletions advanced_filters/mixins.py
Expand Up @@ -16,13 +16,8 @@
from django.utils.encoding import force_text as force_string
from django.views.decorators.csrf import csrf_exempt

try:
from django.utils import six
except ImportError:
import six


class CsrfExemptMixin(object):
class CsrfExemptMixin:
"""
Exempts the view from CSRF requirements.
NOTE:
Expand All @@ -31,10 +26,10 @@ class CsrfExemptMixin(object):

@method_decorator(csrf_exempt)
def dispatch(self, *args, **kwargs):
return super(CsrfExemptMixin, self).dispatch(*args, **kwargs)
return super().dispatch(*args, **kwargs)


class AccessMixin(object):
class AccessMixin:
"""
'Abstract' mixin that gives access mixins the same customizable
functionality.
Expand Down Expand Up @@ -104,11 +99,11 @@ def dispatch(self, request, *args, **kwargs):
if not request.user.is_staff:
return self.handle_no_permission(request)

return super(StaffuserRequiredMixin, self).dispatch(
return super().dispatch(
request, *args, **kwargs)


class JSONResponseMixin(object):
class JSONResponseMixin:
"""
A mixin that allows you to easily serialize simple data such as a dict or
Django models.
Expand All @@ -120,7 +115,7 @@ class JSONResponseMixin(object):
def get_content_type(self):
if (self.content_type is not None and
not isinstance(self.content_type,
(six.string_types, six.text_type))):
((str,), str))):
raise ImproperlyConfigured(
'{0} is missing a content type. Define {0}.content_type, '
'or override {0}.get_content_type().'.format(
Expand Down
8 changes: 1 addition & 7 deletions advanced_filters/models.py
@@ -1,16 +1,10 @@
from django.conf import settings
from django.db import models
from django.db.models import Q
from django.utils.translation import gettext_lazy as _

from .q_serializer import QSerializer

# django < 1.9 support
from django import VERSION
if VERSION >= (2, 0):
from django.utils.translation import gettext_lazy as _
else:
from django.utils.translation import ugettext_lazy as _


class UserLookupManager(models.Manager):
def filter_by_user(self, user):
Expand Down
5 changes: 2 additions & 3 deletions advanced_filters/q_serializer.py
Expand Up @@ -3,7 +3,6 @@
import base64
import time

import six
from django.db.models import Q
from django.core.serializers.base import SerializationError

Expand All @@ -25,7 +24,7 @@ def dt2ts(obj):
return time.mktime(obj.timetuple()) if isinstance(obj, date) else obj


class QSerializer(object):
class QSerializer:
"""
A Q object serializer base class. Pass base64=True when initializing
to Base-64 encode/decode the returned/passed string.
Expand Down Expand Up @@ -121,7 +120,7 @@ def dumps(self, obj):
raise SerializationError
string = json.dumps(self.serialize(obj), default=dt2ts)
if self.b64_enabled:
return base64.b64encode(six.b(string)).decode("utf-8")
return base64.b64encode(string.encode("latin-1")).decode("utf-8")
return string

def loads(self, string, raw=False):
Expand Down

0 comments on commit dfeb005

Please sign in to comment.