diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e856af805a..0bbf2f27cc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -87,7 +87,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.9, "3.10", 3.11] + python-version: ["3.10", 3.11, 3.12] steps: - uses: actions/checkout@v2 diff --git a/pyproject.toml b/pyproject.toml index 887e643dfa..fb8a989622 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "Fable" -version = "4.0.0" +version = "4.3.0" description = "Fable" authors = ["Alfonso Garcia-Caro <@alfonsogcnunez>", "Dag Brattli "] license = "MIT License" diff --git a/src/Fable.Transforms/Python/Fable2Python.fs b/src/Fable.Transforms/Python/Fable2Python.fs index 14fabfcb01..0bdf708696 100644 --- a/src/Fable.Transforms/Python/Fable2Python.fs +++ b/src/Fable.Transforms/Python/Fable2Python.fs @@ -727,7 +727,7 @@ module Annotation = stdlibModuleTypeHint com ctx "typing" "Callable" (argTypes @ [ returnType ]) | Fable.DelegateType (argTypes, returnType) -> stdlibModuleTypeHint com ctx "typing" "Callable" (argTypes @ [ returnType ]) | Fable.Option (genArg, _) -> stdlibModuleTypeHint com ctx "typing" "Optional" [ genArg ] - | Fable.Tuple (genArgs, _) -> stdlibModuleTypeHint com ctx "typing" "Tuple" genArgs + | Fable.Tuple (genArgs, _) -> makeGenericTypeAnnotation com ctx "tuple" genArgs None, [] | Fable.Array (genArg, _) -> match genArg with | Fable.Type.Number (UInt8, _) -> Expression.name "bytearray", [] diff --git a/src/fable-library-py/fable_library/bit_converter.py b/src/fable-library-py/fable_library/bit_converter.py index a0e9fc8849..a2de6890f5 100644 --- a/src/fable-library-py/fable_library/bit_converter.py +++ b/src/fable-library-py/fable_library/bit_converter.py @@ -5,43 +5,43 @@ def get_bytes_char(value: str) -> bytes: - return bytearray(bytes(value, "UTF-8")) + return bytes(value, "UTF-8") def get_bytes_int16(value: int) -> bytes: - return bytearray(value.to_bytes(length=2, byteorder=sys.byteorder)) + return value.to_bytes(length=2, byteorder=sys.byteorder) def get_bytes_uint16(value: int) -> bytes: - return bytearray(value.to_bytes(length=2, byteorder=sys.byteorder)) + return value.to_bytes(length=2, byteorder=sys.byteorder) def get_bytes_int32(value: int) -> bytes: - return bytearray(value.to_bytes(length=4, byteorder=sys.byteorder)) + return value.to_bytes(length=4, byteorder=sys.byteorder) def get_bytes_uint32(value: int) -> bytes: - return bytearray(value.to_bytes(length=4, byteorder=sys.byteorder)) + return value.to_bytes(length=4, byteorder=sys.byteorder) def get_bytes_int64(value: int) -> bytes: - return bytearray(value.to_bytes(length=8, byteorder=sys.byteorder)) + return value.to_bytes(length=8, byteorder=sys.byteorder) def get_bytes_uint64(value: int) -> bytes: - return bytearray(value.to_bytes(length=8, byteorder=sys.byteorder)) + return value.to_bytes(length=8, byteorder=sys.byteorder) def get_bytes_boolean(value: bool) -> bytes: - return bytearray(value.to_bytes(length=1, byteorder=sys.byteorder)) + return value.to_bytes(length=1, byteorder=sys.byteorder) def get_bytes_single(value: float) -> bytes: - return bytearray(struct.pack("f", value)) + return struct.pack("f", value) def get_bytes_double(value: float) -> bytes: - return bytearray(struct.pack("d", value)) + return struct.pack("d", value) def int64bits_to_double(value: int) -> float: diff --git a/src/fable-library-py/fable_library/char.py b/src/fable-library-py/fable_library/char.py index 719576af04..769a879c6d 100644 --- a/src/fable-library-py/fable_library/char.py +++ b/src/fable-library-py/fable_library/char.py @@ -1,7 +1,7 @@ -import unicodedata +from __future__ import annotations +import unicodedata from enum import IntEnum -from typing import Dict, Union class UnicodeCategory(IntEnum): @@ -42,7 +42,7 @@ class UnicodeCategory(IntEnum): OtherNotAssigned = 29 -unicode_category_2_python: Dict[str, UnicodeCategory] = { +unicode_category_2_python: dict[str, UnicodeCategory] = { "Ll": UnicodeCategory.LowercaseLetter, "Lu": UnicodeCategory.UppercaseLetter, "Nd": UnicodeCategory.DecimalDigitNumber, @@ -203,7 +203,7 @@ def is_surrogate(s: str, index: int = 0) -> bool: return 0xD800 <= cp <= 0xDFFF -def is_surrogate_pair(s: str, index: Union[str, int]) -> bool: +def is_surrogate_pair(s: str, index: str | int) -> bool: if isinstance(index, int): return is_high_surrogate(s, index) and is_low_surrogate(s, index + 1) diff --git a/src/fable-library-py/fable_library/date_offset.py b/src/fable-library-py/fable_library/date_offset.py index bc1a48032f..6a512c110a 100644 --- a/src/fable-library-py/fable_library/date_offset.py +++ b/src/fable-library-py/fable_library/date_offset.py @@ -1,5 +1,6 @@ +from __future__ import annotations + from datetime import datetime, timedelta, timezone -from typing import Optional, Union from .types import FSharpRef @@ -31,8 +32,8 @@ def create( h: int, m: int, s: int, - ms: Union[int, timedelta], - offset: Optional[timedelta] = None, + ms: int | timedelta, + offset: timedelta | None = None, ) -> datetime: if isinstance(ms, timedelta): offset = ms @@ -57,9 +58,7 @@ def op_addition(x: datetime, y: timedelta) -> datetime: return x + y -def op_subtraction( - x: datetime, y: Union[datetime, timedelta] -) -> Union[datetime, timedelta]: +def op_subtraction(x: datetime, y: datetime | timedelta) -> datetime | timedelta: if isinstance(y, timedelta): return x - y diff --git a/src/fable-library-py/fable_library/diagnostics.py b/src/fable-library-py/fable_library/diagnostics.py index 86d3e62da6..f19b1804d6 100644 --- a/src/fable-library-py/fable_library/diagnostics.py +++ b/src/fable-library-py/fable_library/diagnostics.py @@ -1,5 +1,6 @@ +from __future__ import annotations + import time -from typing import Optional class TimerError(Exception): @@ -8,8 +9,8 @@ class TimerError(Exception): class StopWatch: def __init__(self) -> None: - self._start_time: Optional[float] = None - self._elapsed_time: Optional[float] = None + self._start_time: float | None = None + self._elapsed_time: float | None = None def is_running(self) -> bool: """Return True if timer is running""" @@ -18,14 +19,14 @@ def is_running(self) -> bool: def start(self) -> None: """Start a new timer""" if self._start_time is not None: - raise TimerError(f"Timer is running. Use .stop() to stop it") + raise TimerError("Timer is running. Use .stop() to stop it") self._start_time = time.perf_counter() def stop(self) -> None: """Stop the timer, and report the elapsed time""" if self._start_time is None: - raise TimerError(f"Timer is not running. Use .start() to start it") + raise TimerError("Timer is not running. Use .start() to start it") self._elapsed_time = time.perf_counter() - self._start_time self._start_time = None @@ -33,17 +34,18 @@ def stop(self) -> None: def elapsed_milliseconds(self) -> int: """Return the elapsed time in milliseconds""" if self._elapsed_time is None: - raise TimerError(f"Timer is not running. Use .start() to start it") + raise TimerError("Timer is not running. Use .start() to start it") return int(self._elapsed_time * 1000) def elapsed_ticks(self) -> int: """Return the elapsed time in ticks""" if self._elapsed_time is None: - raise TimerError(f"Timer is not running. Use .start() to start it") + raise TimerError("Timer is not running. Use .start() to start it") return int(self._elapsed_time * 10000000) + def frequency() -> int: return 1000000000 diff --git a/src/fable-library-py/fable_library/mailbox_processor.py b/src/fable-library-py/fable_library/mailbox_processor.py index 8923b7ddc4..335fd9128e 100644 --- a/src/fable-library-py/fable_library/mailbox_processor.py +++ b/src/fable-library-py/fable_library/mailbox_processor.py @@ -2,10 +2,15 @@ from queue import SimpleQueue from threading import RLock -from typing import Any, Callable, Generic, List, Optional, TypeVar +from typing import Any, Callable, Generic, Optional, TypeVar from .async_ import from_continuations, start_immediate -from .async_builder import Async, CancellationToken, OperationCanceledError +from .async_builder import ( + Async, + CancellationToken, + Continuations, + OperationCanceledError, +) _Msg = TypeVar("_Msg") @@ -32,7 +37,7 @@ def __init__( self.body = body # Holds the continuation i.e the `done` callback of Async.from_continuations returned by `receive`. - self.continuation: List[Callable[[Any], None]] = [] + self.continuation: Continuations[Any] | None = None def post(self, msg: _Msg) -> None: """Post a message synchronously to the mailbox processor. @@ -67,9 +72,9 @@ def post_and_async_reply( """ result: Optional[_Reply] = None - continuation: List[ - Callable[[Any], None] - ] = None # This is the continuation for the `done` callback of the awaiting poster. + continuation: Continuations[ + Any + ] | None = None # This is the continuation for the `done` callback of the awaiting poster. def check_completion() -> None: if result is not None and continuation is not None: @@ -84,7 +89,7 @@ def reply_callback(res: _Reply): self.messages.put(build_message(reply_channel)) self.__process_events() - def callback(conts: List[Callable[[Any], None]]) -> None: + def callback(conts: Continuations[Any]) -> None: nonlocal continuation continuation = conts check_completion() @@ -101,7 +106,7 @@ def receive(self) -> Async[_Msg]: the timeout is exceeded. """ - def callback(conts: List[Callable[[Any], None]]): + def callback(conts: Continuations[Any]): if self.continuation: raise Exception("Receive can only be called once!") @@ -118,7 +123,7 @@ def __process_events(self) -> None: # Cancellation of async workflows is more tricky in Python than # with F# so we check the cancellation token for each process. if self.token.is_cancellation_requested: - self.continuation, cont = [], self.continuation + self.continuation, cont = None, self.continuation if cont: cont[2](OperationCanceledError("Mailbox was cancelled")) return @@ -127,7 +132,7 @@ def __process_events(self) -> None: if self.messages.empty(): return msg = self.messages.get() - self.continuation, cont = [], self.continuation + self.continuation, cont = None, self.continuation if cont: cont[0](msg) diff --git a/src/fable-library-py/fable_library/numeric.py b/src/fable-library-py/fable_library/numeric.py index d443b304b5..7b187beb31 100644 --- a/src/fable-library-py/fable_library/numeric.py +++ b/src/fable-library-py/fable_library/numeric.py @@ -1,34 +1,34 @@ -from typing import Optional +from __future__ import annotations from .types import int64 -def to_fixed(x: float, dp: Optional[int] = None) -> str: +def to_fixed(x: float, dp: int | None = None) -> str: x = int(x) if int(x) == x else x if dp is not None: fmt = "{:.%sf}" % dp return fmt.format(x) - return "{}".format(x) + return f"{x}" -def to_precision(x: float, sd: Optional[int] = None) -> str: +def to_precision(x: float, sd: int | None = None) -> str: x = int(x) if int(x) == x else x if sd is not None: fmt = "{:.%se}" % sd return fmt.format(x) - return "{}".format(x) + return f"{x}" -def to_exponential(x: float, dp: Optional[int] = None) -> str: +def to_exponential(x: float, dp: int | None = None) -> str: if dp is not None: fmt = "{:.%se}" % dp return fmt.format(x) - return "{}".format(x) + return f"{x}" def to_hex(x: int) -> str: @@ -36,7 +36,7 @@ def rshift(val: int, n: int) -> int: sign = 0x10000000000000000 if isinstance(val, int64) else 0x100000000 return val >> n if val >= 0 else (val + sign) >> n - return "{0:x}".format(rshift(x, 0)) + return f"{rshift(x, 0):x}" def multiply(x: float, y: float) -> float: diff --git a/src/fable-library-py/fable_library/observable.py b/src/fable-library-py/fable_library/observable.py index 75d17f41d4..3c22bb6ec8 100644 --- a/src/fable-library-py/fable_library/observable.py +++ b/src/fable-library-py/fable_library/observable.py @@ -1,10 +1,13 @@ +from __future__ import annotations + from abc import abstractmethod -from typing import Any, Callable, Generic, Optional, Protocol, Tuple, TypeVar +from collections.abc import Callable +from typing import Any, Generic, Protocol, TypeVar from .choice import ( - Choice_tryValueIfChoice1Of2, - Choice_tryValueIfChoice2Of2, - FSharpChoice_2, + Choice_tryValueIfChoice1Of2, # type: ignore + Choice_tryValueIfChoice2Of2, # type: ignore + FSharpChoice_2, # type: ignore ) from .option import value from .util import IDisposable @@ -42,8 +45,8 @@ class Observer(IObserver[_T]): def __init__( self, on_next: Callable[[_T], None], - on_error: Optional[Callable[[Exception], None]] = None, - on_completed: Optional[Callable[[], None]] = None, + on_error: Callable[[Exception], None] | None = None, + on_completed: Callable[[], None] | None = None, ) -> None: self._on_next = on_next self._on_error = on_error or _noop @@ -97,11 +100,11 @@ def protect( def choose( - chooser: Callable[[_T], Optional[_U]], source: IObservable[_T] + chooser: Callable[[_T], _U | None], source: IObservable[_T] ) -> IObservable[_U]: def subscribe(observer: IObserver[_U]): def on_next(t: _T) -> None: - def success(u: Optional[_U]) -> None: + def success(u: _U | None) -> None: if u is not None: observer.OnNext(value(u)) @@ -181,9 +184,9 @@ def dispose() -> None: return Observable(subscribe) -def pairwise(source: IObservable[_T]) -> IObservable[Tuple[_T, _T]]: - def subscribe(observer: IObserver[Tuple[_T, _T]]) -> IDisposable: - last: Optional[_T] = None +def pairwise(source: IObservable[_T]) -> IObservable[tuple[_T, _T]]: + def subscribe(observer: IObserver[tuple[_T, _T]]) -> IDisposable: + last: _T | None = None def on_next(value: _T) -> None: nonlocal last @@ -200,7 +203,7 @@ def on_next(value: _T) -> None: def partition( predicate: Callable[[_T], bool], source: IObservable[_T] -) -> Tuple[IObservable[_T], IObservable[_T]]: +) -> tuple[IObservable[_T], IObservable[_T]]: return (filter(predicate, source), filter(lambda x: not predicate(x), source)) @@ -224,7 +227,7 @@ def success(u: _U) -> None: def split( splitter: Callable[[_T], FSharpChoice_2], source: IObservable[_T] -) -> Tuple[IObservable[_T], IObservable[_T]]: +) -> tuple[IObservable[_T], IObservable[_T]]: return ( choose(lambda v: Choice_tryValueIfChoice1Of2(splitter(v)), source), choose(lambda v: Choice_tryValueIfChoice2Of2(splitter(v)), source), diff --git a/src/fable-library-py/fable_library/option.py b/src/fable-library-py/fable_library/option.py index 3cba3677d9..8739dba3c1 100644 --- a/src/fable-library-py/fable_library/option.py +++ b/src/fable-library-py/fable_library/option.py @@ -1,4 +1,7 @@ -from typing import Any, Callable, Generic, List, Optional, TypeVar, cast +from __future__ import annotations + +from collections.abc import Callable +from typing import Any, Generic, TypeVar, cast _T = TypeVar("_T") @@ -32,27 +35,27 @@ def __repr__(self): return str(self) -def default_arg(opt: Optional[_T], default_value: _T) -> _T: +def default_arg(opt: _T | None, default_value: _T) -> _T: return value(opt) if opt is not None else default_value -def default_arg_with(opt: Optional[_T], def_thunk: Callable[[], _T]) -> _T: +def default_arg_with(opt: _T | None, def_thunk: Callable[[], _T]) -> _T: return value(opt) if opt is not None else def_thunk() -def filter(predicate: Callable[[_T], bool], opt: Optional[_T]) -> Optional[_T]: +def filter(predicate: Callable[[_T], bool], opt: _T | None) -> _T | None: if opt is not None: return opt if predicate(value(opt)) else None return opt -def map(mapping: Callable[[_T], _U], opt: Optional[_T]) -> Optional[_U]: +def map(mapping: Callable[[_T], _U], opt: _T | None) -> _U | None: return some(mapping(value(opt))) if opt is not None else None def map2( - mapping: Callable[[_T, _U], _V], opt1: Optional[_T], opt2: Optional[_U] -) -> Optional[_V]: + mapping: Callable[[_T, _U], _V], opt1: _T | None, opt2: _U | None +) -> _V | None: return ( mapping(value(opt1), value(opt2)) if (opt1 is not None and opt2 is not None) @@ -62,10 +65,10 @@ def map2( def map3( mapping: Callable[[_T, _U, _V], _W], - opt1: Optional[_T], - opt2: Optional[_U], - opt3: Optional[_V], -) -> Optional[_W]: + opt1: _T | None, + opt2: _U | None, + opt3: _V | None, +) -> _W | None: return ( mapping(value(opt1), value(opt2), value(opt3)) if (opt1 is not None and opt2 is not None and opt3 is not None) @@ -73,11 +76,11 @@ def map3( ) -def some(x: Any) -> Optional[Any]: +def some(x: Any) -> Any | None: return Some[Any](x) if x is None or isinstance(x, Some) else x -def value(x: Optional[_T]) -> _T: +def value(x: _T | None) -> _T: if x is None: raise Exception("Option has no value") elif isinstance(x, Some): @@ -86,33 +89,31 @@ def value(x: Optional[_T]) -> _T: return x -def of_nullable(x: Optional[_T]) -> Optional[_T]: +def of_nullable(x: _T | None) -> _T | None: return x -def to_nullable(x: Optional[_T]) -> Optional[_T]: +def to_nullable(x: _T | None) -> _T | None: return None if x is None else value(x) -def flatten(x: Optional[Optional[_T]]) -> Optional[_T]: +def flatten(x: _T | None | None) -> _T | None: return x if x is None else value(x) -def to_array(opt: Optional[_T]) -> List[_T]: +def to_array(opt: _T | None) -> list[_T]: return [] if opt is None else [value(opt)] -def bind(binder: Callable[[_T], Optional[_U]], opt: Optional[_T]) -> Optional[_U]: +def bind(binder: Callable[[_T], _U | None], opt: _T | None) -> _U | None: return binder(value(opt)) if opt is not None else None -def or_else(opt: Optional[_T], if_none: Optional[_T]) -> Optional[_T]: +def or_else(opt: _T | None, if_none: _T | None) -> _T | None: return if_none if opt is None else opt -def or_else_with( - opt: Optional[_T], if_none_thunk: Callable[[], Optional[_T]] -) -> Optional[_T]: +def or_else_with(opt: _T | None, if_none_thunk: Callable[[], _T | None]) -> _T | None: return if_none_thunk() if opt is None else opt diff --git a/src/fable-library-py/fable_library/path.py b/src/fable-library-py/fable_library/path.py index 3d1b711d32..6d35c6bde4 100644 --- a/src/fable-library-py/fable_library/path.py +++ b/src/fable-library-py/fable_library/path.py @@ -1,6 +1,7 @@ +from __future__ import annotations + import os import tempfile -from typing import Optional def get_temp_file_name() -> str: @@ -35,7 +36,7 @@ def get_file_name_without_extension(path: str) -> str: return os.path.splitext(os.path.basename(path))[0] -def get_full_path(path: str, base_path: Optional[str]=None) -> str: +def get_full_path(path: str, base_path: str | None = None) -> str: return os.path.join(base_path or "", path) @@ -58,4 +59,4 @@ def has_extension(path: str) -> bool: "get_full_path", "get_relative_path", "has_extension", -] \ No newline at end of file +] diff --git a/src/fable-library-py/fable_library/reflection.py b/src/fable-library-py/fable_library/reflection.py index 093059acc2..7eee35d560 100644 --- a/src/fable-library-py/fable_library/reflection.py +++ b/src/fable-library-py/fable_library/reflection.py @@ -1,9 +1,9 @@ from __future__ import annotations import functools - +from collections.abc import Callable from dataclasses import dataclass -from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union, cast +from typing import Any, cast from .types import FSharpRef, Record from .types import Union as FsUnion @@ -12,8 +12,8 @@ Constructor = Callable[..., Any] -EnumCase = Tuple[str, int] -FieldInfo = Tuple[str, "TypeInfo"] +EnumCase = tuple[str, int] +FieldInfo = tuple[str, "TypeInfo"] PropertyInfo = FieldInfo ParameterInfo = FieldInfo @@ -23,25 +23,25 @@ class CaseInfo: declaringType: TypeInfo tag: int name: str - fields: List[FieldInfo] + fields: list[FieldInfo] @dataclass class MethodInfo: name: str - parameters: List[ParameterInfo] + parameters: list[ParameterInfo] returnType: TypeInfo @dataclass class TypeInfo: fullname: str - generics: Optional[List[TypeInfo]] = None - construct: Optional[Constructor] = None - parent: Optional[TypeInfo] = None - fields: Optional[Callable[[], List[FieldInfo]]] = None - cases: Optional[Callable[[], List[CaseInfo]]] = None - enum_cases: Optional[List[EnumCase]] = None + generics: list[TypeInfo] | None = None + construct: Constructor | None = None + parent: TypeInfo | None = None + fields: Callable[[], list[FieldInfo]] | None = None + cases: Callable[[], list[CaseInfo]] | None = None + enum_cases: list[EnumCase] | None = None def __str__(self) -> str: return full_name(self) @@ -57,23 +57,23 @@ def __hash__(self) -> int: def class_type( fullname: str, - generics: Optional[List[TypeInfo]] = None, - construct: Optional[Constructor] = None, - parent: Optional[TypeInfo] = None, + generics: list[TypeInfo] | None = None, + construct: Constructor | None = None, + parent: TypeInfo | None = None, ) -> TypeInfo: return TypeInfo(fullname, generics, construct, parent) def union_type( fullname: str, - generics: List[TypeInfo], - construct: Type[FsUnion], - cases: Callable[[], List[List[FieldInfo]]], + generics: list[TypeInfo], + construct: type[FsUnion], + cases: Callable[[], list[list[FieldInfo]]], ) -> TypeInfo: - def fn() -> List[CaseInfo]: - caseNames: List[str] = construct.cases() + def fn() -> list[CaseInfo]: + caseNames: list[str] = construct.cases() - def mapper(i: int, fields: List[FieldInfo]) -> CaseInfo: + def mapper(i: int, fields: list[FieldInfo]) -> CaseInfo: return CaseInfo(t, i, caseNames[i], fields) return [mapper(i, x) for i, x in enumerate(cases())] @@ -92,9 +92,9 @@ def delegate_type(*generics: TypeInfo) -> TypeInfo: def record_type( fullname: str, - generics: List[TypeInfo], + generics: list[TypeInfo], construct: Constructor, - fields: Callable[[], List[FieldInfo]], + fields: Callable[[], list[FieldInfo]], ) -> TypeInfo: return TypeInfo(fullname, generics, construct, fields=fields) @@ -116,7 +116,7 @@ def array_type(generic: TypeInfo) -> TypeInfo: def enum_type( - fullname: str, underlyingType: TypeInfo, enumCases: List[EnumCase] + fullname: str, underlyingType: TypeInfo, enumCases: list[EnumCase] ) -> TypeInfo: return TypeInfo(fullname, [underlyingType], None, None, None, None, enumCases) @@ -171,15 +171,15 @@ def get_generic_type_definition(t: TypeInfo): ) -def get_generics(t: TypeInfo) -> List[TypeInfo]: +def get_generics(t: TypeInfo) -> list[TypeInfo]: return t.generics if t.generics else [] -def make_generic_type(t: TypeInfo, generics: List[TypeInfo]) -> TypeInfo: +def make_generic_type(t: TypeInfo, generics: list[TypeInfo]) -> TypeInfo: return TypeInfo(t.fullname, generics, t.construct, t.parent, t.fields, t.cases) -def create_instance(t: TypeInfo, consArgs: List[Any]) -> Any: +def create_instance(t: TypeInfo, consArgs: list[Any]) -> Any: # TODO: Check if consArgs length is same as t.construct? # (Arg types can still be different) if callable(t.construct): @@ -192,9 +192,9 @@ def get_value(propertyInfo: PropertyInfo, v: Any) -> Any: return getattr(v, str(propertyInfo[0])) -def name(info: Union[FieldInfo, TypeInfo, CaseInfo]) -> str: - if isinstance(info, Tuple): - return cast(FieldInfo, info)[0] +def name(info: FieldInfo | (TypeInfo | CaseInfo)) -> str: + if isinstance(info, tuple): + return info[0] elif isinstance(info, TypeInfo): i = info.fullname.rfind(".") @@ -255,7 +255,7 @@ def is_instance_of_type(t: TypeInfo, o: Any) -> bool: if isinstance(o, str): return t.fullname == string_type.fullname - if isinstance(o, (int, float)): + if isinstance(o, int | float): return is_erased_to_number(t) if callable(o): @@ -284,7 +284,7 @@ def is_function(t: TypeInfo) -> bool: return t.fullname == "Microsoft.FSharp.Core.FSharpFunc`2" -def get_element_type(t: TypeInfo) -> Optional[TypeInfo]: +def get_element_type(t: TypeInfo) -> TypeInfo | None: return (t.generics[0] if t.generics else None) if is_array(t) else None @@ -292,21 +292,21 @@ def get_enum_underlying_type(t: TypeInfo): return t.generics[0] if t.generics else None -def get_enum_values(t: TypeInfo) -> List[int]: +def get_enum_values(t: TypeInfo) -> list[int]: if is_enum(t) and t.enum_cases is not None: return [int(kv[1]) for kv in t.enum_cases] else: raise ValueError(f"{t.fullname} is not an enum type") -def get_enum_names(t: TypeInfo) -> List[str]: +def get_enum_names(t: TypeInfo) -> list[str]: if is_enum(t) and t.enum_cases is not None: return [str(kv[0]) for kv in t.enum_cases] else: raise ValueError(f"{t.fullname} is not an enum type") -def get_enum_case(t: TypeInfo, v: Union[int, str]) -> EnumCase: +def get_enum_case(t: TypeInfo, v: int | str) -> EnumCase: if t.enum_cases is None: raise ValueError(f"{t.fullname} is not an enum type") @@ -325,14 +325,14 @@ def get_enum_case(t: TypeInfo, v: Union[int, str]) -> EnumCase: return ("", v) -def get_tuple_elements(t: TypeInfo) -> List[TypeInfo]: +def get_tuple_elements(t: TypeInfo) -> list[TypeInfo]: if is_tuple(t) and t.generics is not None: return t.generics else: raise ValueError(f"{t.fullname} is not a tuple type") -def get_function_elements(t: TypeInfo) -> List[TypeInfo]: +def get_function_elements(t: TypeInfo) -> list[TypeInfo]: if is_function(t) and t.generics is not None: gen = t.generics return [gen[0], gen[1]] @@ -341,7 +341,7 @@ def get_function_elements(t: TypeInfo) -> List[TypeInfo]: def parse_enum(t: TypeInfo, string: str) -> int: - value: Optional[int] + value: int | None try: value = int(string) except Exception: @@ -362,7 +362,7 @@ def get_enum_name(t: TypeInfo, v: int) -> str: return str(get_enum_case(t, v)[0]) -def is_enum_defined(t: TypeInfo, v: Union[str, int]) -> bool: +def is_enum_defined(t: TypeInfo, v: str | int) -> bool: try: kv = get_enum_case(t, v) return kv[0] is not None and kv[0] != "" @@ -373,16 +373,16 @@ def is_enum_defined(t: TypeInfo, v: Union[str, int]) -> bool: return False -def get_record_elements(t: TypeInfo) -> List[FieldInfo]: +def get_record_elements(t: TypeInfo) -> list[FieldInfo]: if t.fields is not None: return t.fields() else: raise ValueError(f"{t.fullname} is not an F# record type") -def get_record_fields(v: Any) -> List[str]: - if isinstance(v, Dict): - return list(cast(Dict[str, Any], v).values()) +def get_record_fields(v: Any) -> list[str]: + if isinstance(v, dict): + return list(cast(dict[str, Any], v).values()) return [getattr(v, k) for k in v.__dict__.keys()] @@ -396,15 +396,15 @@ def get_record_field(v: Any, field: FieldInfo) -> Any: return getattr(v, field[0]) -def get_tuple_fields(v: Tuple[Any, ...]) -> Array[Any]: +def get_tuple_fields(v: tuple[Any, ...]) -> Array[Any]: return list(v) -def get_tuple_field(v: Tuple[Any, ...], i: int) -> Any: +def get_tuple_field(v: tuple[Any, ...], i: int) -> Any: return v[i] -def make_record(t: TypeInfo, values: List[Any]) -> Dict[str, Any]: +def make_record(t: TypeInfo, values: list[Any]) -> dict[str, Any]: fields = get_record_elements(t) if len(fields) != len(values): raise ValueError( @@ -414,20 +414,20 @@ def make_record(t: TypeInfo, values: List[Any]) -> Dict[str, Any]: if t.construct is not None: return t.construct(*values) - def reducer(obj: Dict[str, Any], ifield: Tuple[int, FieldInfo]): + def reducer(obj: dict[str, Any], ifield: tuple[int, FieldInfo]): i, field = ifield obj[field[0]] = values[i] return obj - initial: Dict[str, Any] = {} + initial: dict[str, Any] = {} return functools.reduce(reducer, enumerate(fields), initial) -def make_tuple(values: List[Any], _t: TypeInfo) -> Tuple[Any, ...]: +def make_tuple(values: list[Any], _t: TypeInfo) -> tuple[Any, ...]: return tuple(values) -def make_union(uci: CaseInfo, values: List[Any]) -> Any: +def make_union(uci: CaseInfo, values: list[Any]) -> Any: expectedLength = len(uci.fields or []) if len(values) != expectedLength: raise ValueError( @@ -441,14 +441,14 @@ def make_union(uci: CaseInfo, values: List[Any]) -> Any: ) -def get_union_cases(t: TypeInfo) -> List[CaseInfo]: +def get_union_cases(t: TypeInfo) -> list[CaseInfo]: if t.cases and callable(t.cases): return t.cases() else: raise ValueError(f"{t.fullname} is not an F# union type") -def get_union_fields(v: Any, t: TypeInfo) -> List[Any]: +def get_union_fields(v: Any, t: TypeInfo) -> list[Any]: cases = get_union_cases(t) case_ = cases[v.tag] if not case_: @@ -457,7 +457,7 @@ def get_union_fields(v: Any, t: TypeInfo) -> List[Any]: return [case_, list(v.fields)] -def get_union_case_fields(uci: CaseInfo) -> List[FieldInfo]: +def get_union_case_fields(uci: CaseInfo) -> list[FieldInfo]: return uci.fields if uci.fields else [] @@ -476,6 +476,6 @@ def get_case_name(x: Any) -> str: return x.cases()[x.tag] -def get_case_fields(x: Any) -> List[Any]: +def get_case_fields(x: Any) -> list[Any]: assert_union(x) return x.fields diff --git a/src/fable-library-py/fable_library/reg_exp.py b/src/fable-library-py/fable_library/reg_exp.py index eea934d06d..85a1ea8a7b 100644 --- a/src/fable-library-py/fable_library/reg_exp.py +++ b/src/fable-library-py/fable_library/reg_exp.py @@ -1,32 +1,25 @@ -import re +from __future__ import annotations -from typing import ( - Callable, - Iterator, - List, - Match, - Optional, - Pattern, - Union, - Dict, -) +import re +from collections.abc import Callable, Iterator +from re import Match, Pattern MatchEvaluator = Callable[[Match[str]], str] class GroupCollection: - def __init__(self, groups: List[str], named_groups: Dict[str, str]) -> None: + def __init__(self, groups: list[str], named_groups: dict[str, str]) -> None: self.named_groups = named_groups self.groups = groups - def values(self) -> List[str]: + def values(self) -> list[str]: return list(self.groups) def __len__(self) -> int: return len(self.groups) - def __getitem__(self, key: Union[int, str]) -> Optional[str]: + def __getitem__(self, key: int | str) -> str | None: if isinstance(key, int): return self.groups[key] else: @@ -63,16 +56,14 @@ def unescape(string: str) -> str: return re.sub(r"\\(.)", r"\1", string) -def match( - reg: Union[Pattern[str], str], input: str, start_at: int = 0 -) -> Optional[Match[str]]: +def match(reg: Pattern[str] | str, input: str, start_at: int = 0) -> Match[str] | None: if isinstance(reg, str): flags = _options_to_flags(start_at) return re.search(input, reg, flags) return reg.search(input, pos=start_at) -def matches(reg: Pattern[str], input: str, start_at: int = 0) -> List[Match[str]]: +def matches(reg: Pattern[str], input: str, start_at: int = 0) -> list[Match[str]]: if isinstance(reg, str): flags = _options_to_flags(start_at) input = input.replace("?<", "?P<") @@ -81,7 +72,7 @@ def matches(reg: Pattern[str], input: str, start_at: int = 0) -> List[Match[str] return list(reg.finditer(input, pos=start_at)) -def is_match(reg: Union[Pattern[str], str], input: str, start_at: int = 0) -> bool: +def is_match(reg: Pattern[str] | str, input: str, start_at: int = 0) -> bool: if isinstance(reg, str): # Note: input is the pattern here flags = _options_to_flags(start_at) @@ -91,7 +82,7 @@ def is_match(reg: Union[Pattern[str], str], input: str, start_at: int = 0) -> bo def groups(m: Match[str]) -> GroupCollection: - named_groups: Dict[str, str] = m.groupdict() + named_groups: dict[str, str] = m.groupdict() # .NET adds the whole capture as group 0 groups_ = [m.group(0), *m.groups()] @@ -111,10 +102,10 @@ def options(reg: Pattern[str]) -> int: def replace( - reg: Union[str, Pattern[str]], + reg: str | Pattern[str], input: str, - replacement: Union[str, MatchEvaluator], - limit: Optional[int] = None, + replacement: str | MatchEvaluator, + limit: int | None = None, offset: int = 0, ) -> str: if isinstance(replacement, str): @@ -128,11 +119,11 @@ def replace( def split( - reg: Union[str, Pattern[str]], + reg: str | Pattern[str], input: str, - limit: Optional[int] = None, + limit: int | None = None, offset: int = 0, -) -> List[str]: +) -> list[str]: if isinstance(reg, str): return re.split(input, reg, maxsplit=limit or 0) @@ -140,7 +131,7 @@ def split( return reg.split(input, maxsplit=limit or 0)[:limit] -def get_item(groups: GroupCollection, index: Union[str, int]) -> Optional[str]: +def get_item(groups: GroupCollection, index: str | int) -> str | None: return groups[index] diff --git a/src/fable-library-py/fable_library/resize_array.py b/src/fable-library-py/fable_library/resize_array.py index 1ae510e0a8..d0e7c967b5 100644 --- a/src/fable-library-py/fable_library/resize_array.py +++ b/src/fable-library-py/fable_library/resize_array.py @@ -1,10 +1,13 @@ -from typing import Any, Callable, List, TypeVar +from __future__ import annotations + +from collections.abc import Callable +from typing import Any, TypeVar _T = TypeVar("_T") -def exists(predicate: Callable[[_T], bool], xs: List[_T]) -> bool: +def exists(predicate: Callable[[_T], bool], xs: list[_T]) -> bool: """Test if a predicate is true for at least one element in a list.""" for x in xs: @@ -13,7 +16,7 @@ def exists(predicate: Callable[[_T], bool], xs: List[_T]) -> bool: return False -def find_index(predicate: Callable[[_T], bool], xs: List[_T]) -> int: +def find_index(predicate: Callable[[_T], bool], xs: list[_T]) -> int: """Find the index of the first element in a list that satisfies a predicate.""" for i, x in enumerate(xs): @@ -22,7 +25,7 @@ def find_index(predicate: Callable[[_T], bool], xs: List[_T]) -> int: return -1 -def remove_range(start: int, count: int, xs: List[Any]) -> None: +def remove_range(start: int, count: int, xs: list[Any]) -> None: """Remove a range of elements from a list in-place.""" del xs[start : start + count] diff --git a/src/fable-library-py/fable_library/string_.py b/src/fable-library-py/fable_library/string_.py index 49aac6e991..d88fb19931 100644 --- a/src/fable-library-py/fable_library/string_.py +++ b/src/fable-library-py/fable_library/string_.py @@ -1,21 +1,17 @@ +from __future__ import annotations + import locale import re - from base64 import b64decode, b64encode +from collections.abc import Callable, Iterable from dataclasses import dataclass from datetime import datetime from enum import IntEnum +from re import Match, Pattern from typing import ( Any, - Callable, - Iterable, - List, - Match, NoReturn, - Optional, - Pattern, TypeVar, - Union, cast, overload, ) @@ -54,7 +50,7 @@ def printf(input: str) -> IPrintfFormat: return IPrintfFormat(input=input, cont=format) -def continue_print(cont: Callable[[str], Any], arg: Union[IPrintfFormat, str]) -> Any: +def continue_print(cont: Callable[[str], Any], arg: IPrintfFormat | str) -> Any: """Print continuation.""" if isinstance(arg, IPrintfFormat): @@ -64,20 +60,22 @@ def continue_print(cont: Callable[[str], Any], arg: Union[IPrintfFormat, str]) - return cont(arg) -def to_console(arg: Union[IPrintfFormat, Any]) -> Any: +def to_console(arg: IPrintfFormat | Any) -> Any: return continue_print(print, arg) -def to_console_error(arg: Union[IPrintfFormat, str]): - return continue_print(lambda x: print(x), arg) +def to_console_error(arg: IPrintfFormat | str): + return continue_print(lambda x: print(x), arg) # noqa: T201 + +def to_text(arg: IPrintfFormat | str) -> str | Callable[..., Any]: + def cont(x: str) -> Any: + return x -def to_text(arg: Union[IPrintfFormat, str]) -> Union[str, Callable[..., Any]]: - cont: Callable[[str], Any] = lambda x: x return continue_print(cont, arg) -def to_fail(arg: Union[IPrintfFormat, str]): +def to_fail(arg: IPrintfFormat | str): def fail(msg: str): raise Exception(msg) @@ -91,7 +89,7 @@ def format_replacement( flags = flags or "" format = format or "" - if isinstance(rep, (int, float)): + if isinstance(rep, int | float): if format not in ["x", "X"]: if rep < 0: rep = rep * -1 @@ -146,7 +144,7 @@ def format_replacement( return rep -def interpolate(string: str, values: List[Any]) -> str: +def interpolate(string: str, values: list[Any]) -> str: valIdx = 0 strIdx = 0 result = "" @@ -210,10 +208,10 @@ def format(string: str, *args: Any) -> str: def match(m: Match[str]) -> str: idx, padLength, format, precision_, pattern = list(m.groups()) rep = args[int(idx)] - if isinstance(rep, (int, float)): - precision: Optional[int] = None + if isinstance(rep, int | float): + precision: int | None = None try: - precision: Optional[int] = int(precision_) + precision: int | None = int(precision_) except Exception: pass @@ -309,11 +307,11 @@ def insert(string: str, startIndex: int, value: str): return string[:startIndex] + value + string[startIndex:] -def is_null_or_empty(string: Optional[str]): +def is_null_or_empty(string: str | None): return not isinstance(string, str) or not len(string) -def is_null_or_white_space(string: Optional[Any]) -> bool: +def is_null_or_white_space(string: Any | None) -> bool: return not string or not isinstance(string, str) or string.isspace() @@ -322,10 +320,10 @@ def concat(*xs: Iterable[Any]) -> str: def join(delimiter: str, xs: Iterable[Any]) -> str: - return delimiter.join((str(x) for x in xs)) + return delimiter.join(str(x) for x in xs) -def join_with_indices(delimiter: str, xs: List[str], startIndex: int, count: int): +def join_with_indices(delimiter: str, xs: list[str], startIndex: int, count: int): endIndexPlusOne = startIndex + count if endIndexPlusOne > len(xs): raise ValueError("Index and count must refer to a location within the buffer.") @@ -348,7 +346,7 @@ def from_base64string(b64encoded: str) -> bytes: def pad_left( - string: str, length: int, ch: Optional[str] = None, isRight: Optional[bool] = False + string: str, length: int, ch: str | None = None, isRight: bool | None = False ) -> str: ch = ch or " " length = length - len(string) @@ -358,11 +356,11 @@ def pad_left( return string -def pad_right(string: str, len: int, ch: Optional[str] = None) -> str: +def pad_right(string: str, len: int, ch: str | None = None) -> str: return pad_left(string, len, ch, True) -def remove(string: str, startIndex: int, count: Optional[int] = None): +def remove(string: str, startIndex: int, count: int | None = None): if startIndex >= len(string): raise ValueError("startIndex must be less than length of string") @@ -391,10 +389,10 @@ def get_char_at_index(input: str, index: int): def split( string: str, - splitters: Union[str, List[str]], - count: Optional[int] = None, + splitters: str | list[str], + count: int | None = None, removeEmpty: int = 0, -) -> List[str]: +) -> list[str]: """Split string Returns a string array that contains the substrings in this instance @@ -416,7 +414,7 @@ def split( splitters = [escape(x) for x in splitters] or [" "] i = 0 - splits: List[str] = [] + splits: list[str] = [] matches = re.finditer("|".join(splitters), string) for m in matches: if count is not None and count <= 1: @@ -464,7 +462,7 @@ def filter(pred: Callable[[str], bool], x: str) -> str: return "".join(c for c in x if pred(c)) -def substring(string: str, startIndex: int, length: Optional[int] = None) -> str: +def substring(string: str, startIndex: int, length: int | None = None) -> str: if startIndex + (length or 0) > len(string): raise ValueError("Invalid startIndex and/or length") @@ -483,8 +481,8 @@ class StringComparison(IntEnum): OrdinalIgnoreCase = 5 -def cmp(x: str, y: str, ic: Union[bool, StringComparison]) -> int: - def is_ignore_case(i: Union[bool, StringComparison]) -> bool: +def cmp(x: str, y: str, ic: bool | StringComparison) -> int: + def is_ignore_case(i: bool | StringComparison) -> bool: return ( i is True or i == StringComparison.CurrentCultureIgnoreCase @@ -492,7 +490,7 @@ def is_ignore_case(i: Union[bool, StringComparison]) -> bool: or i == StringComparison.OrdinalIgnoreCase ) - def is_ordinal(i: Union[bool, int]) -> bool: + def is_ordinal(i: bool | int) -> bool: return i == StringComparison.Ordinal or i == StringComparison.OrdinalIgnoreCase if not x: @@ -590,7 +588,7 @@ def starts_with(string: str, pattern: str, ic: int): return False -def index_of_any(string: str, any_of: List[str], *args: int): +def index_of_any(string: str, any_of: list[str], *args: int): if not string: return -1 diff --git a/src/fable-library-py/fable_library/task.py b/src/fable-library-py/fable_library/task.py index 5fdb1e29e2..aab39d1514 100644 --- a/src/fable-library-py/fable_library/task.py +++ b/src/fable-library-py/fable_library/task.py @@ -7,9 +7,9 @@ from __future__ import annotations import asyncio - from asyncio import AbstractEventLoop, Future -from typing import Any, Awaitable, Generic, TypeVar +from collections.abc import Awaitable +from typing import Any, Generic, TypeVar _T = TypeVar("_T") diff --git a/src/fable-library-py/fable_library/task_builder.py b/src/fable-library-py/fable_library/task_builder.py index 49d02fb10c..6dff48892f 100644 --- a/src/fable-library-py/fable_library/task_builder.py +++ b/src/fable-library-py/fable_library/task_builder.py @@ -1,9 +1,8 @@ +from __future__ import annotations + +from collections.abc import Awaitable, Callable, Iterable from typing import ( Any, - Awaitable, - Callable, - Iterable, - Optional, Protocol, TypeVar, overload, @@ -20,7 +19,7 @@ class Delayed(Protocol[_T_co]): - def __call__(self, __unit: Optional[None] = None) -> Awaitable[_T_co]: + def __call__(self, __unit: None | None = None) -> Awaitable[_T_co]: ... diff --git a/src/fable-library-py/fable_library/time_span.py b/src/fable-library-py/fable_library/time_span.py index 8a64fc9f79..b28d1cf08f 100644 --- a/src/fable-library-py/fable_library/time_span.py +++ b/src/fable-library-py/fable_library/time_span.py @@ -1,5 +1,7 @@ +from __future__ import annotations + from datetime import timedelta -from typing import Any, Optional +from typing import Any from .util import pad_left_and_right_with_zeros, pad_with_zeros @@ -101,10 +103,10 @@ def divide(ts: timedelta, divisor: int) -> timedelta: def create( d: int = 0, - h: Optional[int] = None, - m: Optional[int] = None, - s: Optional[int] = None, - ms: Optional[int] = None, + h: int | None = None, + m: int | None = None, + s: int | None = None, + ms: int | None = None, ) -> timedelta: if h is None and m is None and s is None and ms is None: return from_ticks(d) @@ -117,7 +119,7 @@ def create( ) -def to_string(ts: timedelta, format: str = "c", _provider: Optional[Any] = None) -> str: +def to_string(ts: timedelta, format: str = "c", _provider: Any | None = None) -> str: if format not in ["c", "g", "G"]: raise ValueError("Custom formats are not supported") diff --git a/src/fable-library-py/fable_library/types.py b/src/fable-library-py/fable_library/types.py index 4fd152c2c0..8057e2e911 100644 --- a/src/fable-library-py/fable_library/types.py +++ b/src/fable-library-py/fable_library/types.py @@ -1,20 +1,14 @@ from __future__ import annotations import array - from abc import abstractmethod +from collections.abc import Callable, Iterable, MutableSequence from typing import ( Any, - Callable, Generic, - Iterable, - List, - MutableSequence, - Optional, TypeVar, + cast, ) -from typing import Union as Union_ -from typing import cast from .util import Array, IComparable, compare @@ -27,8 +21,8 @@ class FSharpRef(Generic[_T]): def __init__( self, - contents_or_getter: Union_[None, _T, Callable[[], _T]], - setter: Optional[Callable[[_T], None]] = None, + contents_or_getter: None | (_T | Callable[[], _T]), + setter: Callable[[_T], None] | None = None, ) -> None: contents = cast(_T, contents_or_getter) @@ -61,7 +55,7 @@ def __init__(self): @staticmethod @abstractmethod - def cases() -> List[str]: + def cases() -> list[str]: ... @property @@ -186,7 +180,7 @@ def record_get_hashcode(self: Record) -> int: class Record(IComparable): - __slots__: List[str] + __slots__: list[str] def GetHashCode(self) -> int: return record_get_hashcode(self) @@ -234,7 +228,7 @@ def seq_to_string(self: Iterable[Any]) -> str: return str + "]" -def to_string(x: Union_[Iterable[Any], Any], call_stack: int = 0) -> str: +def to_string(x: Iterable[Any] | Any, call_stack: int = 0) -> str: if x is not None: if isinstance(x, float) and int(x) == x: return str(int(x)) @@ -341,35 +335,35 @@ class float32(float): float = float # use native float for float64 -def Int8Array(lst: List[int]) -> MutableSequence[int]: +def Int8Array(lst: list[int]) -> MutableSequence[int]: return array.array("b", lst) -def Uint8Array(lst: List[int]) -> MutableSequence[int]: +def Uint8Array(lst: list[int]) -> MutableSequence[int]: return bytearray(lst) -def Int16Array(lst: List[int]) -> MutableSequence[int]: +def Int16Array(lst: list[int]) -> MutableSequence[int]: return array.array("h", lst) -def Uint16Array(lst: List[int]) -> MutableSequence[int]: +def Uint16Array(lst: list[int]) -> MutableSequence[int]: return array.array("H", lst) -def Int32Array(lst: List[int]) -> MutableSequence[int]: +def Int32Array(lst: list[int]) -> MutableSequence[int]: return array.array("i", lst) -def Uint32Array(lst: List[int]) -> MutableSequence[int]: +def Uint32Array(lst: list[int]) -> MutableSequence[int]: return array.array("I", lst) -def Float32Array(lst: List[float]) -> MutableSequence[float]: +def Float32Array(lst: list[float]) -> MutableSequence[float]: return array.array("f", lst) -def Float64Array(lst: List[float]) -> MutableSequence[float]: +def Float64Array(lst: list[float]) -> MutableSequence[float]: return array.array("d", lst) diff --git a/src/fable-library-py/fable_library/uri.py b/src/fable-library-py/fable_library/uri.py index c324c73879..18fce95f3b 100644 --- a/src/fable-library-py/fable_library/uri.py +++ b/src/fable-library-py/fable_library/uri.py @@ -1,9 +1,7 @@ from __future__ import annotations from enum import IntEnum -from typing import Union -from urllib.parse import ParseResult, urlparse, urljoin, unquote - +from urllib.parse import ParseResult, unquote, urljoin, urlparse from .types import FSharpRef @@ -19,8 +17,8 @@ class Uri: def __init__( self, - base_uri: Union[Uri, str], - kind_or_uri: Union[int, str, Uri, None] = UriKind.Absolute, + base_uri: Uri | str, + kind_or_uri: int | (str | (Uri | None)) = UriKind.Absolute, ) -> None: self.res: ParseResult @@ -104,13 +102,13 @@ def __str__(self) -> str: @staticmethod def create( - uri: Union[str, Uri], kind_or_uri: Union[UriKind, str, Uri] = UriKind.Absolute + uri: str | Uri, kind_or_uri: UriKind | (str | Uri) = UriKind.Absolute ) -> Uri: return Uri(uri, kind_or_uri) @staticmethod def try_create( - uri: Union[str, Uri], kind_or_uri: Union[UriKind, str, Uri], out: FSharpRef[Uri] + uri: str | Uri, kind_or_uri: UriKind | (str | Uri), out: FSharpRef[Uri] ) -> bool: try: out.contents = Uri.create(uri, kind_or_uri) diff --git a/src/fable-library-py/fable_library/util.py b/src/fable-library-py/fable_library/util.py index 538aa1d994..4e99cea8d0 100644 --- a/src/fable-library-py/fable_library/util.py +++ b/src/fable-library-py/fable_library/util.py @@ -1,39 +1,34 @@ from __future__ import annotations + import builtins import functools import math import platform import random import re - +import weakref from abc import ABC, abstractmethod from array import array +from collections.abc import ( + Callable, + Iterable, + Iterator, + MutableSequence, + Sequence, + Sized, +) +from contextlib import AbstractContextManager from enum import IntEnum -from inspect import Parameter, signature from threading import RLock from types import TracebackType from typing import ( Any, - Callable, - ContextManager, - Dict, Generic, - Iterable, - Iterator, - List, - MutableSequence, - Optional, Protocol, - Sequence, - Sized, - Tuple, - Type, TypeVar, - Union, cast, ) from urllib.parse import quote, unquote -import weakref class SupportsLessThan(Protocol): @@ -76,9 +71,9 @@ def __enter__(self): def __exit__( self, - exctype: Optional[Type[BaseException]], - excinst: Optional[BaseException], - exctb: Optional[TracebackType], + exctype: type[BaseException] | None, + excinst: BaseException | None, + exctb: TracebackType | None, ) -> bool: """Exit context management.""" @@ -247,7 +242,7 @@ def is_iterable(x: Any) -> bool: return isinstance(x, Iterable) -def compare_dicts(x: Dict[str, Any], y: Dict[str, Any]) -> int: +def compare_dicts(x: dict[str, Any], y: dict[str, Any]) -> int: """Compare Python dicts with string keys. Python cannot do this natively. @@ -273,7 +268,7 @@ def compare_dicts(x: Dict[str, Any], y: Dict[str, Any]) -> int: return 0 -def compare_arrays(xs: List[Any], ys: List[Any]): +def compare_arrays(xs: list[Any], ys: list[Any]): if xs is None: return 0 if ys is None else 1 @@ -306,10 +301,10 @@ def compare(a: Any, b: Any) -> int: return a.__cmp__(b) if isinstance(a, dict): - return compare_dicts(cast(Dict[str, Any], a), b) + return compare_dicts(cast(dict[str, Any], a), b) - if isinstance(a, List): - return compare_arrays(cast(List[Any], a), b) + if isinstance(a, list): + return compare_arrays(cast(list[Any], a), b) if is_equatable(a) and a == b: return 0 @@ -321,7 +316,7 @@ def compare(a: Any, b: Any) -> int: def equal_arrays_with( - xs: Optional[Sequence[_T]], ys: Optional[Sequence[_T]], eq: Callable[[_T, _T], bool] + xs: Sequence[_T] | None, ys: Sequence[_T] | None, eq: Callable[[_T, _T], bool] ) -> bool: if xs is None: return ys is None @@ -366,12 +361,12 @@ def clamp(comparer: Callable[[_T, _T], int], value: _T, min: _T, max: _T): ) -def assert_equal(actual: Any, expected: Any, msg: Optional[str] = None) -> None: +def assert_equal(actual: Any, expected: Any, msg: str | None = None) -> None: if not equals(actual, expected): raise Exception(msg or f"Expected: ${expected} - Actual: ${actual}") -def assert_not_equal(actual: _T, expected: _T, msg: Optional[str] = None) -> None: +def assert_not_equal(actual: _T, expected: _T, msg: str | None = None) -> None: if equals(actual, expected): raise Exception(msg or f"Expected: ${expected} - Actual: ${actual}") @@ -393,7 +388,7 @@ class Lazy(Generic[_T]): def __init__(self, factory: Callable[[], _T]): self.factory = factory self.is_value_created: bool = False - self.created_value: Optional[_T] = None + self.created_value: _T | None = None @property def Value(self) -> _T: @@ -430,14 +425,14 @@ def pad_left_and_right_with_zeros(i: int, length_left: int, length_right: int) - class Atom(Generic[_T], Protocol): - def __call__(self, *value: _T) -> Optional[_T]: + def __call__(self, *value: _T) -> _T | None: ... def create_atom(value: _T) -> Atom[_T]: atom = value - def wrapper(*value: _T) -> Optional[_T]: + def wrapper(*value: _T) -> _T | None: nonlocal atom if len(value) == 0: @@ -449,41 +444,41 @@ def wrapper(*value: _T) -> Optional[_T]: return wrapper -def create_obj(fields: List[Tuple[Any, Any]]): +def create_obj(fields: list[tuple[Any, Any]]): return dict(fields) -def tohex(val: int, nbits: Optional[int] = None) -> str: +def tohex(val: int, nbits: int | None = None) -> str: if nbits: val = (val + (1 << nbits)) % (1 << nbits) - return "{:x}".format(val) + return f"{val:x}" -def int_to_string(i: int, radix: int = 10, bitsize: Optional[int] = None) -> str: +def int_to_string(i: int, radix: int = 10, bitsize: int | None = None) -> str: if radix == 10: - return "{:d}".format(i) + return f"{i:d}" if radix == 16: return tohex(i, bitsize) if radix == 2: - return "{:b}".format(i) + return f"{i:b}" if radix == 8: - return "{:o}".format(i) + return f"{i:o}" return str(i) -def int8_to_string(i: int, radix: int = 10, bitsize: Optional[int] = None) -> str: +def int8_to_string(i: int, radix: int = 10, bitsize: int | None = None) -> str: return int_to_string(i, radix, 8) -def int16_to_string(i: int, radix: int = 10, bitsize: Optional[int] = None) -> str: +def int16_to_string(i: int, radix: int = 10, bitsize: int | None = None) -> str: return int_to_string(i, radix, 16) -def int32_to_string(i: int, radix: int = 10, bitsize: Optional[int] = None) -> str: +def int32_to_string(i: int, radix: int = 10, bitsize: int | None = None) -> str: return int_to_string(i, radix, 32) -def int64_to_string(i: int, radix: int = 10, bitsize: Optional[int] = None) -> str: +def int64_to_string(i: int, radix: int = 10, bitsize: int | None = None) -> str: return int_to_string(i, radix, 64) @@ -498,8 +493,8 @@ def count(col: Iterable[Any]) -> int: return count -def clear(col: Optional[Union[Dict[Any, Any], List[Any]]]) -> None: - if isinstance(col, (List, Dict)): +def clear(col: dict[Any, Any] | list[Any] | None) -> None: + if isinstance(col, list | dict): col.clear() @@ -565,7 +560,7 @@ class ICollection(IEnumerable_1[_T], Protocol): ... -class IDictionary(ICollection[Tuple[_Key, _Value]], Protocol): +class IDictionary(ICollection[tuple[_Key, _Value]], Protocol): @abstractmethod def keys(self) -> IEnumerable_1[_Key]: ... @@ -634,6 +629,7 @@ def get_enumerator(o: Iterable[Any]) -> Enumerator[Any]: else: return Enumerator(iter(o)) + _T1 = TypeVar("_T1") _T2 = TypeVar("_T2") _T3 = TypeVar("_T3") @@ -648,124 +644,375 @@ def get_enumerator(o: Iterable[Any]) -> Enumerator[Any]: _curried = weakref.WeakKeyDictionary[Any, Any]() -def uncurry10(f: Callable[[_T1], Callable [[_T2], Callable [[_T3], Callable [[_T4], Callable [[_T5], Callable [[_T6], Callable [[_T7], Callable [[_T8], Callable [[_T9], Callable [[_T10], _TResult]]]]]]]]]]) -> Callable[[_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10], _TResult]: - f2: Callable[[_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10], _TResult] = lambda a1, a2, a3, a4, a5, a6, a7, a8, a9, a10: f(a1)(a2)(a3)(a4)(a5)(a6)(a7)(a8)(a9)(a10) - _curried[f2] = f - return f2 -def curry10(f: Callable[[_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10], _TResult]) -> Callable[[_T1], Callable [[_T2], Callable [[_T3], Callable [[_T4], Callable [[_T5], Callable [[_T6], Callable [[_T7], Callable [[_T8], Callable [[_T9], Callable [[_T10], _TResult]]]]]]]]]]: - f2 = _curried.get(f) - if f2 is None: - return lambda a1: lambda a2: lambda a3: lambda a4: lambda a5: lambda a6: lambda a7: lambda a8: lambda a9: lambda a10: f(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) - else: +def uncurry10( + f: Callable[ + [_T1], + Callable[ + [_T2], + Callable[ + [_T3], + Callable[ + [_T4], + Callable[ + [_T5], + Callable[ + [_T6], + Callable[ + [_T7], + Callable[ + [_T8], Callable[[_T9], Callable[[_T10], _TResult]] + ], + ], + ], + ], + ], + ], + ], + ] +) -> Callable[[_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10], _TResult]: + def f2( + a1: _T1, + a2: _T2, + a3: _T3, + a4: _T4, + a5: _T5, + a6: _T6, + a7: _T7, + a8: _T8, + a9: _T9, + a10: _T10, + ) -> _TResult: + return f(a1)(a2)(a3)(a4)(a5)(a6)(a7)(a8)(a9)(a10) + + _curried[f2] = f return f2 -def uncurry9(f: Callable[[_T1], Callable [[_T2], Callable [[_T3], Callable [[_T4], Callable [[_T5], Callable [[_T6], Callable [[_T7], Callable [[_T8], Callable [[_T9], _TResult]]]]]]]]]) -> Callable[[_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9], _TResult]: - f2: Callable[[_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9], _TResult] = lambda a1, a2, a3, a4, a5, a6, a7, a8, a9: f(a1)(a2)(a3)(a4)(a5)(a6)(a7)(a8)(a9) - _curried[f2] = f - return f2 -def curry9(f: Callable[[_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9], _TResult]) -> Callable[[_T1], Callable [[_T2], Callable [[_T3], Callable [[_T4], Callable [[_T5], Callable [[_T6], Callable [[_T7], Callable [[_T8], Callable [[_T9], _TResult]]]]]]]]]: - f2 = _curried.get(f) - if f2 is None: - return lambda a1: lambda a2: lambda a3: lambda a4: lambda a5: lambda a6: lambda a7: lambda a8: lambda a9: f(a1, a2, a3, a4, a5, a6, a7, a8, a9) - else: +def curry10( + f: Callable[[_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10], _TResult] +) -> Callable[ + [_T1], + Callable[ + [_T2], + Callable[ + [_T3], + Callable[ + [_T4], + Callable[ + [_T5], + Callable[ + [_T6], + Callable[ + [_T7], + Callable[ + [_T8], Callable[[_T9], Callable[[_T10], _TResult]] + ], + ], + ], + ], + ], + ], + ], +]: + f2 = _curried.get(f) + if f2 is None: + return lambda a1: lambda a2: lambda a3: lambda a4: lambda a5: lambda a6: lambda a7: lambda a8: lambda a9: lambda a10: f( + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 + ) + else: + return f2 + + +def uncurry9( + f: Callable[ + [_T1], + Callable[ + [_T2], + Callable[ + [_T3], + Callable[ + [_T4], + Callable[ + [_T5], + Callable[ + [_T6], + Callable[[_T7], Callable[[_T8], Callable[[_T9], _TResult]]], + ], + ], + ], + ], + ], + ] +) -> Callable[[_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9], _TResult]: + def f2( + a1: _T1, a2: _T2, a3: _T3, a4: _T4, a5: _T5, a6: _T6, a7: _T7, a8: _T8, a9: _T9 + ) -> _TResult: + return f(a1)(a2)(a3)(a4)(a5)(a6)(a7)(a8)(a9) + + _curried[f2] = f return f2 -def uncurry8(f: Callable[[_T1], Callable [[_T2], Callable [[_T3], Callable [[_T4], Callable [[_T5], Callable [[_T6], Callable [[_T7], Callable [[_T8], _TResult]]]]]]]]) -> Callable[[_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8], _TResult]: - f2: Callable[[_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8], _TResult] = lambda a1, a2, a3, a4, a5, a6, a7, a8: f(a1)(a2)(a3)(a4)(a5)(a6)(a7)(a8) - _curried[f2] = f - return f2 -def curry8(f: Callable[[_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8], _TResult]) -> Callable[[_T1], Callable [[_T2], Callable [[_T3], Callable [[_T4], Callable [[_T5], Callable [[_T6], Callable [[_T7], Callable [[_T8], _TResult]]]]]]]]: - f2 = _curried.get(f) - if f2 is None: - return lambda a1: lambda a2: lambda a3: lambda a4: lambda a5: lambda a6: lambda a7: lambda a8: f(a1, a2, a3, a4, a5, a6, a7, a8) - else: +def curry9( + f: Callable[[_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9], _TResult] +) -> Callable[ + [_T1], + Callable[ + [_T2], + Callable[ + [_T3], + Callable[ + [_T4], + Callable[ + [_T5], + Callable[ + [_T6], + Callable[[_T7], Callable[[_T8], Callable[[_T9], _TResult]]], + ], + ], + ], + ], + ], +]: + f2 = _curried.get(f) + if f2 is None: + return lambda a1: lambda a2: lambda a3: lambda a4: lambda a5: lambda a6: lambda a7: lambda a8: lambda a9: f( + a1, a2, a3, a4, a5, a6, a7, a8, a9 + ) + else: + return f2 + + +def uncurry8( + f: Callable[ + [_T1], + Callable[ + [_T2], + Callable[ + [_T3], + Callable[ + [_T4], + Callable[ + [_T5], + Callable[[_T6], Callable[[_T7], Callable[[_T8], _TResult]]], + ], + ], + ], + ], + ] +) -> Callable[[_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8], _TResult]: + def f2( + a1: _T1, a2: _T2, a3: _T3, a4: _T4, a5: _T5, a6: _T6, a7: _T7, a8: _T8 + ) -> _TResult: + return f(a1)(a2)(a3)(a4)(a5)(a6)(a7)(a8) + + _curried[f2] = f return f2 -def uncurry7(f: Callable[[_T1], Callable [[_T2], Callable [[_T3], Callable [[_T4], Callable [[_T5], Callable [[_T6], Callable [[_T7], _TResult]]]]]]]) -> Callable[[_T1, _T2, _T3, _T4, _T5, _T6, _T7], _TResult]: - f2: Callable[[_T1, _T2, _T3, _T4, _T5, _T6, _T7], _TResult] = lambda a1, a2, a3, a4, a5, a6, a7: f(a1)(a2)(a3)(a4)(a5)(a6)(a7) - _curried[f2] = f - return f2 -def curry7(f: Callable[[_T1, _T2, _T3, _T4, _T5, _T6, _T7], _TResult]) -> Callable[[_T1], Callable [[_T2], Callable [[_T3], Callable [[_T4], Callable [[_T5], Callable [[_T6], Callable [[_T7], _TResult]]]]]]]: - f2 = _curried.get(f) - if f2 is None: - return lambda a1: lambda a2: lambda a3: lambda a4: lambda a5: lambda a6: lambda a7: f(a1, a2, a3, a4, a5, a6, a7) - else: +def curry8( + f: Callable[[_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8], _TResult] +) -> Callable[ + [_T1], + Callable[ + [_T2], + Callable[ + [_T3], + Callable[ + [_T4], + Callable[ + [_T5], Callable[[_T6], Callable[[_T7], Callable[[_T8], _TResult]]] + ], + ], + ], + ], +]: + f2 = _curried.get(f) + if f2 is None: + return lambda a1: lambda a2: lambda a3: lambda a4: lambda a5: lambda a6: lambda a7: lambda a8: f( + a1, a2, a3, a4, a5, a6, a7, a8 + ) + else: + return f2 + + +def uncurry7( + f: Callable[ + [_T1], + Callable[ + [_T2], + Callable[ + [_T3], + Callable[ + [_T4], Callable[[_T5], Callable[[_T6], Callable[[_T7], _TResult]]] + ], + ], + ], + ] +) -> Callable[[_T1, _T2, _T3, _T4, _T5, _T6, _T7], _TResult]: + def f2(a1: _T1, a2: _T2, a3: _T3, a4: _T4, a5: _T5, a6: _T6, a7: _T7) -> _TResult: + return f(a1)(a2)(a3)(a4)(a5)(a6)(a7) + + _curried[f2] = f return f2 -def uncurry6(f: Callable[[_T1], Callable [[_T2], Callable [[_T3], Callable [[_T4], Callable [[_T5], Callable [[_T6], _TResult]]]]]]) -> Callable[[_T1, _T2, _T3, _T4, _T5, _T6], _TResult]: - f2: Callable[[_T1, _T2, _T3, _T4, _T5, _T6], _TResult] = lambda a1, a2, a3, a4, a5, a6: f(a1)(a2)(a3)(a4)(a5)(a6) - _curried[f2] = f - return f2 -def curry6(f: Callable[[_T1, _T2, _T3, _T4, _T5, _T6], _TResult]) -> Callable[[_T1], Callable [[_T2], Callable [[_T3], Callable [[_T4], Callable [[_T5], Callable [[_T6], _TResult]]]]]]: - f2 = _curried.get(f) - if f2 is None: - return lambda a1: lambda a2: lambda a3: lambda a4: lambda a5: lambda a6: f(a1, a2, a3, a4, a5, a6) - else: +def curry7( + f: Callable[[_T1, _T2, _T3, _T4, _T5, _T6, _T7], _TResult] +) -> Callable[ + [_T1], + Callable[ + [_T2], + Callable[ + [_T3], + Callable[ + [_T4], Callable[[_T5], Callable[[_T6], Callable[[_T7], _TResult]]] + ], + ], + ], +]: + f2 = _curried.get(f) + if f2 is None: + return lambda a1: lambda a2: lambda a3: lambda a4: lambda a5: lambda a6: lambda a7: f( + a1, a2, a3, a4, a5, a6, a7 + ) + else: + return f2 + + +def uncurry6( + f: Callable[ + [_T1], + Callable[ + [_T2], + Callable[ + [_T3], Callable[[_T4], Callable[[_T5], Callable[[_T6], _TResult]]] + ], + ], + ] +) -> Callable[[_T1, _T2, _T3, _T4, _T5, _T6], _TResult]: + def f2(a1: _T1, a2: _T2, a3: _T3, a4: _T4, a5: _T5, a6: _T6) -> _TResult: + return f(a1)(a2)(a3)(a4)(a5)(a6) + + _curried[f2] = f return f2 -def uncurry5(f: Callable[[_T1], Callable [[_T2], Callable [[_T3], Callable [[_T4], Callable [[_T5], _TResult]]]]]) -> Callable[[_T1, _T2, _T3, _T4, _T5], _TResult]: - f2: Callable[[_T1, _T2, _T3, _T4, _T5], _TResult] = lambda a1, a2, a3, a4, a5: f(a1)(a2)(a3)(a4)(a5) - _curried[f2] = f - return f2 -def curry5(f: Callable[[_T1, _T2, _T3, _T4, _T5], _TResult]) -> Callable[[_T1], Callable [[_T2], Callable [[_T3], Callable [[_T4], Callable [[_T5], _TResult]]]]]: - f2 = _curried.get(f) - if f2 is None: - return lambda a1: lambda a2: lambda a3: lambda a4: lambda a5: f(a1, a2, a3, a4, a5) - else: +def curry6( + f: Callable[[_T1, _T2, _T3, _T4, _T5, _T6], _TResult] +) -> Callable[ + [_T1], + Callable[ + [_T2], + Callable[[_T3], Callable[[_T4], Callable[[_T5], Callable[[_T6], _TResult]]]], + ], +]: + f2 = _curried.get(f) + if f2 is None: + return lambda a1: lambda a2: lambda a3: lambda a4: lambda a5: lambda a6: f( + a1, a2, a3, a4, a5, a6 + ) + else: + return f2 + + +def uncurry5( + f: Callable[ + [_T1], + Callable[[_T2], Callable[[_T3], Callable[[_T4], Callable[[_T5], _TResult]]]], + ] +) -> Callable[[_T1, _T2, _T3, _T4, _T5], _TResult]: + def f2(a1: _T1, a2: _T2, a3: _T3, a4: _T4, a5: _T5) -> _TResult: + return f(a1)(a2)(a3)(a4)(a5) + + _curried[f2] = f return f2 -def uncurry4(f: Callable[[_T1], Callable [[_T2], Callable [[_T3], Callable [[_T4], _TResult]]]]) -> Callable[[_T1, _T2, _T3, _T4], _TResult]: - f2: Callable[[_T1, _T2, _T3, _T4], _TResult] = lambda a1, a2, a3, a4: f(a1)(a2)(a3)(a4) - _curried[f2] = f - return f2 -def curry4(f: Callable[[_T1, _T2, _T3, _T4], _TResult]) -> Callable[[_T1], Callable [[_T2], Callable [[_T3], Callable [[_T4], _TResult]]]]: - f2 = _curried.get(f) - if f2 is None: - return lambda a1: lambda a2: lambda a3: lambda a4: f(a1, a2, a3, a4) - else: +def curry5( + f: Callable[[_T1, _T2, _T3, _T4, _T5], _TResult] +) -> Callable[ + [_T1], Callable[[_T2], Callable[[_T3], Callable[[_T4], Callable[[_T5], _TResult]]]] +]: + f2 = _curried.get(f) + if f2 is None: + return lambda a1: lambda a2: lambda a3: lambda a4: lambda a5: f( + a1, a2, a3, a4, a5 + ) + else: + return f2 + + +def uncurry4( + f: Callable[[_T1], Callable[[_T2], Callable[[_T3], Callable[[_T4], _TResult]]]] +) -> Callable[[_T1, _T2, _T3, _T4], _TResult]: + def f2(a1: _T1, a2: _T2, a3: _T3, a4: _T4) -> _TResult: + return f(a1)(a2)(a3)(a4) + + _curried[f2] = f return f2 -def uncurry3(f: Callable[[_T1], Callable [[_T2], Callable [[_T3], _TResult]]]) -> Callable[[_T1, _T2, _T3], _TResult]: - f2: Callable[[_T1, _T2, _T3], _TResult] = lambda a1, a2, a3: f(a1)(a2)(a3) - _curried[f2] = f - return f2 -def curry3(f: Callable[[_T1, _T2, _T3], _TResult]) -> Callable[[_T1], Callable [[_T2], Callable [[_T3], _TResult]]]: - f2 = _curried.get(f) - if f2 is None: - return lambda a1: lambda a2: lambda a3: f(a1, a2, a3) - else: +def curry4( + f: Callable[[_T1, _T2, _T3, _T4], _TResult] +) -> Callable[[_T1], Callable[[_T2], Callable[[_T3], Callable[[_T4], _TResult]]]]: + f2 = _curried.get(f) + if f2 is None: + return lambda a1: lambda a2: lambda a3: lambda a4: f(a1, a2, a3, a4) + else: + return f2 + + +def uncurry3( + f: Callable[[_T1], Callable[[_T2], Callable[[_T3], _TResult]]] +) -> Callable[[_T1, _T2, _T3], _TResult]: + def f2(a1: _T1, a2: _T2, a3: _T3) -> _TResult: + return f(a1)(a2)(a3) + + _curried[f2] = f return f2 -def uncurry2(f: Callable[[_T1], Callable [[_T2], _TResult]]) -> Callable[[_T1, _T2], _TResult]: - f2: Callable[[_T1, _T2], _TResult] = lambda a1, a2: f(a1)(a2) - _curried[f2] = f - return f2 -def curry2(f: Callable[[_T1, _T2], _TResult]) -> Callable[[_T1], Callable [[_T2], _TResult]]: - f2 = _curried.get(f) - if f2 is None: - return lambda a1: lambda a2: f(a1, a2) - else: +def curry3( + f: Callable[[_T1, _T2, _T3], _TResult] +) -> Callable[[_T1], Callable[[_T2], Callable[[_T3], _TResult]]]: + f2 = _curried.get(f) + if f2 is None: + return lambda a1: lambda a2: lambda a3: f(a1, a2, a3) + else: + return f2 + + +def uncurry2( + f: Callable[[_T1], Callable[[_T2], _TResult]] +) -> Callable[[_T1, _T2], _TResult]: + def f2(a1: _T1, a2: _T2) -> _TResult: + return f(a1)(a2) + + _curried[f2] = f return f2 +def curry2( + f: Callable[[_T1, _T2], _TResult] +) -> Callable[[_T1], Callable[[_T2], _TResult]]: + f2 = _curried.get(f) + if f2 is None: + return lambda a1: lambda a2: f(a1, a2) + else: + return f2 + + def is_array_like(x: Any) -> bool: - return isinstance(x, (list, tuple, set, array, bytes, bytearray)) + return isinstance(x, list | tuple | set | array | bytes | bytearray) def is_disposable(x: Any) -> bool: return x is not None and isinstance(x, IDisposable) -def dispose(x: Union[Disposable, ContextManager[Any]]) -> None: +def dispose(x: Disposable | AbstractContextManager[Any]) -> None: """Helper to dispose objects. Also tries to call `__exit__` if the object turns out to be a Python resource manager. @@ -803,13 +1050,13 @@ def __next__(self): class ObjectRef: - id_map: Dict[int, int] = dict() + id_map: dict[int, int] = dict() count = 0 @staticmethod def id(o: Any) -> int: _id = id(o) - if not _id in ObjectRef.id_map: + if _id not in ObjectRef.id_map: count = ObjectRef.count + 1 ObjectRef.id_map[_id] = count @@ -851,7 +1098,7 @@ def identity_hash(x: Any) -> int: return physical_hash(x) -def combine_hash_codes(hashes: List[int]) -> int: +def combine_hash_codes(hashes: list[int]) -> int: if not hashes: return 0 @@ -862,8 +1109,8 @@ def structural_hash(x: Any) -> int: return hash(x) -def array_hash(xs: List[Any]) -> int: - hashes: List[int] = [] +def array_hash(xs: list[Any]) -> int: + hashes: list[int] = [] for x in xs: hashes.append(structural_hash(x))