From de937ceafd2259598f468d4b0a97c09bd6b9a208 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Mon, 16 Oct 2023 14:05:02 +0100 Subject: [PATCH 1/2] Support Django 5.0 and Python 3.12 --- .github/workflows/tests.yml | 20 +++---- CHANGES.md | 7 ++- setup.py | 4 ++ tox.ini | 3 +- typedmodels/__init__.py | 6 -- typedmodels/models.py | 107 ++++++++++++++++++++++++------------ 6 files changed, 95 insertions(+), 52 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2260ccb..6c3e67e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,27 +8,27 @@ jobs: python-version: - "3.8" - "3.9" - django-version: - - "3.2" - - "4.0" - - "4.1" - - "4.2" + - "3.10" + - "3.11" + - "3.12" 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 (django ${{ matrix.django-version }}) + + - name: Install dependencies run: | - python -m pip install --upgrade pip - pip install flake8 pyyaml coveralls pytest-django django==${{ matrix.django-version }}.* - pip install -e . + pip install flake8 + - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + - name: Test with pytest run: | - coverage run $(which pytest) --ds=test_settings typedmodels/tests.py + tox run -f py$(echo ${{ matrix.python-version }} | tr -d .) diff --git a/CHANGES.md b/CHANGES.md index a4759a5..c07c963 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,7 +2,12 @@ Backward-incompatible changes for released versions are listed here (for 0.5 onwards.) -* Added support for Django 4.2. +* Added support for Django 4.2 and 5.0. + +* Added support for Python 3.12. + +* Dropped the `VERSION` and `__version__` attributes. To check the version of the package, use `importlib.metadata.version("django-typed-models")` ([docs](https://docs.python.org/3/library/importlib.metadata.html#distribution-versions) / + [backport](https://pypi.org/project/importlib-metadata/)). ## 0.13 diff --git a/setup.py b/setup.py index df0a6e3..4fb1823 100755 --- a/setup.py +++ b/setup.py @@ -29,6 +29,7 @@ def read_relative_file(filename): "Framework :: Django :: 4.0", "Framework :: Django :: 4.1", "Framework :: Django :: 4.2", + "Framework :: Django :: 5.0", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", @@ -39,6 +40,9 @@ def read_relative_file(filename): "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", "Topic :: Utilities", ], ) diff --git a/tox.ini b/tox.ini index 8310167..2edb6bb 100644 --- a/tox.ini +++ b/tox.ini @@ -4,11 +4,11 @@ envlist = {py36,py39}-{dj32} {py38,py310}-{dj40} {py38,py310}-{dj41} {py38,py310}-{dj42} + {py310,py311,py312}-{dj50} [testenv] changedir = {toxinidir} commands = - pip --disable-pip-version-check install -e . coverage run {envbindir}/pytest --ds=test_settings typedmodels/tests.py {posargs} coverage report --omit=typedmodels/test* @@ -25,3 +25,4 @@ deps = dj40: Django~=4.0.0 dj41: Django~=4.1.0 dj42: Django~=4.2.0 + dj50: Django~=5.0a1 diff --git a/typedmodels/__init__.py b/typedmodels/__init__.py index a5c1cd1..e69de29 100644 --- a/typedmodels/__init__.py +++ b/typedmodels/__init__.py @@ -1,6 +0,0 @@ - - -pkg_resources = __import__('pkg_resources') -distribution = pkg_resources.get_distribution('django-typed-models') - -VERSION = __version__ = distribution.version diff --git a/typedmodels/models.py b/typedmodels/models.py index 2d0830f..5198e7c 100644 --- a/typedmodels/models.py +++ b/typedmodels/models.py @@ -1,7 +1,7 @@ -import inspect from functools import partial import types +import django from django.core.exceptions import FieldDoesNotExist, FieldError from django.core.serializers.python import Serializer as _PythonSerializer from django.core.serializers.xml_serializer import Serializer as _XmlSerializer @@ -245,40 +245,79 @@ def _model_has_field(cls, base_class, field_name): def _patch_fields_cache(cls, base_class): orig_get_fields = cls._meta._get_fields - def _get_fields( - self, - forward=True, - reverse=True, - include_parents=True, - include_hidden=False, - seen_models=None, - ): - cache_key = ( - forward, - reverse, - include_parents, - include_hidden, - seen_models is None, - ) + if django.VERSION >= (5, 0): + + def _get_fields( + self, + forward=True, + reverse=True, + include_parents=True, + include_hidden=False, + topmost_call=True, + ): + cache_key = ( + forward, + reverse, + include_parents, + include_hidden, + topmost_call, + ) - was_cached = cache_key in self._get_fields_cache - fields = orig_get_fields( - forward=forward, - reverse=reverse, - include_parents=include_parents, - include_hidden=include_hidden, - seen_models=seen_models, - ) - # If it was cached already, it's because we've already filtered this, skip it - if not was_cached: - fields = [ - f - for f in fields - if TypedModelMetaclass._model_has_field(cls, base_class, f.name) - ] - fields = make_immutable_fields_list("get_fields()", fields) - self._get_fields_cache[cache_key] = fields - return fields + was_cached = cache_key in self._get_fields_cache + fields = orig_get_fields( + forward=forward, + reverse=reverse, + include_parents=include_parents, + include_hidden=include_hidden, + topmost_call=topmost_call, + ) + # If it was cached already, it's because we've already filtered this, skip it + if not was_cached: + fields = [ + f + for f in fields + if TypedModelMetaclass._model_has_field(cls, base_class, f.name) + ] + fields = make_immutable_fields_list("get_fields()", fields) + self._get_fields_cache[cache_key] = fields + return fields + + else: + + def _get_fields( + self, + forward=True, + reverse=True, + include_parents=True, + include_hidden=False, + seen_models=None, + ): + cache_key = ( + forward, + reverse, + include_parents, + include_hidden, + seen_models is None, + ) + + was_cached = cache_key in self._get_fields_cache + fields = orig_get_fields( + forward=forward, + reverse=reverse, + include_parents=include_parents, + include_hidden=include_hidden, + seen_models=seen_models, + ) + # If it was cached already, it's because we've already filtered this, skip it + if not was_cached: + fields = [ + f + for f in fields + if TypedModelMetaclass._model_has_field(cls, base_class, f.name) + ] + fields = make_immutable_fields_list("get_fields()", fields) + self._get_fields_cache[cache_key] = fields + return fields cls._meta._get_fields = partial(_get_fields, cls._meta) From 7394d58dd74af299b7225d4edc1c5fe15a6dd194 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Tue, 24 Oct 2023 15:28:02 +0100 Subject: [PATCH 2/2] install tox --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6c3e67e..5a4245c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -22,7 +22,7 @@ jobs: - name: Install dependencies run: | - pip install flake8 + pip install flake8 tox - name: Lint with flake8 run: |