diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index f95b58b..7cf1e87 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -8,10 +8,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Set up Python 3.12 + - name: Set up Python 3.13 uses: actions/setup-python@v4 with: - python-version: 3.12 + python-version: 3.13 - name: Install Dependencies run: | python -m pip install --upgrade pip diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 61305f8..1b34506 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["3.8.18", "3.9.25", "3.10.18", "3.11.14", "3.12.12", "3.13.11", "3.14.2"] steps: - uses: actions/checkout@v3 diff --git a/pyproject.toml b/pyproject.toml index 0a7cefd..90f7b74 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,2 +1,2 @@ line-length = 120 -target-version = ['py37', 'py38', 'py39', 'py310'] \ No newline at end of file +target-version = ['py37', 'py38', 'py39', 'py310', 'py311', 'py312', 'py313', 'py314'] \ No newline at end of file diff --git a/setup.py b/setup.py index b701756..18c1f0d 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ from setuptools import setup, find_packages -__VERSION__ = "1.2.0" +__VERSION__ = "1.2.2" base_dir = os.path.abspath(os.path.dirname(__file__)) @@ -49,19 +49,20 @@ "models", "data" ], - python_requires=">=3.6", + python_requires=">=3.7", classifiers=[ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", "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", + "Programming Language :: Python :: 3.14", ], test_suite="tests", project_urls={ diff --git a/src/python_easy_json/json_object.py b/src/python_easy_json/json_object.py index f520ff4..63e83a1 100644 --- a/src/python_easy_json/json_object.py +++ b/src/python_easy_json/json_object.py @@ -13,6 +13,10 @@ from dateutil import parser as dt_parser from json import JSONDecodeError +# 3.14 introduced lazy annotation loading, we must use the 'annotationlib' to inspect annotations. +if not (sys.version_info.major == 3 and sys.version_info.minor < 14): + from annotationlib import get_annotations, Format as annot_format + _enum_t = type(enum.Enum) # Support OrderedDict for Python versions 3.6 or below. @@ -45,8 +49,8 @@ def _get_annot_cls(annots: dict, key: str, ignore_builtins = False) -> typing.Li cls_ = cls_.__args__[0] # Check if typing annotation class is a Union type. # Try to find the right object class in the Union types list, ignore 'builtin' types. - if '__args__' in cls_.__dict__ and isinstance(cls_.__dict__['__args__'], (list, tuple)): - for cls_item in cls_.__dict__['__args__']: + if hasattr(cls_, '__args__') and isinstance(cls_.__args__, (list, tuple)): + for cls_item in cls_.__args__: # Try to find the right object class in the Union types list, ignore 'builtin' types. if issubclass(type(cls_item), object) and not isinstance(cls_item, typing.TypeVar): if ignore_builtins and cls_item.__module__ == 'builtins': @@ -75,10 +79,12 @@ def _collect_annotations(self, cls_: object): continue result = self._collect_annotations(base) annots.update(result) - - if hasattr(cls_, '__annotations__'): - annots.update(cls_.__annotations__) - + # 3.14 introduced breaking changes to annotation inspection due to lazy annotation loading. + if sys.version_info.major == 3 and sys.version_info.minor < 14: + if hasattr(cls_, '__annotations__'): + annots.update(cls_.__annotations__) + else: + annots.update(get_annotations(cls_, format=annot_format.VALUE)) return annots @staticmethod diff --git a/tests/test_json_with_enum.py b/tests/test_json_with_enum.py index 4b30943..22f2fb4 100644 --- a/tests/test_json_with_enum.py +++ b/tests/test_json_with_enum.py @@ -2,7 +2,7 @@ # This file is subject to the terms and conditions defined in the # file 'LICENSE', which is part of this source code package. # -from datetime import datetime +from datetime import datetime, timezone from enum import Enum, IntEnum from tests.base_test import BaseTestCase @@ -45,7 +45,7 @@ class TestJSONWithEnum(BaseTestCase): def test_object_with_enum_values(self): """ Test JSONObject class with IntEnum property. """ - ts = datetime.utcnow() + ts = datetime.now(timezone.utc) data = { 'timestamp': ts.isoformat(), @@ -69,7 +69,7 @@ def test_object_with_enum_values(self): def test_str_enum(self): """ Test an enum with string values """ - ts = datetime.utcnow() + ts = datetime.now(timezone.utc) data = { 'timestamp': ts.isoformat(),