Skip to content

Commit c447dfe

Browse files
authored
Provisionally enable 3.12 (#424)
* Provisionally enable 3.12 * Maybe fix? * Remove 3.7 * Update history
1 parent 7305bb7 commit c447dfe

File tree

17 files changed

+463
-631
lines changed

17 files changed

+463
-631
lines changed

.github/workflows/main.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515

1616
strategy:
1717
matrix:
18-
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "pypy-3.8"]
18+
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "pypy-3.8"]
1919
fail-fast: false
2020

2121
steps:
@@ -24,6 +24,7 @@ jobs:
2424
- uses: "actions/setup-python@v4"
2525
with:
2626
python-version: "${{ matrix.python-version }}"
27+
allow-prereleases: true
2728

2829
- name: "Run Tox"
2930
run: |

HISTORY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
- **Potentially breaking**: {py:func}`cattrs.gen.make_dict_structure_fn` and {py:func}`cattrs.gen.typeddicts.make_dict_structure_fn` will use the values for the `detailed_validation` and `forbid_extra_keys` parameters from the given converter by default now.
99
If you're using these functions directly, the old behavior can be restored by passing in the desired values directly.
1010
([#410](https://github.com/python-attrs/cattrs/issues/410) [#411](https://github.com/python-attrs/cattrs/pull/411))
11+
- Python 3.12 is now supported. Python 3.7 is no longer supported; use older releases there.
12+
([#424](https://github.com/python-attrs/cattrs/pull/424))
1113
- Introduce the `use_class_methods` strategy. Learn more [here](https://catt.rs/en/latest/strategies.html#using-class-specific-structure-and-unstructure-methods).
1214
([#405](https://github.com/python-attrs/cattrs/pull/405))
1315
- Implement the `union passthrough` strategy, enabling much richer union handling for preconfigured converters. [Learn more here](https://catt.rs/en/stable/strategies.html#union-passthrough).

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ destructure them.
108108

109109
- Free software: MIT license
110110
- Documentation: https://catt.rs
111-
- Python versions supported: 3.7 and up. (Older Python versions, like 2.7, 3.5 and 3.6 are supported by older versions; see the changelog.)
111+
- Python versions supported: 3.8 and up. (Older Python versions are supported by older versions; see the changelog.)
112112

113113
## Features
114114

docs/structuring.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,6 @@ Generic TypedDicts work on Python 3.11 and later, since that is the first Python
260260

261261
[`typing.Required` and `typing.NotRequired`](https://peps.python.org/pep-0655/) are supported.
262262

263-
On Python 3.7, using `typing_extensions.TypedDict` is required since `typing.TypedDict` doesn't exist there.
264263
On Python 3.8, using `typing_extensions.TypedDict` is recommended since `typing.TypedDict` doesn't support all necessary features, so certain combinations of subclassing, totality and `typing.Required` won't work.
265264

266265
[Similar to _attrs_ classes](customizing.md#using-cattrsgen-generators), structuring can be customized using {meth}`cattrs.gen.typeddicts.make_dict_structure_fn`.

docs/unstructuring.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ False
5252

5353
Generic TypedDicts work on Python 3.11 and later, since that is the first Python version that supports them in general.
5454

55-
On Python 3.7, using `typing_extensions.TypedDict` is required since `typing.TypedDict` doesn't exist there.
5655
On Python 3.8, using `typing_extensions.TypedDict` is recommended since `typing.TypedDict` doesn't support all necessary features, so certain combinations of subclassing, totality and `typing.Required` won't work.
5756

5857
[Similar to _attrs_ classes](customizing.md#using-cattrsgen-generators), unstructuring can be customized using {meth}`cattrs.gen.typeddicts.make_dict_unstructure_fn`.

pdm.lock

Lines changed: 424 additions & 573 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ test = [
1919
"hypothesis>=6.79.4",
2020
"pytest>=7.4.0",
2121
"pytest-benchmark>=4.0.0",
22-
"immutables>=0.19",
22+
"immutables>=0.20",
2323
"typing-extensions>=4.7.1",
2424
"coverage>=7.2.7",
2525
]
@@ -53,10 +53,23 @@ dependencies = [
5353
"typing-extensions>=4.1.0, !=4.6.3; python_version < '3.11'",
5454
"exceptiongroup>=1.1.1; python_version < '3.11'",
5555
]
56-
requires-python = ">=3.7"
56+
requires-python = ">=3.8"
5757
readme = "README.md"
5858
license = {text = "MIT"}
5959
keywords = ["attrs", "serialization", "dataclasses"]
60+
classifiers = [
61+
"Development Status :: 5 - Production/Stable",
62+
"Intended Audience :: Developers",
63+
"License :: OSI Approved :: MIT License",
64+
"Programming Language :: Python :: 3.8",
65+
"Programming Language :: Python :: 3.9",
66+
"Programming Language :: Python :: 3.10",
67+
"Programming Language :: Python :: 3.11",
68+
"Programming Language :: Python :: 3.12",
69+
"Programming Language :: Python :: Implementation :: CPython",
70+
"Programming Language :: Python :: Implementation :: PyPy",
71+
"Typing :: Typed",
72+
]
6073

6174
[project.urls]
6275
Homepage = "https://catt.rs"

src/cattrs/_compat.py

Lines changed: 10 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@
66
from dataclasses import fields as dataclass_fields
77
from dataclasses import is_dataclass
88
from typing import AbstractSet as TypingAbstractSet
9-
from typing import Any, Deque, Dict, FrozenSet, List
9+
from typing import Any, Deque, Dict, Final, FrozenSet, List
1010
from typing import Mapping as TypingMapping
1111
from typing import MutableMapping as TypingMutableMapping
1212
from typing import MutableSequence as TypingMutableSequence
1313
from typing import MutableSet as TypingMutableSet
14-
from typing import NewType, Optional
14+
from typing import NewType, Optional, Protocol
1515
from typing import Sequence as TypingSequence
1616
from typing import Set as TypingSet
17-
from typing import Tuple, get_type_hints
17+
from typing import Tuple, get_args, get_origin, get_type_hints
1818

19-
from attr import NOTHING, Attribute, Factory
20-
from attr import fields as attrs_fields
21-
from attr import resolve_types
19+
from attrs import NOTHING, Attribute, Factory
20+
from attrs import fields as attrs_fields
21+
from attrs import resolve_types
2222

2323
__all__ = ["ExceptionGroup", "ExtensionsTypedDict", "TypedDict", "is_typeddict"]
2424

@@ -27,18 +27,6 @@
2727
except ImportError:
2828
ExtensionsTypedDict = None
2929

30-
if sys.version_info >= (3, 8):
31-
from typing import Final, Protocol, get_args, get_origin
32-
33-
else:
34-
35-
def get_args(cl):
36-
return cl.__args__
37-
38-
def get_origin(cl):
39-
return getattr(cl, "__origin__", None)
40-
41-
from typing_extensions import Final, Protocol
4230

4331
if sys.version_info >= (3, 11):
4432
from builtins import ExceptionGroup
@@ -355,16 +343,11 @@ def get_full_type_hints(obj, globalns=None, localns=None):
355343
TupleSubscriptable = Tuple
356344

357345
from collections import Counter as ColCounter
358-
from typing import Counter, Union, _GenericAlias
346+
from typing import Counter, TypedDict, Union, _GenericAlias
359347

360348
from typing_extensions import Annotated, NotRequired, Required
361349
from typing_extensions import get_origin as te_get_origin
362350

363-
if sys.version_info >= (3, 8):
364-
from typing import TypedDict
365-
else:
366-
TypedDict = ExtensionsTypedDict
367-
368351
def is_annotated(type) -> bool:
369352
return te_get_origin(type) is Annotated
370353

@@ -440,16 +423,10 @@ def is_counter(type):
440423
or getattr(type, "__origin__", None) is ColCounter
441424
)
442425

443-
if sys.version_info >= (3, 8):
444-
from typing import Literal
445-
446-
def is_literal(type) -> bool:
447-
return type.__class__ is _GenericAlias and type.__origin__ is Literal
426+
from typing import Literal
448427

449-
else:
450-
# No literals in 3.7.
451-
def is_literal(_) -> bool:
452-
return False
428+
def is_literal(type) -> bool:
429+
return type.__class__ is _GenericAlias and type.__origin__ is Literal
453430

454431
def is_generic(obj):
455432
return isinstance(obj, _GenericAlias)

src/cattrs/converters.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -819,7 +819,7 @@ def __init__(
819819
if OriginAbstractSet in co:
820820
if OriginMutableSet not in co:
821821
co[OriginMutableSet] = co[OriginAbstractSet]
822-
co[AbcMutableSet] = co[OriginAbstractSet] # For 3.7/3.8 compatibility.
822+
co[AbcMutableSet] = co[OriginAbstractSet] # For 3.8 compatibility.
823823
if FrozenSetSubscriptable not in co:
824824
co[FrozenSetSubscriptable] = co[OriginAbstractSet]
825825

@@ -828,7 +828,7 @@ def __init__(
828828
co[set] = co[OriginMutableSet]
829829

830830
if FrozenSetSubscriptable in co:
831-
co[frozenset] = co[FrozenSetSubscriptable] # For 3.7/3.8 compatibility.
831+
co[frozenset] = co[FrozenSetSubscriptable] # For 3.8 compatibility.
832832

833833
# abc.Sequence overrides, if defined, can apply to MutableSequences, lists and
834834
# tuples

src/cattrs/v.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def format_exception(exc: BaseException, type: Union[type, None]) -> str:
4141
res = f"invalid value for type, expected {tn}"
4242
elif isinstance(exc, ForbiddenExtraKeysError):
4343
res = f"extra fields found ({', '.join(exc.extra_fields)})"
44-
elif isinstance(exc, AttributeError) and exc.args[0].endswith( # noqa: SIM114
44+
elif isinstance(exc, AttributeError) and exc.args[0].endswith(
4545
"object has no attribute 'items'"
4646
):
4747
# This was supposed to be a mapping (and have .items()) but it something else.

0 commit comments

Comments
 (0)