From 49385134b55cc236d7ae0d66b17be985cb5b24b5 Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Tue, 1 May 2018 08:17:33 +0200 Subject: [PATCH 01/20] chore: ignore .DS_Store --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 74b4086..db46e9a 100644 --- a/.gitignore +++ b/.gitignore @@ -13,5 +13,5 @@ tests/db.sqlite* /.eggs/ /htmlcov/ /advanced_filters/.coverage - +.DS_Store /tests/local.db From c88bafcb4028f80efac4b1aa11a02fe7906076e9 Mon Sep 17 00:00:00 2001 From: benny daon Date: Tue, 12 Sep 2017 12:00:02 +0200 Subject: [PATCH 02/20] python 2.6 and django < 1.7 are deprecated --- setup.py | 1 - tox.ini | 12 ++++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/setup.py b/setup.py index 9fb5fc2..bcc8618 100644 --- a/setup.py +++ b/setup.py @@ -78,7 +78,6 @@ def get_full_description(): 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.2', diff --git a/tox.ini b/tox.ini index 039d5e5..7f24d39 100644 --- a/tox.ini +++ b/tox.ini @@ -1,27 +1,23 @@ [tox] envlist = - py26-d{15,16} - py27-d{15,16,17,18,19,110} - py{33,34}-d{15,16,17,18} + py27-d{17,18,19,110} + py{33,34}-d{17,18} py34-d{19,110} py35-d{18,19,110} - pypy-d{15,16,17,18,19,110} + pypy-d{17,18,19,110} [pep8] max-line-length = 120 [testenv] deps = - d15: Django>=1.5,<1.6 - d16: Django>=1.6,<1.7 d17: Django>=1.7,<1.8 d18: Django>=1.8,<1.9 d19: Django>=1.9,<1.10 d110: Django>=1.10,<1.11 - py26: unittest2 -rtest-reqs.txt commands = pip install -e .[test] coverage run -m py.test advanced_filters - pep8 --exclude=*urls.py --exclude=*migrations -v advanced_filters + pep8 --exclude=urls.py,migrations,.ropeproject -v advanced_filters From 521b8712e31d9015c7ac92510e914514ade11467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Tue, 23 Jan 2018 06:42:35 +0100 Subject: [PATCH 03/20] fixes for Django 2.0 and 1.11, update tests --- .travis.yml | 18 +++++++++++++++++- advanced_filters/models.py | 8 ++++++-- advanced_filters/q_serializer.py | 2 +- advanced_filters/tests/test_admin.py | 5 ++++- advanced_filters/tests/test_views.py | 14 +++++++++++--- tests/customers/models.py | 2 +- tests/test_project/settings.py | 3 ++- tests/test_project/urls.py | 2 +- tox.ini | 8 +++++--- 9 files changed, 48 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index e12dacd..16e3f5a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,18 +18,32 @@ matrix: env: DJANGO="Django>=1.9,<1.10" - python: "3.4" env: DJANGO="Django>=1.10,<1.11" + - python: "3.4" + env: DJANGO="Django>=2.0,<2.1" - python: "3.5" env: DJANGO="Django>=1.9,<1.10" - python: "3.5" env: DJANGO="Django>=1.10,<1.11" + - python: "3.5" + env: DJANGO="Django>=1.11,<1.12" + - python: "3.5" + env: DJANGO="Django>=2.0,<2.1" exclude: - python: "2.6" + - python: "2.7" + env: DJANGO="Django>=2.0,<2.1" - python: "3.3" env: DJANGO="Django>=1.9,<1.10" - python: "3.3" env: DJANGO="Django>=1.10,<1.11" + - python: "3.3" + env: DJANGO="Django>=1.11,<1.12" + - python: "3.3" + env: DJANGO="Django>=2.0,<2.1" - python: "3.4" - python: "3.5" + - python: "pypy" + env: DJANGO="Django>=2.0,<2.1" env: - DJANGO="Django>=1.5,<1.6" - DJANGO="Django>=1.6,<1.7" @@ -37,6 +51,8 @@ env: - DJANGO="Django>=1.8,<1.9" - DJANGO="Django>=1.9,<1.10" - DJANGO="Django>=1.10,<1.11" + - DJANGO="Django>=1.11,<1.12" + - DJANGO="Django>=2.0,<2.1" install: - pip install $DJANGO - pip install -e .[test] @@ -44,4 +60,4 @@ script: - coverage run -m py.test advanced_filters - pep8 --exclude=*urls.py --exclude=*migrations advanced_filters -v after_success: - coveralls \ No newline at end of file + coveralls diff --git a/advanced_filters/models.py b/advanced_filters/models.py index 6534275..2c9f749 100644 --- a/advanced_filters/models.py +++ b/advanced_filters/models.py @@ -19,8 +19,12 @@ class Meta: verbose_name_plural = _('Advanced Filters') title = models.CharField(max_length=255, null=False, blank=False, verbose_name=_('Title')) - created_by = models.ForeignKey(settings.AUTH_USER_MODEL, - related_name='created_advanced_filters', verbose_name=_('Created by')) + created_by = models.ForeignKey( + settings.AUTH_USER_MODEL, + related_name='created_advanced_filters', + verbose_name=_('Created by'), + on_delete=models.CASCADE, + ) created_at = models.DateTimeField(auto_now_add=True, null=True, verbose_name=_('Created at')) url = models.CharField(max_length=255, null=False, blank=False, verbose_name=_('URL')) users = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, verbose_name=_('Users')) diff --git a/advanced_filters/q_serializer.py b/advanced_filters/q_serializer.py index 21d58df..a30a6a0 100644 --- a/advanced_filters/q_serializer.py +++ b/advanced_filters/q_serializer.py @@ -121,7 +121,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)) + return base64.b64encode(six.b(string)).decode("utf-8") return string def loads(self, string, raw=False): diff --git a/advanced_filters/tests/test_admin.py b/advanced_filters/tests/test_admin.py index f31185b..0391034 100644 --- a/advanced_filters/tests/test_admin.py +++ b/advanced_filters/tests/test_admin.py @@ -1,4 +1,7 @@ -from django.core.urlresolvers import reverse +try: + from django.urls import reverse +except: # Django < 2.0 + from django.core.urlresolvers import reverse from django.contrib.auth.models import Permission from django.db.models import Q from django.test import TestCase diff --git a/advanced_filters/tests/test_views.py b/advanced_filters/tests/test_views.py index 51a1162..00ba45e 100644 --- a/advanced_filters/tests/test_views.py +++ b/advanced_filters/tests/test_views.py @@ -6,7 +6,10 @@ except ImportError: from django.test.utils import override_settings from django.utils.encoding import force_text -from django.core.urlresolvers import reverse +try: + from django.urls import reverse +except: # Django < 2.0 + from django.core.urlresolvers import reverse import django from tests import factories @@ -47,7 +50,12 @@ def test_invalid_args(self): self.assert_view_error( 'need more than 1 value to unpack', model='a', field_name='b', exception=ValueError) - if django.VERSION >= (1, 7): + if django.VERSION >= (1, 11): + self.assert_view_error("No installed app with label 'Foo'.", + model='Foo.test', field_name='baz') + self.assert_view_error("App 'reps' doesn't have a 'Foo' model.", + model='reps.Foo', field_name='b') + elif django.VERSION >= (1, 7): self.assert_view_error("No installed app with label 'foo'.", model='foo.test', field_name='baz') self.assert_view_error("App 'reps' doesn't have a 'foo' model.", @@ -57,7 +65,7 @@ def test_invalid_args(self): model='foo.test', field_name='baz') self.assert_view_error("No installed app/model: reps.Foo", model='reps.Foo', field_name='b') - if sys.version_info >= (3, 3): + if sys.version_info >= (3, 3) or django.VERSION >= (1, 11): expected_exception = "SalesRep has no field named 'baz'" else: expected_exception = "SalesRep has no field named u'baz'" diff --git a/tests/customers/models.py b/tests/customers/models.py index 6b4b846..295191b 100644 --- a/tests/customers/models.py +++ b/tests/customers/models.py @@ -21,5 +21,5 @@ class Client(AbstractBaseUser): _('active'), default=True, help_text=_('Designates whether this user should be treated as ' 'active. Unselect this instead of deleting accounts.')) - assigned_to = models.ForeignKey('reps.SalesRep') + assigned_to = models.ForeignKey('reps.SalesRep', on_delete=models.CASCADE) date_joined = models.DateTimeField(_('date joined'), default=timezone.now) diff --git a/tests/test_project/settings.py b/tests/test_project/settings.py index a0fe29a..beb176c 100644 --- a/tests/test_project/settings.py +++ b/tests/test_project/settings.py @@ -41,7 +41,7 @@ 'tests.customers', ) -MIDDLEWARE_CLASSES = ( +MIDDLEWARE = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', @@ -49,6 +49,7 @@ 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ) +MIDDLEWARE_CLASSES = MIDDLEWARE ROOT_URLCONF = 'tests.test_project.urls' WSGI_APPLICATION = 'tests.test_project.wsgi.application' diff --git a/tests/test_project/urls.py b/tests/test_project/urls.py index 2e9425d..0284f21 100644 --- a/tests/test_project/urls.py +++ b/tests/test_project/urls.py @@ -4,6 +4,6 @@ admin.autodiscover() # django < 1.7 support urlpatterns = [ - url(r'^admin/', include(admin.site.urls)), + url(r'^admin/', admin.site.urls), url(r'^advanced_filters/', include('advanced_filters.urls')) ] diff --git a/tox.ini b/tox.ini index 7f24d39..e01516e 100644 --- a/tox.ini +++ b/tox.ini @@ -2,9 +2,9 @@ envlist = py27-d{17,18,19,110} py{33,34}-d{17,18} - py34-d{19,110} - py35-d{18,19,110} - pypy-d{17,18,19,110} + py34-d{19,110,111,20} + py35-d{18,19,110,111,20} + pypy-d{17,18,19,110,111} [pep8] max-line-length = 120 @@ -15,6 +15,8 @@ deps = d18: Django>=1.8,<1.9 d19: Django>=1.9,<1.10 d110: Django>=1.10,<1.11 + d110: Django>=1.11,<1.12 + d20: Django>=2.0,<2.1 -rtest-reqs.txt commands = From 3881751d09c60d947aa6f4fa57238d253394e39c Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Tue, 15 May 2018 09:22:54 +0200 Subject: [PATCH 04/20] fix: bump django-braces==1.13 for Django 2 support --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index bcc8618..7577903 100644 --- a/setup.py +++ b/setup.py @@ -63,7 +63,7 @@ def get_full_description(): packages=find_packages(exclude=['tests*', 'tests.*', '*.tests']), include_package_data=True, install_requires=[ - 'django-braces==1.4.0', + 'django-braces==1.13.0', 'simplejson==3.6.5', ], extras_require=dict(test=TEST_REQS), From 233e1137ffbe083716dd18165907c2d6e50700ac Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Tue, 15 May 2018 09:48:18 +0200 Subject: [PATCH 05/20] tests: correct tox env django spec for ver 1.11 --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index e01516e..08cb63c 100644 --- a/tox.ini +++ b/tox.ini @@ -15,7 +15,7 @@ deps = d18: Django>=1.8,<1.9 d19: Django>=1.9,<1.10 d110: Django>=1.10,<1.11 - d110: Django>=1.11,<1.12 + d111: Django>=1.11,<1.12 d20: Django>=2.0,<2.1 -rtest-reqs.txt From a70f5615f12500d02c46f710038e2f4f57e616d2 Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Sun, 10 Jun 2018 09:11:55 +0200 Subject: [PATCH 06/20] tests: correct make_query assertion for Django>=2 --- advanced_filters/tests/test_forms.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/advanced_filters/tests/test_forms.py b/advanced_filters/tests/test_forms.py index e38f8ea..0a407f7 100644 --- a/advanced_filters/tests/test_forms.py +++ b/advanced_filters/tests/test_forms.py @@ -5,6 +5,7 @@ from django.contrib.auth import get_user_model from django.db.models import Q, FieldDoesNotExist from django.test import TestCase +import django import pytest @@ -104,11 +105,17 @@ def test_make_query(self): assert isinstance(q, Q) assert isinstance(q.children, list) assert q.connector == 'AND' - assert not q.negated - subquery = q.children[0] - assert isinstance(subquery, Q) - assert subquery.negated - assert subquery.children[0] == ('fname__iexact', 'john') + if django.VERSION >= (2, 0): + # django 2+ flattens nested empty Query + assert q.negated + assert q.children[0] == ('fname__iexact', 'john') + else: + # django <2 has a parent Query that stays default + assert not q.negated + subquery = q.children[0] + assert isinstance(subquery, Q) + assert subquery.negated + assert subquery.children[0] == ('fname__iexact', 'john') def test_invalid_existing_query(self): Rep = get_user_model() From 30e15108b7a1ce4ed1182986812087114d1c6104 Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Sun, 10 Jun 2018 09:21:37 +0200 Subject: [PATCH 07/20] chore: add updated migrations of model attributes mostly this just updates verbose_name property of all fields since we started using explicit field names for translated field labels --- .../migrations/0003_auto_20180610_0718.py | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 advanced_filters/migrations/0003_auto_20180610_0718.py diff --git a/advanced_filters/migrations/0003_auto_20180610_0718.py b/advanced_filters/migrations/0003_auto_20180610_0718.py new file mode 100644 index 0000000..8f41a1f --- /dev/null +++ b/advanced_filters/migrations/0003_auto_20180610_0718.py @@ -0,0 +1,45 @@ +# Generated by Django 2.0.6 on 2018-06-10 07:18 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('advanced_filters', '0002_advancedfilter_created_at'), + ] + + operations = [ + migrations.AlterField( + model_name='advancedfilter', + name='created_at', + field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='Created at'), + ), + migrations.AlterField( + model_name='advancedfilter', + name='created_by', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='created_advanced_filters', to=settings.AUTH_USER_MODEL, verbose_name='Created by'), + ), + migrations.AlterField( + model_name='advancedfilter', + name='groups', + field=models.ManyToManyField(blank=True, to='auth.Group', verbose_name='Groups'), + ), + migrations.AlterField( + model_name='advancedfilter', + name='title', + field=models.CharField(max_length=255, verbose_name='Title'), + ), + migrations.AlterField( + model_name='advancedfilter', + name='url', + field=models.CharField(max_length=255, verbose_name='URL'), + ), + migrations.AlterField( + model_name='advancedfilter', + name='users', + field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Users'), + ), + ] From 8cb3371e51d988c2015907ce077989a9ef9b9870 Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Sun, 10 Jun 2018 12:38:22 +0200 Subject: [PATCH 08/20] fix: use request context processor in test_project required with current admin filter template to display the edit button --- .gitignore | 1 + tests/test_project/settings.py | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index db46e9a..2bdfe29 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ tests/db.sqlite* /htmlcov/ /advanced_filters/.coverage .DS_Store +.pytest_cache /tests/local.db diff --git a/tests/test_project/settings.py b/tests/test_project/settings.py index beb176c..84b60f4 100644 --- a/tests/test_project/settings.py +++ b/tests/test_project/settings.py @@ -68,6 +68,7 @@ 'django.template.context_processors.debug', 'django.template.context_processors.i18n', 'django.template.context_processors.media', + 'django.template.context_processors.request', 'django.template.context_processors.static', 'django.template.context_processors.tz', 'django.contrib.messages.context_processors.messages', From 3f9596386e0e7e5560e4a290c65bbfb5040fa125 Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Sun, 10 Jun 2018 12:48:26 +0200 Subject: [PATCH 09/20] style: avoid all-catch except clause --- advanced_filters/tests/test_admin.py | 2 +- advanced_filters/tests/test_views.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/advanced_filters/tests/test_admin.py b/advanced_filters/tests/test_admin.py index 0391034..d993b64 100644 --- a/advanced_filters/tests/test_admin.py +++ b/advanced_filters/tests/test_admin.py @@ -1,6 +1,6 @@ try: from django.urls import reverse -except: # Django < 2.0 +except ImportError: # Django < 2.0 from django.core.urlresolvers import reverse from django.contrib.auth.models import Permission from django.db.models import Q diff --git a/advanced_filters/tests/test_views.py b/advanced_filters/tests/test_views.py index 00ba45e..f264a59 100644 --- a/advanced_filters/tests/test_views.py +++ b/advanced_filters/tests/test_views.py @@ -8,7 +8,7 @@ from django.utils.encoding import force_text try: from django.urls import reverse -except: # Django < 2.0 +except ImportError: # Django < 2.0 from django.core.urlresolvers import reverse import django From e769781ac489dfd408c2f872b2d60603451fc677 Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Sun, 10 Jun 2018 12:49:36 +0200 Subject: [PATCH 10/20] chore: bump to next minor release 1.1.0 Since we're breaking backward compatiblity, by dropping Python 2.6 --- advanced_filters/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/advanced_filters/__init__.py b/advanced_filters/__init__.py index 6773694..1a72d32 100644 --- a/advanced_filters/__init__.py +++ b/advanced_filters/__init__.py @@ -1 +1 @@ -__version__ = '1.0.7.1' +__version__ = '1.1.0' From 1efdea02c6cc518aa915365b9c9a7ead70fb7f5c Mon Sep 17 00:00:00 2001 From: predatell <898242+predatell@users.noreply.github.com> Date: Wed, 20 Jun 2018 08:58:03 +0000 Subject: [PATCH 11/20] lower and upper bounds in install_requires --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index bcc8618..4d5f66d 100644 --- a/setup.py +++ b/setup.py @@ -63,8 +63,8 @@ def get_full_description(): packages=find_packages(exclude=['tests*', 'tests.*', '*.tests']), include_package_data=True, install_requires=[ - 'django-braces==1.4.0', - 'simplejson==3.6.5', + 'django-braces>=1.4.0,<2', + 'simplejson>=3.6.5,<4', ], extras_require=dict(test=TEST_REQS), zip_safe=False, From 666d9212fe05ecc70836535d1fcbee40dbe510ea Mon Sep 17 00:00:00 2001 From: Goncalo Gomes Date: Tue, 28 Aug 2018 17:35:59 +0200 Subject: [PATCH 12/20] fix ValueError while creating empty form --- advanced_filters/forms.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/advanced_filters/forms.py b/advanced_filters/forms.py index 51453da..45c51ca 100644 --- a/advanced_filters/forms.py +++ b/advanced_filters/forms.py @@ -209,16 +209,10 @@ def __init__(self, *args, **kwargs): form = self.forms[0] self.fields = form.visible_fields() - @property - def empty_form(self): - form = self.form( - model_fields=self.model_fields, - auto_id=self.auto_id, - prefix=self.add_prefix('__prefix__'), - empty_permitted=True, - ) - self.add_fields(form, None) - return form + def get_form_kwargs(self, index): + kwargs = super(AdvancedFilterFormSet, self).get_form_kwargs(index) + kwargs['model_fields'] = self.model_fields + return kwargs def _construct_forms(self): # not strictly required, but Django 1.5 calls this on init From ae3a31b43c6936d43db0ca6b025c7a1cfbde8329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dlouh=C3=BD?= Date: Tue, 4 Sep 2018 12:08:21 +0200 Subject: [PATCH 13/20] test in Django 2.1 --- .travis.yml | 37 ++++++++++++++++++++----------------- test-reqs.txt | 2 +- tox.ini | 5 +++-- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index 16e3f5a..9bcbc7d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: python sudo: false cache: pip python: - - "2.6" - "2.7" - "3.3" - "3.4" @@ -14,24 +13,23 @@ matrix: env: DJANGO="Django>=1.5,<1.6" - python: "2.6" env: DJANGO="Django>=1.6,<1.7" - - python: "3.4" - env: DJANGO="Django>=1.9,<1.10" - - python: "3.4" - env: DJANGO="Django>=1.10,<1.11" - - python: "3.4" - env: DJANGO="Django>=2.0,<2.1" - - python: "3.5" - env: DJANGO="Django>=1.9,<1.10" - - python: "3.5" - env: DJANGO="Django>=1.10,<1.11" - - python: "3.5" + - python: "3.6" env: DJANGO="Django>=1.11,<1.12" - - python: "3.5" + - python: "3.6" env: DJANGO="Django>=2.0,<2.1" + - python: "3.6" + env: DJANGO="Django>=2.1,<2.2" PYTEST_DJANGO="pytest-django==3.4.2" exclude: - - python: "2.6" - python: "2.7" env: DJANGO="Django>=2.0,<2.1" + - python: "2.7" + env: DJANGO="Django>=2.1,<2.2" PYTEST_DJANGO="pytest-django==3.4.2" + - python: "3.5" + env: DJANGO="Django>=1.5,<1.6" + - python: "3.5" + env: DJANGO="Django>=1.6,<1.7" + - python: "3.5" + env: DJANGO="Django>=1.7,<1.8" - python: "3.3" env: DJANGO="Django>=1.9,<1.10" - python: "3.3" @@ -40,10 +38,14 @@ matrix: env: DJANGO="Django>=1.11,<1.12" - python: "3.3" env: DJANGO="Django>=2.0,<2.1" - - python: "3.4" - - python: "3.5" - python: "pypy" env: DJANGO="Django>=2.0,<2.1" + - python: "3.3" + env: DJANGO="Django>=2.1,<2.2" PYTEST_DJANGO="pytest-django==3.4.2" + - python: "3.4" + env: DJANGO="Django>=2.1,<2.2" PYTEST_DJANGO="pytest-django==3.4.2" + - python: "pypy" + env: DJANGO="Django>=2.1,<2.2" PYTEST_DJANGO="pytest-django==3.4.2" env: - DJANGO="Django>=1.5,<1.6" - DJANGO="Django>=1.6,<1.7" @@ -53,9 +55,10 @@ env: - DJANGO="Django>=1.10,<1.11" - DJANGO="Django>=1.11,<1.12" - DJANGO="Django>=2.0,<2.1" + - DJANGO="Django>=2.1,<2.2" PYTEST_DJANGO="pytest-django==3.4.2" install: - pip install $DJANGO - - pip install -e .[test] + - pip install -e .[test] $PYTEST_DJANGO script: - coverage run -m py.test advanced_filters - pep8 --exclude=*urls.py --exclude=*migrations advanced_filters -v diff --git a/test-reqs.txt b/test-reqs.txt index e0d85fb..c578204 100644 --- a/test-reqs.txt +++ b/test-reqs.txt @@ -1,4 +1,4 @@ coveralls==0.5 factory-boy==2.5.2 pep8==1.6.2 -pytest-django==2.9.1 \ No newline at end of file +pytest-django==2.9.1 diff --git a/tox.ini b/tox.ini index 08cb63c..5492d7c 100644 --- a/tox.ini +++ b/tox.ini @@ -2,8 +2,8 @@ envlist = py27-d{17,18,19,110} py{33,34}-d{17,18} - py34-d{19,110,111,20} - py35-d{18,19,110,111,20} + py34-d{19,110,111,20,21} + py35-d{18,19,110,111,20,21} pypy-d{17,18,19,110,111} [pep8] @@ -17,6 +17,7 @@ deps = d110: Django>=1.10,<1.11 d111: Django>=1.11,<1.12 d20: Django>=2.0,<2.1 + d21: Django>=2.1,<2.2 -rtest-reqs.txt commands = From d3cb81eab0019a3f7a5e6ff201ec332175742392 Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Sat, 8 Sep 2018 12:55:40 +0200 Subject: [PATCH 14/20] tests: update pytest-django in diff. envs + tox --- .travis.yml | 21 ++++++++++++--------- test-reqs.txt | 1 - tox.ini | 7 +++++-- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9bcbc7d..e5debd5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,15 +47,18 @@ matrix: - python: "pypy" env: DJANGO="Django>=2.1,<2.2" PYTEST_DJANGO="pytest-django==3.4.2" env: - - DJANGO="Django>=1.5,<1.6" - - DJANGO="Django>=1.6,<1.7" - - DJANGO="Django>=1.7,<1.8" - - DJANGO="Django>=1.8,<1.9" - - DJANGO="Django>=1.9,<1.10" - - DJANGO="Django>=1.10,<1.11" - - DJANGO="Django>=1.11,<1.12" - - DJANGO="Django>=2.0,<2.1" - - DJANGO="Django>=2.1,<2.2" PYTEST_DJANGO="pytest-django==3.4.2" + global: + - PYTEST_DJANGO=pytest-django==2.9.1 + matrix: + - DJANGO="Django>=1.5,<1.6" + - DJANGO="Django>=1.6,<1.7" + - DJANGO="Django>=1.7,<1.8" + - DJANGO="Django>=1.8,<1.9" + - DJANGO="Django>=1.9,<1.10" + - DJANGO="Django>=1.10,<1.11" + - DJANGO="Django>=1.11,<1.12" + - DJANGO="Django>=2.0,<2.1" + - DJANGO="Django>=2.1,<2.2" PYTEST_DJANGO="pytest-django==3.4.2" install: - pip install $DJANGO - pip install -e .[test] $PYTEST_DJANGO diff --git a/test-reqs.txt b/test-reqs.txt index c578204..05f2926 100644 --- a/test-reqs.txt +++ b/test-reqs.txt @@ -1,4 +1,3 @@ coveralls==0.5 factory-boy==2.5.2 pep8==1.6.2 -pytest-django==2.9.1 diff --git a/tox.ini b/tox.ini index 5492d7c..2dd8546 100644 --- a/tox.ini +++ b/tox.ini @@ -2,8 +2,9 @@ envlist = py27-d{17,18,19,110} py{33,34}-d{17,18} - py34-d{19,110,111,20,21} + py34-d{19,110,111,20} py35-d{18,19,110,111,20,21} + py36-d{111,20,21} pypy-d{17,18,19,110,111} [pep8] @@ -18,9 +19,11 @@ deps = d111: Django>=1.11,<1.12 d20: Django>=2.0,<2.1 d21: Django>=2.1,<2.2 + !d21: pytest-django==2.9.1 + d21: pytest-django==3.4.2 -rtest-reqs.txt commands = - pip install -e .[test] + pip install -e . coverage run -m py.test advanced_filters pep8 --exclude=urls.py,migrations,.ropeproject -v advanced_filters From d6b2d9ab25e80e10f30d6d39defc6f558f2b5274 Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Sun, 16 Sep 2018 09:03:43 +0200 Subject: [PATCH 15/20] chore: cleanup Django < 1.7 support remnants also remove oldr python/django versions from .travis.yml --- .travis.yml | 10 ---------- advanced_filters/admin.py | 9 ++------- advanced_filters/forms.py | 18 ++++-------------- advanced_filters/views.py | 15 +++------------ tests/test_project/urls.py | 2 -- 5 files changed, 9 insertions(+), 45 deletions(-) diff --git a/.travis.yml b/.travis.yml index e5debd5..9e7e347 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,10 +9,6 @@ python: - "pypy" matrix: include: - - python: "2.6" - env: DJANGO="Django>=1.5,<1.6" - - python: "2.6" - env: DJANGO="Django>=1.6,<1.7" - python: "3.6" env: DJANGO="Django>=1.11,<1.12" - python: "3.6" @@ -24,10 +20,6 @@ matrix: env: DJANGO="Django>=2.0,<2.1" - python: "2.7" env: DJANGO="Django>=2.1,<2.2" PYTEST_DJANGO="pytest-django==3.4.2" - - python: "3.5" - env: DJANGO="Django>=1.5,<1.6" - - python: "3.5" - env: DJANGO="Django>=1.6,<1.7" - python: "3.5" env: DJANGO="Django>=1.7,<1.8" - python: "3.3" @@ -50,8 +42,6 @@ env: global: - PYTEST_DJANGO=pytest-django==2.9.1 matrix: - - DJANGO="Django>=1.5,<1.6" - - DJANGO="Django>=1.6,<1.7" - DJANGO="Django>=1.7,<1.8" - DJANGO="Django>=1.8,<1.9" - DJANGO="Django>=1.9,<1.10" diff --git a/advanced_filters/admin.py b/advanced_filters/admin.py index 9401064..5663fdb 100644 --- a/advanced_filters/admin.py +++ b/advanced_filters/admin.py @@ -2,15 +2,10 @@ from django.conf import settings from django.contrib import admin, messages +from django.contrib.admin.utils import unquote from django.http import HttpResponseRedirect -from django.utils.translation import ugettext_lazy as _ - -try: - from django.contrib.admin.utils import unquote -except ImportError: - # django < 1.7 support - from django.contrib.admin.util import unquote from django.shortcuts import resolve_url +from django.utils.translation import ugettext_lazy as _ from .forms import AdvancedFilterForm from .models import AdvancedFilter diff --git a/advanced_filters/forms.py b/advanced_filters/forms.py index 45c51ca..243f8ec 100644 --- a/advanced_filters/forms.py +++ b/advanced_filters/forms.py @@ -5,22 +5,11 @@ from django import forms -try: - from django.apps import apps - get_model = apps.get_model -except ImportError: - # django < 1.7 support - from django.db.models import get_model +from django.apps import apps from django.conf import settings from django.contrib import admin - -try: - from django.contrib.admin.utils import get_fields_from_path -except ImportError: - # django < 1.7 support - from django.contrib.admin.util import get_fields_from_path - +from django.contrib.admin.utils import get_fields_from_path from django.db.models import Q, FieldDoesNotExist from django.db.models.fields import DateField from django.forms.formsets import formset_factory, BaseFormSet @@ -230,6 +219,7 @@ def forms(self): forms.append(self.empty_form) # add initial empty form return forms + AFQFormSet = formset_factory( AdvancedFilterQueryForm, formset=AdvancedFilterFormSet, extra=1, can_delete=True) @@ -294,7 +284,7 @@ def __init__(self, *args, **kwargs): self._model = model_admin.model elif instance and instance.model: # get existing instance model - self._model = get_model(*instance.model.split('.')) + self._model = apps.get_model(*instance.model.split('.')) try: model_admin = admin.site._registry[self._model] except KeyError: diff --git a/advanced_filters/views.py b/advanced_filters/views.py index f7f6241..feb265f 100644 --- a/advanced_filters/views.py +++ b/advanced_filters/views.py @@ -1,18 +1,9 @@ from operator import itemgetter import logging -try: - from django.apps import apps - get_model = apps.get_model -except ImportError: - # django < 1.7 support - from django.db.models import get_model +from django.apps import apps from django.conf import settings -try: - from django.contrib.admin.utils import get_fields_from_path -except ImportError: - # django < 1.7 support - from django.contrib.admin.util import get_fields_from_path +from django.contrib.admin.utils import get_fields_from_path from django.db import models from django.db.models.fields import FieldDoesNotExist from django.utils.encoding import force_text @@ -43,7 +34,7 @@ def get(self, request, model=None, field_name=None): status=400) app_label, model_name = model.split('.', 1) try: - model_obj = get_model(app_label, model_name) + model_obj = apps.get_model(app_label, model_name) field = get_fields_from_path(model_obj, field_name)[-1] model_obj = field.model # use new model if followed a ForeignKey except AttributeError as e: diff --git a/tests/test_project/urls.py b/tests/test_project/urls.py index 0284f21..f3c5556 100644 --- a/tests/test_project/urls.py +++ b/tests/test_project/urls.py @@ -1,8 +1,6 @@ from django.conf.urls import include, url from django.contrib import admin -admin.autodiscover() # django < 1.7 support - urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^advanced_filters/', include('advanced_filters.urls')) From 6bdb6aaef764665b10919e2573a407c7be004bd3 Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Sun, 16 Sep 2018 09:47:57 +0200 Subject: [PATCH 16/20] fix: add python 3.6 and 3.7 in travis and add Python 3.7 to tox matrix --- .travis.yml | 6 ++++++ tox.ini | 1 + 2 files changed, 7 insertions(+) diff --git a/.travis.yml b/.travis.yml index 9e7e347..b22a702 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,8 @@ python: - "3.3" - "3.4" - "3.5" + - "3.6" + - "3.7" - "pypy" matrix: include: @@ -15,6 +17,10 @@ matrix: env: DJANGO="Django>=2.0,<2.1" - python: "3.6" env: DJANGO="Django>=2.1,<2.2" PYTEST_DJANGO="pytest-django==3.4.2" + - python: "3.7" + env: DJANGO="Django>=2.0,<2.1" + - python: "3.7" + env: DJANGO="Django>=2.1,<2.2" PYTEST_DJANGO="pytest-django==3.4.2" exclude: - python: "2.7" env: DJANGO="Django>=2.0,<2.1" diff --git a/tox.ini b/tox.ini index 2dd8546..67db49d 100644 --- a/tox.ini +++ b/tox.ini @@ -5,6 +5,7 @@ envlist = py34-d{19,110,111,20} py35-d{18,19,110,111,20,21} py36-d{111,20,21} + py37-d{20,21} pypy-d{17,18,19,110,111} [pep8] From 52ebee2f87bc3df468df18b7b111504920da998e Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Sun, 16 Sep 2018 10:42:59 +0200 Subject: [PATCH 17/20] chore: drop python 3.3 support in tox (couldn't make it work with 3.3 again for the life of me) Also, fix matrix duplicity; and comment out 3.7 in travis as in: https://github.com/travis-ci/travis-ci/issues/9815 --- .travis.yml | 10 ++++------ tox.ini | 3 +-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index b22a702..9c43239 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,6 @@ python: - "3.3" - "3.4" - "3.5" - - "3.6" - - "3.7" - "pypy" matrix: include: @@ -17,10 +15,10 @@ matrix: env: DJANGO="Django>=2.0,<2.1" - python: "3.6" env: DJANGO="Django>=2.1,<2.2" PYTEST_DJANGO="pytest-django==3.4.2" - - python: "3.7" - env: DJANGO="Django>=2.0,<2.1" - - python: "3.7" - env: DJANGO="Django>=2.1,<2.2" PYTEST_DJANGO="pytest-django==3.4.2" + # - python: "3.7" + # env: DJANGO="Django>=2.0,<2.1" + # - python: "3.7" + # env: DJANGO="Django>=2.1,<2.2" PYTEST_DJANGO="pytest-django==3.4.2" exclude: - python: "2.7" env: DJANGO="Django>=2.0,<2.1" diff --git a/tox.ini b/tox.ini index 67db49d..58d2dc5 100644 --- a/tox.ini +++ b/tox.ini @@ -1,8 +1,7 @@ [tox] envlist = py27-d{17,18,19,110} - py{33,34}-d{17,18} - py34-d{19,110,111,20} + py34-d{17,18,19,110,111,20} py35-d{18,19,110,111,20,21} py36-d{111,20,21} py37-d{20,21} From 88b7405b31b520c5d87f8c3ba4df0d2c6a4fa2a1 Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Sat, 22 Sep 2018 12:33:25 +0200 Subject: [PATCH 18/20] fix: remove compat forks for Django versions < 1.7 --- advanced_filters/admin.py | 6 ---- advanced_filters/forms.py | 8 ----- .../templates/admin/advanced_filters.html | 4 +-- .../admin/advanced_filters/change_form.html | 4 +-- advanced_filters/tests/test_admin.py | 29 ++++--------------- advanced_filters/tests/test_q_serializer.py | 5 ---- conftest.py | 6 ---- 7 files changed, 7 insertions(+), 55 deletions(-) diff --git a/advanced_filters/admin.py b/advanced_filters/admin.py index 5663fdb..5cd7f5e 100644 --- a/advanced_filters/admin.py +++ b/advanced_filters/admin.py @@ -34,12 +34,6 @@ def queryset(self, request, queryset): filters = AdvancedFilter.objects.filter(id=self.value()) if hasattr(filters, 'first'): advfilter = filters.first() - else: - # django == 1.5 support - try: - advfilter = filters.order_by()[0] - except IndexError: - advfilter = None if not advfilter: logger.error("AdvancedListFilters.queryset: Invalid filter id") return queryset diff --git a/advanced_filters/forms.py b/advanced_filters/forms.py index 243f8ec..9068f74 100644 --- a/advanced_filters/forms.py +++ b/advanced_filters/forms.py @@ -203,14 +203,6 @@ def get_form_kwargs(self, index): kwargs['model_fields'] = self.model_fields return kwargs - def _construct_forms(self): - # not strictly required, but Django 1.5 calls this on init - # django == 1.5 support - self.forms = [] - for i in range(min(self.total_form_count(), self.absolute_max)): - self.forms.append(self._construct_form( - i, model_fields=self.model_fields)) - @cached_property def forms(self): # override the original property to include `model_fields` argument diff --git a/advanced_filters/templates/admin/advanced_filters.html b/advanced_filters/templates/admin/advanced_filters.html index 6aac20c..f1f5487 100644 --- a/advanced_filters/templates/admin/advanced_filters.html +++ b/advanced_filters/templates/admin/advanced_filters.html @@ -1,7 +1,5 @@ {% extends original_change_list_template %} {% load i18n static admin_modify %} -{# django == 1.5 support #} -{# {% load cycle from future %} #} {% block extrastyle %} {{ advanced_filters.media.css }} @@ -79,7 +77,7 @@

