Skip to content

Commit 54cdffc

Browse files
committed
fix: django 5.x compatibility
1 parent 7f0b9cc commit 54cdffc

File tree

9 files changed

+177
-49
lines changed

9 files changed

+177
-49
lines changed

.github/workflows/test.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Test
2+
3+
on: push
4+
5+
jobs:
6+
build:
7+
runs-on: ubuntu-latest
8+
strategy:
9+
matrix:
10+
include:
11+
- django-version: "2.2"
12+
python-version: "3.8"
13+
- django-version: "3.2"
14+
python-version: "3.9"
15+
- django-version: "4.2"
16+
python-version: "3.10"
17+
- django-version: "4.2"
18+
python-version: "3.11"
19+
- django-version: "5.1"
20+
python-version: "3.12"
21+
- django-version: "5.2"
22+
python-version: "3.13"
23+
24+
name: Django ${{ matrix.django-version }} (Python ${{ matrix.python-version }})
25+
26+
env:
27+
DJANGO: ${{ matrix.django-version }}
28+
29+
steps:
30+
- uses: actions/checkout@v3
31+
- name: Set up Python ${{ matrix.python-version }}
32+
uses: actions/setup-python@v4
33+
with:
34+
python-version: ${{ matrix.python-version }}
35+
- name: Install dependencies
36+
run: |
37+
python3 -m pip install --upgrade pip
38+
python3 -m pip install tox tox-gh-actions
39+
- name: Test with tox
40+
run: tox

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ venv*/
1414
.python-version
1515
.coverage
1616
htmlcov/
17+
__pycache__
18+
.tox

curation/__init__.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1 @@
1-
import pkg_resources
2-
3-
try:
4-
__version__ = pkg_resources.get_distribution('django-curation').version
5-
except pkg_resources.DistributionNotFound:
6-
__version__ = None
1+
__version__ = "2.1.0"

curation/fields.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
from collections.abc import Iterable
2+
from itertools import islice, zip_longest
3+
14
from django.core import exceptions, validators
25
from django.db import models
36
from django.apps import apps
@@ -12,6 +15,33 @@
1215
from .generic import GenericForeignKey
1316
from .widgets import SourceSelect
1417

18+
try:
19+
from django.utils.choices import BaseChoiceIterator
20+
except ImportError:
21+
class BaseChoiceIterator:
22+
"""Base class for lazy iterators for choices."""
23+
24+
def __eq__(self, other):
25+
if isinstance(other, Iterable):
26+
return all(a == b for a, b in zip_longest(self, other, fillvalue=object()))
27+
return super().__eq__(other)
28+
29+
def __getitem__(self, index):
30+
if isinstance(index, slice) or index < 0:
31+
# Suboptimally consume whole iterator to handle slices and negative
32+
# indexes.
33+
return list(self)[index]
34+
try:
35+
return next(islice(self, index, index + 1))
36+
except StopIteration:
37+
raise IndexError("index out of range") from None
38+
39+
def __iter__(self):
40+
raise NotImplementedError(
41+
"BaseChoiceIterator subclasses must implement __iter__()."
42+
)
43+
44+
1545

1646
def get_content_type_id_for_model(model):
1747
value = ContentType.objects.get_for_model(model, False).pk
@@ -109,7 +139,7 @@ class CuratedGenericForeignKey(CuratedRelatedField, GenericForeignKey):
109139
pass
110140

111141

112-
class ContentTypeIdChoices(object):
142+
class ContentTypeIdChoices(BaseChoiceIterator):
113143
"""
114144
Iterable used for ContentTypeSourceField's `choices` keyword argument
115145
"""
@@ -136,7 +166,7 @@ def __iter__(self):
136166
yield (source_value, label)
137167

138168

139-
class ContentTypeSourceChoices(object):
169+
class ContentTypeSourceChoices(BaseChoiceIterator):
140170

141171
# Sentinel value if a given choice in ct_choices is a 2-tuple and so does
142172
# not have a source_value
@@ -544,6 +574,9 @@ def __init__(self, *args, **kwargs):
544574
kwargs.setdefault('on_delete', models.CASCADE)
545575
super(ContentTypeSourceField, self).__init__('contenttypes.ContentType', *args, **kwargs)
546576

577+
def get_cache_name(self):
578+
return self.name
579+
547580
def contribute_to_class(self, cls, name):
548581
super(models.ForeignKey, self).contribute_to_class(cls, name)
549582

curation/urls.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import functools
22
from django.contrib import admin
3-
from django.conf.urls import url
3+
from django.urls import re_path
44

55
from . import views as curation_views
66

@@ -15,13 +15,13 @@ def wrapper(*args, **kwargs):
1515

1616

