Skip to content

Commit

Permalink
More type aliases
Browse files Browse the repository at this point in the history
  • Loading branch information
nineteendo committed Sep 19, 2024
1 parent cfa26fc commit ea6ea0e
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 53 deletions.
8 changes: 5 additions & 3 deletions bench/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
if TYPE_CHECKING:
from collections.abc import Callable

_Func = Callable[[Any], Any]

seed(0)
_USER: dict[str, Any] = {
"userId": 3381293,
Expand Down Expand Up @@ -72,7 +74,7 @@
for _ in range(256)
},
}
_ENCODE_FUNCS: dict[str, Callable[[Any], Any]] = {
_ENCODE_FUNCS: dict[str, _Func] = {
"json": json.JSONEncoder().encode,
"jsonyx": jsonyx.Encoder().dumps,
"msgspec": msgspec.json.Encoder().encode,
Expand All @@ -84,7 +86,7 @@
_DECODE_CASES: dict[str, Any] = {
case: jsonyx.dumps(obj) for case, obj in _ENCODE_CASES.items()
}
_DECODE_FUNCS: dict[str, Callable[[Any], Any]] = {
_DECODE_FUNCS: dict[str, _Func] = {
"json": json.JSONDecoder().decode,
"jsonyx": jsonyx.Decoder().loads,
"msgspec": msgspec.json.Decoder().decode,
Expand All @@ -96,7 +98,7 @@


def _run_benchmark(
name: str, cases: dict[str, Any], funcs: dict[str, Callable[[Any], Any]],
name: str, cases: dict[str, Any], funcs: dict[str, _Func],
) -> None:
results: list[list[str]] = []
for case, obj in cases.items():
Expand Down
22 changes: 9 additions & 13 deletions src/jsonyx/_decoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class _SupportsRead(Protocol[_T_co]):
def read(self, length: int = ..., /) -> _T_co: # type: ignore
"""Read string."""

_MatchFunc = Callable[[str, int], Match[str] | None]
_Scanner = Callable[[str, str], Any]
_StrPath = PathLike[str] | str


Expand All @@ -49,25 +51,19 @@ def read(self, length: int = ..., /) -> _T_co: # type: ignore
"t": "\t",
}

_match_chunk: Callable[[str, int], Match[str] | None] = re.compile(
r'[^"\\\x00-\x1f]+', _FLAGS,
).match
_match_line_end: Callable[[str, int], Match[str] | None] = re.compile(
r"[^\n\r]+", _FLAGS,
).match
_match_number: Callable[[str, int], Match[str] | None] = re.compile(
_match_chunk: _MatchFunc = re.compile(r'[^"\\\x00-\x1f]+', _FLAGS).match
_match_line_end: _MatchFunc = re.compile(r"[^\n\r]+", _FLAGS).match
_match_number: _MatchFunc = re.compile(
r"""
(-?0|-?[1-9]\d*) # integer
(\.\d+)? # [frac]
([eE][-+]?\d+)? # [exp]
""", _FLAGS,
).match
_match_unquoted_key: Callable[[str, int], Match[str] | None] = re.compile(
_match_unquoted_key: _MatchFunc = re.compile(
r"(?:\w+|[^\x00-\x7f]+)+", _FLAGS,
).match
_match_whitespace: Callable[[str, int], Match[str] | None] = re.compile(
r"[ \t\n\r]+", _FLAGS,
).match
_match_whitespace: _MatchFunc = re.compile(r"[ \t\n\r]+", _FLAGS).match


def _get_err_context(doc: str, start: int, end: int) -> tuple[int, str, int]:
Expand Down Expand Up @@ -289,7 +285,7 @@ def make_scanner(
allow_trailing_comma: bool, # noqa: FBT001
allow_unquoted_keys: bool, # noqa: FBT001
use_decimal: bool, # noqa: FBT001
) -> Callable[[str, str], Any]:
) -> _Scanner:
"""Make JSON scanner."""
memo: dict[str, str] = {}
memoize: Callable[[str, str], str] = memo.setdefault
Expand Down Expand Up @@ -638,7 +634,7 @@ def __init__(
"""Create a new JSON decoder."""
allow_surrogates: bool = "surrogates" in allow
self._errors: str = "surrogatepass" if allow_surrogates else "strict"
self._scanner: Callable[[str, str], tuple[Any]] = make_scanner(
self._scanner: _Scanner = make_scanner(
"comments" in allow, "duplicate_keys" in allow,
"missing_commas" in allow, "nan_and_infinity" in allow,
allow_surrogates, "trailing_comma" in allow,
Expand Down
9 changes: 3 additions & 6 deletions src/jsonyx/_differ.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,16 @@
from decimal import Decimal
from itertools import starmap
from math import isnan
from re import DOTALL, MULTILINE, VERBOSE, Match, RegexFlag
from re import DOTALL, MULTILINE, VERBOSE, Match
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
from collections.abc import Callable, KeysView

_Operation = dict[str, Any]
_SubFunc = Callable[[Callable[[Match[str]], str], str], str]

_FLAGS: RegexFlag = VERBOSE | MULTILINE | DOTALL

_escape: Callable[[Callable[[Match[str]], str], str], str] = re.compile(
r"['~]", _FLAGS,
).sub
_escape: _SubFunc = re.compile(r"['~]", VERBOSE | MULTILINE | DOTALL).sub


def _replace(match: Match[str]) -> str:
Expand Down
32 changes: 16 additions & 16 deletions src/jsonyx/_encoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@
from collections.abc import Callable, Container, ItemsView
from os import PathLike

_T = TypeVar("_T")
_T_contra = TypeVar("_T_contra", contravariant=True)

# pylint: disable-next=R0903
class _SupportsWrite(Protocol[_T_contra]):
def write(self, s: _T_contra, /) -> object:
"""Write string."""

_EncodeFunc = Callable[[_T], str]
_StrPath = PathLike[str] | str
_SubFunc = Callable[[Callable[[Match[str]], str], str], str]
_WriteFunc = Callable[[str], object]


_ESCAPE_DCT: dict[str, str] = {chr(i): f"\\u{i:04x}" for i in range(0x20)} | {
Expand All @@ -41,19 +45,15 @@ def write(self, s: _T_contra, /) -> object:
}
_FLAGS: RegexFlag = VERBOSE | MULTILINE | DOTALL

_escape: Callable[[Callable[[Match[str]], str], str], str] = re.compile(
r'["\\\x00-\x1f]', _FLAGS,
).sub
_escape_ascii: Callable[[Callable[[Match[str]], str], str], str] = re.compile(
r'["\\]|[^\x20-\x7e]', _FLAGS,
).sub
_escape: _SubFunc = re.compile(r'["\\\x00-\x1f]', _FLAGS).sub
_escape_ascii: _SubFunc = re.compile(r'["\\]|[^\x20-\x7e]', _FLAGS).sub

try:
if not TYPE_CHECKING:
from _jsonyx import make_encoder
except ImportError:
def make_encoder(
encode_decimal: Callable[[Decimal], str],
encode_decimal: _EncodeFunc[Decimal],
indent: str | None,
mapping_types: type | tuple[type, ...],
seq_types: type | tuple[type, ...],
Expand All @@ -68,10 +68,10 @@ def make_encoder(
quoted_keys: bool, # noqa: FBT001
sort_keys: bool, # noqa: FBT001
trailing_comma: bool, # noqa: FBT001
) -> Callable[[object], str]:
) -> _EncodeFunc[object]:
"""Make JSON encoder."""
float_repr: Callable[[float], str] = float.__repr__
int_repr: Callable[[int], str] = int.__repr__
float_repr: _EncodeFunc[float] = float.__repr__
int_repr: _EncodeFunc[int] = int.__repr__
markers: dict[int, object] = {}

if not ensure_ascii:
Expand Down Expand Up @@ -119,7 +119,7 @@ def floatstr(num: float) -> str:
return "NaN"

def write_sequence(
seq: Any, write: Callable[[str], object], old_indent: str,
seq: Any, write: _WriteFunc, old_indent: str,
) -> None:
if not seq:
write("[]")
Expand Down Expand Up @@ -163,7 +163,7 @@ def write_sequence(
write("]")

def write_mapping(
mapping: Any, write: Callable[[str], object], old_indent: str,
mapping: Any, write: _WriteFunc, old_indent: str,
) -> None:
if not mapping:
write("{}")
Expand Down Expand Up @@ -220,7 +220,7 @@ def write_mapping(
write("}")

def write_value(
obj: object, write: Callable[[str], object], current_indent: str,
obj: object, write: _WriteFunc, current_indent: str,
) -> None:
if isinstance(obj, str):
write(encode_string(obj))
Expand Down Expand Up @@ -250,7 +250,7 @@ def write_value(

def encoder(obj: object) -> str:
io: StringIO = StringIO()
write: Callable[[str], object] = io.write
write: _WriteFunc = io.write
try:
write_value(obj, write, "\n")
except (ValueError, TypeError) as exc:
Expand Down Expand Up @@ -312,7 +312,7 @@ def __init__(
"""Create a new JSON encoder."""
allow_nan_and_infinity: bool = "nan_and_infinity" in allow
allow_surrogates: bool = "surrogates" in allow
decimal_str: Callable[[Decimal], str] = Decimal.__str__
decimal_str: _EncodeFunc[Decimal] = Decimal.__str__

long_item_separator, key_separator = separators
if commas:
Expand All @@ -338,7 +338,7 @@ def encode_decimal(decimal: Decimal) -> str:

return decimal_str(decimal)

self._encoder: Callable[[object], str] = make_encoder(
self._encoder: _EncodeFunc[object] = make_encoder(
encode_decimal, indent, mapping_types, seq_types, end,
item_separator, long_item_separator, key_separator,
allow_nan_and_infinity, allow_surrogates, ensure_ascii,
Expand Down
24 changes: 9 additions & 15 deletions src/jsonyx/_manipulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,38 +24,34 @@
_Target = dict[Any, Any] | list[Any]
_Key = int | slice | str
_Node = tuple[_Target, _Key]
_MatchFunc = Callable[[str, int], Match[str] | None]
_Operation = dict[str, Any]
_Operator = Callable[[Any, Any], Any]


_FLAGS: RegexFlag = VERBOSE | MULTILINE | DOTALL

_match_idx: Callable[[str, int], Match[str] | None] = re.compile(
r"-?0|-?[1-9]\d*", _FLAGS,
).match
_match_number: Callable[[str, int], Match[str] | None] = re.compile(
_match_idx: _MatchFunc = re.compile(r"-?0|-?[1-9]\d*", _FLAGS).match
_match_number: _MatchFunc = re.compile(
r"""
(-?0|-?[1-9]\d*) # integer
(\.\d+)? # [frac]
([eE][-+]?\d+)? # [exp]
""", _FLAGS,
).match
_match_slice: Callable[[str, int], Match[str] | None] = re.compile(
_match_slice: _MatchFunc = re.compile(
r"""
(-?0|-?[1-9]\d*)? # [start]
: # ":"
(-?0|-?[1-9]\d*)? # [stop]
(?::(-?0|-?[1-9]\d*)?)? # [":" [step]]
""", _FLAGS,
).match
_match_str_chunk: Callable[[str, int], Match[str] | None] = re.compile(
r"[^'~]*", _FLAGS,
).match
_match_unquoted_key: Callable[[str, int], Match[str] | None] = re.compile(
_match_str_chunk: _MatchFunc = re.compile(r"[^'~]*", _FLAGS).match
_match_unquoted_key: _MatchFunc = re.compile(
r"(?:\w+|[^\x00-\x7f]+)+", _FLAGS,
).match
_match_whitespace: Callable[[str, int], Match[str] | None] = re.compile(
r"\ +", _FLAGS,
).match
_match_whitespace: _MatchFunc = re.compile(r"\ +", _FLAGS).match


def _errmsg(msg: str, query: str, start: int, end: int = 0) -> JSONSyntaxError:
Expand Down Expand Up @@ -104,9 +100,7 @@ def _has_key(target: _Target, key: _Key) -> bool:
return -len(target) <= key < len(target) # type: ignore


def _scan_query_operator(
query: str, end: int,
) -> tuple[Callable[[Any, Any], Any] | None, int]:
def _scan_query_operator(query: str, end: int) -> tuple[_Operator | None, int]:
if query[end:end + 2] == "<=":
operator, end = le, end + 2
elif query[end:end + 1] == "<":
Expand Down

0 comments on commit ea6ea0e

Please sign in to comment.