{% trans "Create advanced filter" %}:

// Do nothing if target element is select2 input if( $(e.target).hasClass('select2-input') ) { return true; - } + } // Else call parent method $.magnificPopup.proto._onFocusIn.call(this,e); }; diff --git a/advanced_filters/templates/admin/advanced_filters/change_form.html b/advanced_filters/templates/admin/advanced_filters/change_form.html index 3c68840..e64920d 100644 --- a/advanced_filters/templates/admin/advanced_filters/change_form.html +++ b/advanced_filters/templates/admin/advanced_filters/change_form.html @@ -1,8 +1,6 @@ {% extends "admin/change_form.html" %} {% load i18n admin_static admin_modify admin_urls %} -{# django == 1.5 support #} -{# {% load cycle from future %} #} {% block extrastyle %} {{ adminform.media.css }} @@ -51,7 +49,7 @@

{% trans "Change advanced filter" %}:

{% submit_row %} {% endblock %} - + {% prepopulated_fields_js %} {{ adminform.media.js }} diff --git a/advanced_filters/tests/test_admin.py b/advanced_filters/tests/test_admin.py index d993b64..320d5ff 100644 --- a/advanced_filters/tests/test_admin.py +++ b/advanced_filters/tests/test_admin.py @@ -47,12 +47,8 @@ def test_change_and_goto(self): with self.settings(ADVANCED_FILTER_EDIT_BY_USER=False): res = self.client.post(url, data=form_data) assert res.status_code == 302 - # django == 1.5 support - if hasattr(res, 'url'): - assert res.url.endswith('admin/customers/client/?_afilter=1') - else: - url = res['location'] - assert url.endswith('admin/customers/client/?_afilter=1') + url = res['location'] + assert url.endswith('admin/customers/client/?_afilter=1') def test_create_page_disabled(self): self.user.user_permissions.add(Permission.objects.get( @@ -113,7 +109,6 @@ def test_create_form_valid(self): assert form.is_valid() assert AdvancedFilter.objects.count() == 1 - # django == 1.5 support created_filter = AdvancedFilter.objects.order_by('-pk')[0] assert created_filter.title == self.good_data['title'] @@ -125,15 +120,10 @@ def test_create_form_valid(self): assert res.status_code == 302 assert AdvancedFilter.objects.count() == 2 - # django == 1.5 support created_filter = AdvancedFilter.objects.order_by('-pk')[0] - if hasattr(res, 'url'): - assert res.url.endswith('admin/customers/client/?_afilter=%s' % - created_filter.pk) - else: - url = res['location'] - assert url.endswith('admin/customers/client/?_afilter=%s' % - created_filter.pk) + url = res['location'] + assert url.endswith('admin/customers/client/?_afilter=%s' % + created_filter.pk) assert list(created_filter.query.children[0]) == self.query @@ -162,9 +152,6 @@ def test_filters_not_available(self): # filter not applied due to user not being in list if hasattr(cl, 'queryset'): assert cl.queryset.count() == 10 - else: - # django == 1.5 support - assert cl.query_set.count() == 10 def test_filters_available_to_users(self): self.a.users.add(self.user) @@ -176,9 +163,6 @@ def test_filters_available_to_users(self): for f in cl.filter_specs) if hasattr(cl, 'queryset'): assert cl.queryset.count() == 2 - else: - # django == 1.5 support - assert cl.query_set.count() == 2 def test_filters_available_to_groups(self): group = self.user.groups.create() @@ -190,6 +174,3 @@ def test_filters_available_to_groups(self): assert cl.filter_specs if hasattr(cl, 'queryset'): assert cl.queryset.count() == 2 - else: - # django == 1.5 support - assert cl.query_set.count() == 2 diff --git a/advanced_filters/tests/test_q_serializer.py b/advanced_filters/tests/test_q_serializer.py index 6f3f4c8..a098e8d 100644 --- a/advanced_filters/tests/test_q_serializer.py +++ b/advanced_filters/tests/test_q_serializer.py @@ -1,12 +1,9 @@ from django.db.models import Q from django.test import TestCase -import django import json from ..q_serializer import QSerializer -NEWER_DJANGO = django.VERSION >= (1, 6) - class QSerializerTest(TestCase): correct_query = { @@ -14,8 +11,6 @@ class QSerializerTest(TestCase): 'connector': u'AND', 'negated': False, } - if not NEWER_DJANGO: - correct_query['subtree_parents'] = [] def setUp(self): self.s = QSerializer() diff --git a/conftest.py b/conftest.py index f88223a..e69de29 100644 --- a/conftest.py +++ b/conftest.py @@ -1,6 +0,0 @@ -import django - -IGNORE_MIGRATIONS = django.VERSION < (1, 7) - -if IGNORE_MIGRATIONS: - collect_ignore = ["advanced_filters/migrations"] From 4b9422c82fee5106cfd2ac9f716bfb417f050b90 Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Sat, 22 Sep 2018 12:39:32 +0200 Subject: [PATCH 19/20] docs: update docs to specify supported django ver --- README.rst | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index f23d1bb..db24ca4 100644 --- a/README.rst +++ b/README.rst @@ -26,11 +26,10 @@ For release notes, see `Changelog = 1.5 (Django 1.5 - 1.9 on Python 2/3/PyPy2) +- Django >= 1.7 (Django 1.7 - 2.1 on Python 2/3/PyPy2) - django-braces == 1.4.0 - simplejson == 3.6.5 -*NOTE*: While the latest Django 1.5.X is supported, the bundled jQuery it includes is outdated (1.4.2) and as such, most of our admin frontend scripts fail. This means that to use advanced-filters in Django 1.5 admin, you'd have to probably include your own jQuery (1.9 or later) and add it to global namespace prior to other scripts in `AdvancedFilterForm.Meta`. Installation & Set up ===================== @@ -53,11 +52,17 @@ Extending a ModelAdmin is pretty straightforward: class ProfileAdmin(AdminAdvancedFiltersMixin, models.ModelAdmin): list_filter = ('name', 'language', 'ts') # simple list filters - # select from these fields in the advanced filter creation form + # specify which fields can be selected in the advanced filter + # creation form advanced_filter_fields = ( - 'name', 'language', 'ts' + 'name', + 'language', + 'ts', + # even use related fields as lookup fields - 'country__name', 'posts__title', 'comments__content' + 'country__name', + 'posts__title', + 'comments__content', ) Adding a new advanced filter (see below) will display a new list filter From 048a430e96005a88938925dfad0210ffbf1fdd79 Mon Sep 17 00:00:00 2001 From: Pavel Savchenko Date: Sun, 16 Sep 2018 08:55:35 +0200 Subject: [PATCH 20/20] chore: update changelog of 1.1 --- CHANGELOG.rst | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f622bc1..4e8379e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,47 @@ Changelog ========= +1.1.0 - The future is bright +---------------------------- + +This release highlights support for Django 2.0 and 2.1 as well as +deprecating support for versions Django < 1.7 and Python 2.6 and 3.3 + +Bug fixes +~~~~~~~~~ + +- bump django-braces==1.13 for Django 2 support (Merge 80e055e) +- use request context processor in test_project (Merge 80e055e) + +Misc. +~~~~~ + +- ignore .DS_Store +- fixes for Django 2.0 and 1.11, update tests (Merge 80e055e) +- test in Django 2.1 (Merge d8d236d) +- add updated migrations of model attributes (Merge 80e055e) +- fix ValueError while creating empty form (Merge d8d236d) +- python 2.6 and django < 1.7 are deprecated +- lower and upper bounds in install_requires +- avoid all-catch except clause (Merge 80e055e) + +Tests +~~~~~ + +- correct tox env django spec for ver 1.11 (Merge 80e055e) +- correct make_query assertion for Django>=2 (Merge 80e055e) +- update pytest-django in diff. envs + tox (Merge d8d236d) + +Contributors +~~~~~~~~~~~~ + +- Goncalo Gomes +- predatell +- Petr DlouhĂ˝ +- benny daon +- Pavel Savchenko + + 1.0.7.1 - Fix PyPi fail -----------------------