Skip to content

Commit

Permalink
feat: drop Python 3.7 support (#601)
Browse files Browse the repository at this point in the history
* feat: drop Python 3.7 support

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix: fix formatting

* fix: fix formatting

* fix: fix TypedDict test for 3.8

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix: fix lint

* fix: fix TypedDict test for 3.8

* fix: fix pre-commit local config

* fix: fix TypedDict test for 3.8

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
wyfo and pre-commit-ci[bot] authored Oct 19, 2023
1 parent c58e402 commit 8ff1d36
Show file tree
Hide file tree
Showing 41 changed files with 154 additions and 413 deletions.
14 changes: 7 additions & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
default_language_version:
python: python3.11
python: python3.12
repos:
- repo: local
hooks:
- id: update_readme
name: Update Readme
entry: python scripts/generate_readme.py
language: python
language: system
- id: sort_all
name: Sort __all__
entry: python scripts/sort_all.py
language: python
language: system
types: [python]
- repo: https://github.com/hadialqattan/pycln
rev: v2.1.2
rev: v2.3.0
hooks:
- id: pycln
- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: isort
- repo: https://github.com/psf/black
rev: 22.12.0
rev: 23.10.0
hooks:
- id: black
args: [-C]
- repo: https://github.com/PyCQA/flake8
rev: 6.0.0
rev: 6.1.0
hooks:
- id: flake8
exclude: ^examples/.*\.py$
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.991
rev: v1.6.1
hooks:
- id: mypy
args: [--ignore-missing-imports, --scripts-are-modules, --warn-unused-ignores, --warn-redundant-cast, --check-untyped-defs]
Expand Down
4 changes: 1 addition & 3 deletions apischema/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
from functools import lru_cache
from typing import Callable, Iterator, MutableMapping, TypeVar, cast

from apischema.utils import type_dict_wrapper

_cached: list = []

Func = TypeVar("Func", bound=Callable)
Expand Down Expand Up @@ -35,7 +33,7 @@ def set_size(size: int):

class CacheAwareDict(MutableMapping[K, V]):
def __init__(self, wrapped: MutableMapping[K, V]):
self.wrapped = type_dict_wrapper(wrapped)
self.wrapped = wrapped

def __getitem__(self, key: K) -> V:
return self.wrapped[key]
Expand Down
11 changes: 1 addition & 10 deletions apischema/conversions/converters.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import sys
from collections import defaultdict
from enum import Enum
from functools import partial, wraps
Expand Down Expand Up @@ -46,15 +45,7 @@
)
Serializer = TypeVar("Serializer", bound=Union[Callable, Conversion, property, type])

default_deserialization: Callable[[type], Optional[AnyConversion]]
# defaultdict.get is not hashable in 3.7
if sys.version_info < (3, 8):

def default_deserialization(tp):
return _deserializers.get(tp)

else:
default_deserialization = _deserializers.get
default_deserialization: Callable[[type], Optional[AnyConversion]] = _deserializers.get


def default_serialization(tp: Type) -> Optional[AnyConversion]:
Expand Down
3 changes: 1 addition & 2 deletions apischema/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def __set_name__(self, owner, name):
def dependent_required(
fields: Mapping[Any, Collection[Any]],
*groups: Collection[Any],
owner: Optional[type] = None
owner: Optional[type] = None,
):
...

Expand All @@ -65,7 +65,6 @@ def dependent_required(*groups: Collection[Any], owner: Optional[type] = None):
if owner is None:
return DependentRequiredDescriptor(fields, groups)
else:

