Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Test

on: push

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- django-version: "2.2"
python-version: "3.8"
- django-version: "3.2"
python-version: "3.9"
- django-version: "4.2"
python-version: "3.10"
- django-version: "4.2"
python-version: "3.11"
- django-version: "5.1"
python-version: "3.12"
- django-version: "5.2"
python-version: "3.13"

name: Django ${{ matrix.django-version }} (Python ${{ matrix.python-version }})

env:
DJANGO: ${{ matrix.django-version }}

steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python3 -m pip install --upgrade pip
python3 -m pip install tox tox-gh-actions
- name: Test with tox
run: tox
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ venv*/
.python-version
.coverage
htmlcov/
__pycache__
.tox
7 changes: 1 addition & 6 deletions curation/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1 @@
import pkg_resources

try:
__version__ = pkg_resources.get_distribution('django-curation').version
except pkg_resources.DistributionNotFound:
__version__ = None
__version__ = "2.1.0"
37 changes: 35 additions & 2 deletions curation/fields.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from collections.abc import Iterable
from itertools import islice, zip_longest

from django.core import exceptions, validators
from django.db import models
from django.apps import apps
Expand All @@ -12,6 +15,33 @@
from .generic import GenericForeignKey
from .widgets import SourceSelect

try:
from django.utils.choices import BaseChoiceIterator
except ImportError:
class BaseChoiceIterator:
"""Base class for lazy iterators for choices."""

def __eq__(self, other):
if isinstance(other, Iterable):
return all(a == b for a, b in zip_longest(self, other, fillvalue=object()))
return super().__eq__(other)

def __getitem__(self, index):
if isinstance(index, slice) or index < 0:
# Suboptimally consume whole iterator to handle slices and negative
# indexes.
return list(self)[index]
try:
return next(islice(self, index, index + 1))
except StopIteration:
raise IndexError("index out of range") from None

def __iter__(self):
raise NotImplementedError(
"BaseChoiceIterator subclasses must implement __iter__()."
)



def get_content_type_id_for_model(model):
value = ContentType.objects.get_for_model(model, False).pk
Expand Down Expand Up @@ -109,7 +139,7 @@ class CuratedGenericForeignKey(CuratedRelatedField, GenericForeignKey):
pass


class ContentTypeIdChoices(object):
class ContentTypeIdChoices(BaseChoiceIterator):
"""
Iterable used for ContentTypeSourceField's `choices` keyword argument
"""
Expand All @@ -136,7 +166,7 @@ def __iter__(self):
yield (source_value, label)


class ContentTypeSourceChoices(object):
class ContentTypeSourceChoices(BaseChoiceIterator):

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

def get_cache_name(self):
return self.name

def contribute_to_class(self, cls, name):
super(models.ForeignKey, self).contribute_to_class(cls, name)

Expand Down
8 changes: 4 additions & 4 deletions curation/urls.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import functools
from django.contrib import admin
from django.conf.urls import url
from django.urls import re_path

from . import views as curation_views

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


urlpatterns = [
url(r'^content-type-list\.js$',
re_path(r'^content-type-list\.js$',
wrap(curation_views.get_content_types), # 'curation.views.get_content_types',
name="curation_content_type_list"),
url(r'^lookup/related/$',
re_path(r'^lookup/related/$',
wrap(curation_views.related_lookup), # 'curation.views.related_lookup',
name="curation_related_lookup"),
url(r'^r/(?P<content_type_id>\d+)/(?P<object_id>.+)/$',
re_path(r'^r/(?P<content_type_id>\d+)/(?P<object_id>.+)/$',
wrap(curation_views.shortcut),
name="curation_shortcut"),
]
50 changes: 50 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
[build-system]
build-backend = "setuptools.build_meta"
requires = ["setuptools>=75.3.2"]

[project]
name = "django-curation"
dynamic = ["version"]
description = "A model used for curating other models and proxying their attributes"
readme = "README.rst"
license = { text = "BSD-2-Clause" }
requires-python = ">=3"
authors = [
{ name = "The Atlantic", email = "programmers@theatlantic.com" },
]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Web Environment",
"Framework :: Django",
"Framework :: Django :: 2.2",
"Framework :: Django :: 3.2",
"Framework :: Django :: 4.2",
"Framework :: Django :: 5.0",
"Framework :: Django :: 5.1",
"Framework :: Django :: 5.2",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]
dependencies = []

[project.urls]
Homepage = "https://github.com/theatlantic/django-curation"

[tool.setuptools]
zip-safe = false
platforms = ["any"]
include-package-data = true

[tool.setuptools.packages.find]
include = ["curation*"]
namespaces = false

[tool.setuptools.dynamic]
version = { attr = "curation.__version__" }
readme = { file = ["README.rst"] }
7 changes: 7 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[pytest]
DJANGO_SETTINGS_MODULE = tests.settings
addopts = --tb=short --create-db
django_find_project = false
python_files = tests.py test_*.py *_tests.py
pythonpath = .
testpaths = tests
33 changes: 2 additions & 31 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,3 @@
#!/usr/bin/env python
from __future__ import absolute_import
from setuptools import setup, find_packages
from setuptools import setup


setup(
name='django-curation',
version="2.0.2",
description='A model used for curating other models and proxying their attributes',
author='The Atlantic',
author_email='programmers@theatlantic.com',
url='https://github.com/theatlantic/django-curation',
packages=find_packages(exclude=("tests", "tests.*")),
python_requires='!=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4*, <4',
classifiers=[
'Environment :: Web Environment',
'Intended Audience :: Developers',
'Operating System :: OS Independent',
'Framework :: Django',
'Framework :: Django :: 2.0',
'Framework :: Django :: 2.1',
'Framework :: Django :: 2.2',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
],
include_package_data=True,
zip_safe=False,
)
setup()
42 changes: 36 additions & 6 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,7 +1,34 @@
[tox]
skipsdist=True
envlist =
py37-dj{20,21,22,30,31}
envlist =
py{36,37,38,39}-dj22
py{36,37,38,39,310}-dj32
py{38,39,310}-dj40
py{38,39,310,311}-dj41
py{38,39,310,311,312}-dj42
py{310,311,312}-dj{50,51}
py{310,311,312,313}-dj52

[gh-actions]
python =
3.7: py37
3.8: py38
3.9: py39
3.10: py310
3.11: py311
3.12: py312
3.13: py313

[gh-actions:env]
DJANGO =
2.2: dj22
3.2: dj32
4.0: dj40
4.1: dj41
4.2: dj42
5.0: dj50
5.1: dj51
5.2: dj52

[testenv]
usedevelop = True
Expand All @@ -11,11 +38,14 @@ deps =
pytest
pytest-cov
pytest-django
dj20: Django>=2.0,<2.1
dj21: Django>=2.1,<2.2
dj22: Django>=2.2,<3.0
dj30: Django>=3.0,<3.1
dj31: Django>=3.1,<3.2
dj32: Django>=3.2,<4.0
dj40: Django>=4.0,<4.1
dj41: Django>=4.1,<4.2
dj42: Django>=4.2,<4.3
dj50: Django>=5.0,<5.1
dj51: Django>=5.1a1,<5.2
dj52: Django>=5.2,<5.3

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