Skip to content
This repository has been archived by the owner on Sep 9, 2024. It is now read-only.

Commit

Permalink
Fixes for py3.10+
Browse files Browse the repository at this point in the history
  • Loading branch information
seandstewart committed Feb 27, 2024
1 parent 1c94696 commit ce83e1c
Show file tree
Hide file tree
Showing 10 changed files with 411 additions and 280 deletions.
14 changes: 10 additions & 4 deletions benchmark/models/pyd.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,29 @@
from typing import Any, List, Optional

import orjson
from pydantic import BaseConfig, BaseModel, ConstrainedStr, PositiveInt, ValidationError
from pydantic import (
BaseConfig,
BaseModel,
PositiveInt,
StringConstraints,
ValidationError,
)


def orjson_dumps(v, *, default):
# orjson.dumps returns bytes, to match standard json.dumps we need to decode
return orjson.dumps(v, default=default).decode()


class DBString(ConstrainedStr):
class DBString(StringConstraints):
max_length = 255


class HTTPReferer(ConstrainedStr):
class HTTPReferer(StringConstraints):
max_length = 1023


class GReCaptchaResponse(ConstrainedStr):
class GReCaptchaResponse(StringConstraints):
min_length = 20
max_length = 1000

Expand Down
582 changes: 363 additions & 219 deletions poetry.lock

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,20 @@ future-typing = "^0.4.1"
astunparse = {version = "^1.6.3", python = "<3.9"}

[tool.poetry.group.test.dependencies]
pytest = "^7.2"
pytest = "^8"
pytest-cov = "^4"
pandas = "^1.1.3"
sqlalchemy = "^1.3.13"
asyncpg = "^0.27.0"
pandas = "^2"
sqlalchemy = "^2"
asyncpg = "^0.29"
pytest-parametrize-suite = "^23.1.1"

[tool.poetry.group.benchmarks.dependencies]
pytest-benchmark = {version = "^4", extras = ["histogram"]}
marshmallow = "^3"
djangorestframework = "^3"
pydantic = {version = "^1", extras = ["email"]}
pydantic = {version = "^2", extras = ["email"]}
django = "^4"
apischema = "^0.17.1"
apischema = "^0.18"

[tool.poetry.group.lint.dependencies]
flake8 = "^7"
Expand All @@ -75,7 +75,7 @@ mkdocs-awesome-pages-plugin = "^2"
pymdown-extensions = "^10"

[tool.poetry.group.dev.dependencies]
pre-commit = "^2"
pre-commit = "^3"
sqlalchemy-stubs = "^0.4"
bumpver = "^2023"
fastjsonschema = "^2"
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ markupsafe==2.1.5 ; python_full_version >= "3.8.1" and python_version < "4.0"
mergedeep==1.3.4 ; python_full_version >= "3.8.1" and python_version < "4.0"
mkdocs-awesome-pages-plugin==2.9.2 ; python_full_version >= "3.8.1" and python_version < "4.0"
mkdocs-material-extensions==1.3.1 ; python_full_version >= "3.8.1" and python_version < "4.0"
mkdocs-material==9.5.10 ; python_full_version >= "3.8.1" and python_version < "4.0"
mkdocs-material==9.5.11 ; python_full_version >= "3.8.1" and python_version < "4.0"
mkdocs==1.5.3 ; python_full_version >= "3.8.1" and python_version < "4.0"
natsort==8.4.0 ; python_full_version >= "3.8.1" and python_version < "4.0"
packaging==23.2 ; python_full_version >= "3.8.1" and python_version < "4.0"
Expand Down
4 changes: 2 additions & 2 deletions src/typical/core/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ def __hash__(self):
def __repr__(self) -> str:
fs = []
for field in dataclasses.fields(self):
fs.append(f"{field.name}={getattr(self, field.name)!r}")
fs.append(f"{field.name}={reprlib.repr(getattr(self, field.name))}")
return f"{self.__class__.__name__}({', '.join(fs)})"

