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
4 changes: 2 additions & 2 deletions .github/workflows/coverage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
line-length = 120
target-version = ['py37', 'py38', 'py39', 'py310']
target-version = ['py37', 'py38', 'py39', 'py310', 'py311', 'py312', 'py313', 'py314']
7 changes: 4 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__))

Expand Down Expand Up @@ -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={
Expand Down
18 changes: 12 additions & 6 deletions src/python_easy_json/json_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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':
Expand Down Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions tests/test_json_with_enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(),
Expand All @@ -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(),
Expand Down