dep_req = _dependent_requireds[owner]
for field, required in fields.items():
dep_req.append((field, required))
Expand Down
19 changes: 9 additions & 10 deletions apischema/deserialization/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def check_only(method: DeserializationMethod) -> bool:
def is_raw_dataclass(cls: type) -> bool:
return (
dataclasses.is_dataclass(cls)
and type(cls) == type # no metaclass
and type(cls) is type # no metaclass
and "__slots__" not in cls.__dict__
and not hasattr(cls, "__post_init__")
and all(f.init for f in dataclasses.fields(cls))
Expand All @@ -167,7 +167,7 @@ def is_raw_dataclass(cls: type) -> bool:
or getattr(cls, dataclasses._PARAMS).frozen # type: ignore
)
and (
list(inspect.signature(cls.__init__, follow_wrapped=False).parameters) # type: ignore
list(inspect.signature(cls.__init__, follow_wrapped=False).parameters)
== ["__dataclass_self__" if "self" in dataclasses.fields(cls) else "self"]
+ [f.name for f in dataclasses.fields(cls)]
)
Expand Down Expand Up @@ -603,8 +603,7 @@ def len_error(constraints: Constraints) -> Union[str, Callable[[Any], str]]:
return self._factory(factory, list)

def union(self, types: Sequence[AnyType]) -> DeserializationMethodFactory:
discriminator = get_inherited_discriminator(types)
if discriminator is not None:
if discriminator := get_inherited_discriminator(types):
return self.discriminate(discriminator, types)
alt_factories = self._union_results(types)
if len(alt_factories) == 1:
Expand Down Expand Up @@ -743,7 +742,7 @@ def deserialization_method(
no_copy: Optional[bool] = None,
pass_through: Optional[CollectionOrPredicate[type]] = None,
schema: Optional[Schema] = None,
validators: Collection[Callable] = ()
validators: Collection[Callable] = (),
) -> Callable[[Any], T]:
...

Expand All @@ -761,7 +760,7 @@ def deserialization_method(
no_copy: Optional[bool] = None,
pass_through: Optional[CollectionOrPredicate[type]] = None,
schema: Optional[Schema] = None,
validators: Collection[Callable] = ()
validators: Collection[Callable] = (),
) -> Callable[[Any], Any]:
...

Expand All @@ -778,7 +777,7 @@ def deserialization_method(
no_copy: Optional[bool] = None,
pass_through: Optional[CollectionOrPredicate[type]] = None,
schema: Optional[Schema] = None,
validators: Collection[Callable] = ()
validators: Collection[Callable] = (),
) -> Callable[[Any], Any]:
from apischema import settings

Expand Down Expand Up @@ -821,7 +820,7 @@ def deserialize(
no_copy: Optional[bool] = None,
pass_through: Optional[CollectionOrPredicate[type]] = None,
schema: Optional[Schema] = None,
validators: Collection[Callable] = ()
validators: Collection[Callable] = (),
) -> T:
...

Expand All @@ -840,7 +839,7 @@ def deserialize(
no_copy: Optional[bool] = None,
pass_through: Optional[CollectionOrPredicate[type]] = None,
schema: Optional[Schema] = None,
validators: Collection[Callable] = ()
validators: Collection[Callable] = (),
) -> Any:
...