1717
urlpatterns = [
18-
url(r'^content-type-list\.js$',
18+
re_path(r'^content-type-list\.js$',
1919
wrap(curation_views.get_content_types), # 'curation.views.get_content_types',
2020
name="curation_content_type_list"),
21-
url(r'^lookup/related/$',
21+
re_path(r'^lookup/related/$',
2222
wrap(curation_views.related_lookup), # 'curation.views.related_lookup',
2323
name="curation_related_lookup"),
24-
url(r'^r/(?P<content_type_id>\d+)/(?P<object_id>.+)/$',
24+
re_path(r'^r/(?P<content_type_id>\d+)/(?P<object_id>.+)/$',
2525
wrap(curation_views.shortcut),
2626
name="curation_shortcut"),
2727
]

pyproject.toml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
[build-system]
2+
build-backend = "setuptools.build_meta"
3+
requires = ["setuptools>=75.3.2"]
4+
5+
[project]
6+
name = "django-curation"
7+
dynamic = ["version"]
8+
description = "A model used for curating other models and proxying their attributes"
9+
readme = "README.rst"
10+
license = { text = "BSD-2-Clause" }
11+
requires-python = ">=3"
12+
authors = [
13+
{ name = "The Atlantic", email = "[email protected]" },
14+
]
15+
classifiers = [
16+
"Development Status :: 5 - Production/Stable",
17+
"Environment :: Web Environment",
18+
"Framework :: Django",
19+
"Framework :: Django :: 2.2",
20+
"Framework :: Django :: 3.2",
21+
"Framework :: Django :: 4.2",
22+
"Framework :: Django :: 5.0",
23+
"Framework :: Django :: 5.1",
24+
"Framework :: Django :: 5.2",
25+
"Programming Language :: Python :: 3 :: Only",
26+
"Programming Language :: Python :: 3.7",
27+
"Programming Language :: Python :: 3.8",
28+
"Programming Language :: Python :: 3.9",
29+
"Programming Language :: Python :: 3.10",
30+
"Programming Language :: Python :: 3.11",
31+
"Programming Language :: Python :: 3.12",
32+
"Programming Language :: Python :: 3.13",
33+
]
34+
dependencies = []
35+
36+
[project.urls]
37+
Homepage = "https://github.com/theatlantic/django-curation"
38+
39+
[tool.setuptools]
40+
zip-safe = false
41+
platforms = ["any"]
42+
include-package-data = true
43+
44+
[tool.setuptools.packages.find]
45+
include = ["curation*"]
46+
namespaces = false
47+
48+
[tool.setuptools.dynamic]
49+
version = { attr = "curation.__version__" }
50+
readme = { file = ["README.rst"] }

pytest.ini

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[pytest]
2+
DJANGO_SETTINGS_MODULE = tests.settings
3+
addopts = --tb=short --create-db
4+
django_find_project = false
5+
python_files = tests.py test_*.py *_tests.py
6+
pythonpath = .
7+
testpaths = tests

setup.py

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,3 @@
1-
#!/usr/bin/env python
2-
from __future__ import absolute_import
3-
from setuptools import setup, find_packages
1+
from setuptools import setup
42

5-
6-
setup(
7-
name='django-curation',
8-
version="2.0.2",
9-
description='A model used for curating other models and proxying their attributes',
10-
author='The Atlantic',
11-
author_email='[email protected]',
12-
url='https://github.com/theatlantic/django-curation',
13-
packages=find_packages(exclude=("tests", "tests.*")),
14-
python_requires='!=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4*, <4',
15-
classifiers=[
16-
'Environment :: Web Environment',
17-
'Intended Audience :: Developers',
18-
'Operating System :: OS Independent',
19-
'Framework :: Django',
20-
'Framework :: Django :: 2.0',
21-
'Framework :: Django :: 2.1',
22-
'Framework :: Django :: 2.2',
23-
'Programming Language :: Python',
24-
'Programming Language :: Python :: 3',
25-
'Programming Language :: Python :: 3.5',
26-
'Programming Language :: Python :: 3.6',
27-
'Programming Language :: Python :: 3.7',
28-
'Programming Language :: Python :: 3.8',
29-
],
30-
include_package_data=True,
31-
zip_safe=False,
32-
)
3+
setup()

tox.ini

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,34 @@
11
[tox]
22
skipsdist=True
3-
envlist =
4-
py37-dj{20,21,22,30,31}
3+
envlist =
4+
py{36,37,38,39}-dj22
5+
py{36,37,38,39,310}-dj32
6+
py{38,39,310}-dj40
7+
py{38,39,310,311}-dj41
8+
py{38,39,310,311,312}-dj42
9+
py{310,311,312}-dj{50,51}
10+
py{310,311,312,313}-dj52
11+
12+
[gh-actions]
13+
python =
14+
3.7: py37
15+
3.8: py38
16+
3.9: py39
17+
3.10: py310
18+
3.11: py311
19+
3.12: py312
20+
3.13: py313
21+
22+
[gh-actions:env]
23+
DJANGO =
24+
2.2: dj22
25+
3.2: dj32
26+
4.0: dj40
27+
4.1: dj41
28+
4.2: dj42
29+
5.0: dj50
30+
5.1: dj51
31+
5.2: dj52
532

633
[testenv]
734
usedevelop = True
@@ -11,11 +38,14 @@ deps =
1138
pytest
1239
pytest-cov
1340
pytest-django
14-
dj20: Django>=2.0,<2.1
15-
dj21: Django>=2.1,<2.2
1641
dj22: Django>=2.2,<3.0
17-
dj30: Django>=3.0,<3.1
18-
dj31: Django>=3.1,<3.2
42+
dj32: Django>=3.2,<4.0
43+
dj40: Django>=4.0,<4.1
44+
dj41: Django>=4.1,<4.2
45+
dj42: Django>=4.2,<4.3
46+
dj50: Django>=5.0,<5.1
47+
dj51: Django>=5.1a1,<5.2
48+
dj52: Django>=5.2,<5.3
1949

2050
[testenv:pep8]
2151
description = Run PEP8 (flake8) against the curation package directory

0 commit comments

Comments
 (0)