def asdict(self) -> SerdeConfigD:
Expand Down Expand Up @@ -386,7 +386,7 @@ class ForwardDelayedAnnotation:
def __repr__(self):
return (
f"{self.__class__.__name__}("
f"ref={self.ref},"
f"ref={reprlib.repr(self.ref)},"
f"module={self.module}!r, "
f"parameter={self.parameter}, "
f"is_optional={self.is_optional}, "
Expand Down
15 changes: 11 additions & 4 deletions src/typical/core/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,17 @@ def tojson(
__dumps=orjson.dumps,
**kwargs,
) -> bytes:
sort_keys = kwargs.pop("sort_keys", None)
option = kwargs.pop("option", None)
if indent:
option = kwargs.pop("option", None)
opt = orjson.OPT_INDENT_2 | orjson.OPT_APPEND_NEWLINE
kwargs["option"] = (opt | option) if option else opt
option = (opt | option) if option else opt
if sort_keys:
opt = orjson.OPT_SORT_KEYS
option = (opt | option) if option else opt
if option is not None:
kwargs["option"] = option

return __dumps(__prim(o), **kwargs)

tojson.__module__ = serializer.__module__
Expand All @@ -41,7 +48,7 @@ def tojson(
dumps, loads = orjson.dumps, orjson.loads


except (ImportError, ModuleNotFoundError):
except (ImportError, ModuleNotFoundError) as e:
orjson = None

try:
Expand Down Expand Up @@ -71,7 +78,7 @@ def tojson(

dumps, loads = ujson.dumps, ujson.loads

except (ImportError, ModuleNotFoundError): # pragma: nobranch
except (ImportError, ModuleNotFoundError) as e: # pragma: nobranch
import json

ujson = None
Expand Down
6 changes: 3 additions & 3 deletions src/typical/inspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,11 @@ def get_args(annotation: Any) -> Tuple[Any, ...]:
>>> from typing import Dict, TypeVar
>>> T = TypeVar("T")
>>> inspection.get_args(Dict)
()
()
>>> inspection.get_args(Dict[str, int])
(<class 'str'>, <class 'int'>)
(<class 'str'>, <class 'int'>)
>>> inspection.get_args(Dict[str, T])
(<class 'str'>,)
(<class 'str'>,)
"""
args = typing.get_args(annotation)
if not args:
Expand Down
2 changes: 1 addition & 1 deletion src/typical/magic/schema/jsonschema/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ class BaseSchemaField:
examples: list[Any] | None = None
readOnly: bool | None = None
writeOnly: bool | None = None
extensions: tuple[frozendict.FrozenDict[str, SchemaFieldT], ...] | None = None
extensions: tuple[frozendict.FrozenDict[str, BaseSchemaField], ...] | None = None

@reprlib.recursive_repr()
def __repr__(self) -> str: # pragma: nocover
Expand Down
3 changes: 3 additions & 0 deletions src/typical/serde/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ def __init__(
self._bind_closure()

def _bind_closure(self):
self.__call__ = None
self.__name__ = self.__class__.__name__
self.__qualname__ = self.__name__
self.__call__ = self._get_closure()
self.__name__ = self.__call__.__name__
self.__qualname__ = self.__call__.__qualname__
Expand Down
49 changes: 10 additions & 39 deletions tests/legacy/test_serdes.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@
import decimal
import enum
import ipaddress
import json
import re
import typing
from types import MappingProxyType
from typing import ClassVar, Dict, Generic, List, Mapping, Optional, TypeVar

import orjson
import pytest
import ujson

Expand Down Expand Up @@ -283,53 +281,26 @@ class Bar:
foos: List[Foo]


@pytest.mark.parametrize(
argnames=("obj", "expected"),
argvalues=[
(None, b"null"),
(MultiNum.INT, b"1"),
(MultiNum.STR, b'"str"'),
(
{objects.FooNum.bar: objects.Typic(var="foo")},
b'{"bar":{"var":"foo"}}',
),
([typic.URL("foo")], b'["foo"]'),
(Omit(), b'{"bar":"foo"}'),
(Bar(foos=[Foo("bar")]), b'{"foos":[{"bar":"bar","id":null}]}'),
],
)
def test_tojson(obj, expected):
assert typic.tojson(obj, option=orjson.OPT_SORT_KEYS) == expected


@typic.klass
class Foo:
bar: str
id: Optional[typic.ReadOnly[int]] = None


@typic.klass
class Bar:
foos: List[Foo]


@pytest.mark.parametrize(
argnames=("obj", "expected"),
argvalues=[
(None, "null"),
(MultiNum.INT, "1"),
(MultiNum.STR, '"str"'),
(
{objects.FooNum.bar: objects.Typic(var="foo")},
'{"bar":{"var":"foo"}}',
),
([typic.URL("foo")], '["foo"]'),
(Omit(), '{"bar":"foo"}'),
(Bar(foos=[Foo("bar")]), '{"foos":[{"bar":"bar","id":null}]}'),
],
)
def test_tojson_native(obj, expected):
native = (
json.dumps(typic.primitive(obj), sort_keys=True)
.replace("\n", "")
.replace(" ", "")
)
assert typic.tojson(obj, option=orjson.OPT_SORT_KEYS).decode() == native == expected
def test_tojson(obj, expected):
encoded = typic.tojson(obj, sort_keys=True).replace("\n", "").replace(" ", "")
if isinstance(encoded, bytes):
encoded = encoded.decode()
assert encoded == expected


badbar = Bar([])
Expand Down

0 comments on commit ce83e1c

Please sign in to comment.