Expand All @@ -858,7 +857,7 @@ def deserialize(
no_copy: Optional[bool] = None,
pass_through: Optional[CollectionOrPredicate[type]] = None,
schema: Optional[Schema] = None,
validators: Collection[Callable] = ()
validators: Collection[Callable] = (),
) -> Any:
return deserialization_method(
type,
Expand Down
5 changes: 0 additions & 5 deletions apischema/discriminators.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,6 @@
from apischema.typing import get_args, is_literal, is_typed_dict
from apischema.utils import get_origin_or_type2, identity, no_annotated

try:
from apischema.typing import Literal
except ImportError:
Literal = ... # type: ignore

Cls = TypeVar("Cls", bound=type)


Expand Down
4 changes: 1 addition & 3 deletions apischema/graphql/relay/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from apischema.type_names import get_type_name, type_name
from apischema.types import NoneType
from apischema.typing import generic_mro, get_args, get_origin
from apischema.utils import get_args2, is_union_of, wrap_generic_init_subclass
from apischema.utils import get_args2, is_union_of

Cursor_ = TypeVar("Cursor_")
Node_ = TypeVar("Node_")
Expand Down Expand Up @@ -34,7 +34,6 @@ class Edge(Generic[Node_, Cursor_]):
node: Node_
cursor: Cursor_

@wrap_generic_init_subclass
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
type_name(graphql=edge_name)(cls)
Expand Down Expand Up @@ -79,7 +78,6 @@ class Connection(Generic[Node_, Cursor_, Edge_]):
edges: Optional[Sequence[Optional[Edge_]]]
page_info: PageInfo[Cursor_]

@wrap_generic_init_subclass
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
type_name(graphql=connection_name)(cls)
3 changes: 1 addition & 2 deletions apischema/graphql/relay/global_identification.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from apischema.ordering import order
from apischema.type_names import get_type_name
from apischema.typing import generic_mro, get_args, get_origin
from apischema.utils import PREFIX, has_type_vars, wrap_generic_init_subclass
from apischema.utils import PREFIX, has_type_vars

ID_TYPE_ATTR = f"{PREFIX}id_type"

Expand Down Expand Up @@ -113,7 +113,6 @@ def _node_key(cls) -> str:
raise TypeError(f"Node {cls} has no type_name registered")
return node_name

@wrap_generic_init_subclass
def __init_subclass__(cls, not_a_node: bool = False, **kwargs):
super().__init_subclass__(**kwargs)
if not not_a_node:
Expand Down
3 changes: 1 addition & 2 deletions apischema/graphql/relay/mutations.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from apischema.type_names import type_name
from apischema.types import AnyType, Undefined
from apischema.typing import get_type_hints
from apischema.utils import is_async, is_union_of, wrap_generic_init_subclass
from apischema.utils import is_async, is_union_of

ClientMutationId = NewType("ClientMutationId", str)
type_name(None)(ClientMutationId)
Expand All @@ -41,7 +41,6 @@ class Mutation:
# Mutate is not defined to prevent Mypy warning about signature of superclass
mutate: ClassVar[Callable]

@wrap_generic_init_subclass
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
if not hasattr(cls, "mutate"):
Expand Down
21 changes: 13 additions & 8 deletions apischema/graphql/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from enum import Enum
from functools import wraps
from inspect import Parameter, iscoroutinefunction
from itertools import chain
from typing import (
Any,
AsyncIterable,
Expand All @@ -15,6 +14,7 @@
Generic,
Iterable,
List,
Literal,
Mapping,
NewType,
Optional,
Expand Down Expand Up @@ -61,7 +61,7 @@
from apischema.serialization import SerializationMethod, serialize
from apischema.serialization.serialized_methods import ErrorHandler
from apischema.type_names import TypeName, TypeNameFactory, get_type_name
from apischema.types import AnyType, NoneType, OrderedDict, Undefined, UndefinedType
from apischema.types import AnyType, NoneType, Undefined, UndefinedType
from apischema.typing import get_args, get_origin, is_annotated
from apischema.utils import (
Lazy,
Expand Down Expand Up @@ -335,8 +335,6 @@ def factory(

@cache_type
def literal(self, values: Sequence[Any]) -> TypeFactory[GraphQLTp]:
from apischema.typing import Literal

if not all(isinstance(v, str) for v in values):
raise TypeError("apischema GraphQL only support Literal of strings")

Expand Down Expand Up @@ -476,7 +474,7 @@ def merge_fields(cls: type, fields: Sequence[BaseField]) -> Dict[str, FieldType]
f"Flattened field {cls.__name__}.{err.field.name}"
f" must have an object type"
)
return OrderedDict(chain.from_iterable(map(lambda f: f.items(), sorted_fields)))
return {k: v for f in sorted_fields for k, v in f.items()}


class InputSchemaBuilder(
Expand Down Expand Up @@ -760,7 +758,7 @@ def object(
interfaces = list(map(self.visit, get_interfaces(cls)))
if interfaces or flattened_factories:

def interface_thunk() -> Collection[graphql.GraphQLInterfaceType]:
def interface_thunk() -> Collection[graphql.GraphQLInterfaceType]: # noqa
all_interfaces = {
cast(graphql.GraphQLInterfaceType, i.raw_type) for i in interfaces
}
Expand Down Expand Up @@ -1020,13 +1018,20 @@ def root_type(
if not fields:
return None
tp, type_name = type(name, (), {}), TypeName(graphql=name)
return output_builder.object(tp, (), fields).merge(type_name, None).raw_type
root = output_builder.object(tp, (), fields).merge(type_name, None).raw_type
assert isinstance(root, graphql.GraphQLObjectType)
return root

def check_named(tp: graphql.GraphQLType) -> graphql.GraphQLNamedType:
if not isinstance(tp, graphql.GraphQLNamedType):
raise TypeError(f"schema type {tp} is not named")
return tp

return graphql.GraphQLSchema(
query=root_type("Query", query_fields),
mutation=root_type("Mutation", mutation_fields),
subscription=root_type("Subscription", subscription_fields),
types=[output_builder.visit(cls).raw_type for cls in types],
types=[check_named(output_builder.visit(cls).raw_type) for cls in types],
directives=directives,
description=description,
extensions=extensions,
Expand Down
5 changes: 2 additions & 3 deletions apischema/json_schema/refs.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def annotated(self, tp: AnyType, annotations: Sequence[Any]):
if not isinstance(ref, str):
continue
ref_annotations = annotations[: len(annotations) - i]
annotated = Annotated[(tp, *ref_annotations)] # type: ignore
annotated = Annotated[(tp, *ref_annotations)]
if self._incr_ref(ref, annotated):
return
if (
Expand Down Expand Up @@ -106,8 +106,7 @@ def mapping(self, cls: Type[Mapping], key_type: AnyType, value_type: AnyType):
self.visit(value_type)

def object(self, tp: AnyType, fields: Sequence[ObjectField]):
parent = get_discriminated_parent(get_origin_or_type(tp))
if parent is not None:
if parent := get_discriminated_parent(get_origin_or_type(tp)):
self._incr_ref(get_type_name(parent).json_schema, parent)
for field in fields:
self.visit_with_conv(field.type, self._field_conversion(field))
Expand Down
14 changes: 6 additions & 8 deletions apischema/json_schema/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
get_serialized_methods,
)
from apischema.type_names import TypeNameFactory, get_type_name
from apischema.types import AnyType, OrderedDict, UndefinedType
from apischema.types import AnyType, UndefinedType
from apischema.typing import get_args, get_origin, is_typed_dict, is_union
from apischema.utils import (
context_setter,
Expand Down Expand Up @@ -318,8 +318,7 @@ def object(self, tp: AnyType, fields: Sequence[ObjectField]) -> JsonSchema:
alias_by_names = {f.name: f.alias for f in fields}.__getitem__
dependent_required = get_dependent_required(cls)
result = []
discriminator_parent = get_discriminated_parent(cls)
if discriminator_parent is not None:
if discriminator_parent := get_discriminated_parent(cls):
discriminator_ref = self.ref_schema(
get_type_name(discriminator_parent).json_schema
)
Expand All @@ -333,13 +332,12 @@ def object(self, tp: AnyType, fields: Sequence[ObjectField]) -> JsonSchema:
required=[p.alias for p in properties if p.required],
additionalProperties=additional_properties,
patternProperties=pattern_properties,
dependentRequired=OrderedDict(
(
alias_by_names(f),
sorted(map(alias_by_names, dependent_required[f])),
dependentRequired={
alias_by_names(f): sorted(
map(alias_by_names, dependent_required[f])
)
for f in sorted(dependent_required, key=alias_by_names)
),
},
)
)
if flattened_schemas:
Expand Down
Loading

0 comments on commit 8ff1d36

Please sign in to comment.