comment here
This commit is contained in:
39
.CondaPkg/env/lib/python3.11/site-packages/typish/__init__.py
vendored
Normal file
39
.CondaPkg/env/lib/python3.11/site-packages/typish/__init__.py
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
from typish._meta import __version__
|
||||
from typish._types import (
|
||||
T,
|
||||
KT,
|
||||
VT,
|
||||
Empty,
|
||||
Unknown,
|
||||
Module,
|
||||
NoneType,
|
||||
Ellipsis_,
|
||||
EllipsisType,
|
||||
)
|
||||
from typish.classes._cls_dict import ClsDict
|
||||
from typish.classes._cls_function import ClsFunction
|
||||
from typish.classes._literal import Literal, LiteralAlias, is_literal_type
|
||||
from typish.classes._something import Something, TypingType
|
||||
from typish.classes._subscriptable_type import SubscriptableType
|
||||
from typish.classes._union_type import UnionType
|
||||
from typish.decorators._hintable import hintable
|
||||
from typish.functions._common_ancestor import (
|
||||
common_ancestor,
|
||||
common_ancestor_of_types
|
||||
)
|
||||
from typish.functions._get_alias import get_alias
|
||||
from typish.functions._get_args import get_args
|
||||
from typish.functions._get_mro import get_mro
|
||||
from typish.functions._get_origin import get_origin
|
||||
from typish.functions._get_simple_name import get_simple_name
|
||||
from typish.functions._get_type import get_type
|
||||
from typish.functions._get_type_hints_of_callable import (
|
||||
get_args_and_return_type,
|
||||
get_type_hints_of_callable
|
||||
)
|
||||
from typish.functions._instance_of import instance_of
|
||||
from typish.functions._is_type_annotation import is_type_annotation
|
||||
from typish.functions._is_optional_type import is_optional_type
|
||||
from typish.functions._subclass_of import subclass_of
|
||||
from typish.functions._is_from_typing import is_from_typing
|
||||
from typish._state import State, register_get_type
|
||||
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/__pycache__/_meta.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/__pycache__/_meta.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/__pycache__/_state.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/__pycache__/_state.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/__pycache__/_types.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/__pycache__/_types.cpython-311.pyc
vendored
Normal file
Binary file not shown.
7
.CondaPkg/env/lib/python3.11/site-packages/typish/_meta.py
vendored
Normal file
7
.CondaPkg/env/lib/python3.11/site-packages/typish/_meta.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
__title__ = 'typish'
|
||||
__version__ = '1.9.3'
|
||||
__author__ = 'Ramon Hagenaars'
|
||||
__author_email__ = 'ramon.hagenaars@gmail.com'
|
||||
__description__ = 'Functionality for types'
|
||||
__url__ = 'https://github.com/ramonhagenaars/typish'
|
||||
__license__ = 'MIT'
|
||||
45
.CondaPkg/env/lib/python3.11/site-packages/typish/_state.py
vendored
Normal file
45
.CondaPkg/env/lib/python3.11/site-packages/typish/_state.py
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
from typing import Callable
|
||||
|
||||
from typish import T
|
||||
|
||||
|
||||
class State:
|
||||
"""
|
||||
A class which instances hold any state that may be used by typish.
|
||||
"""
|
||||
def __init__(self) -> None:
|
||||
"""
|
||||
Constructor.
|
||||
"""
|
||||
self.get_type_per_cls = {}
|
||||
|
||||
def register_get_type(
|
||||
self,
|
||||
cls: T,
|
||||
get_type_function: Callable[[T], type]) -> None:
|
||||
"""
|
||||
Register a callable for some type that is to be used when calling
|
||||
typish.get_type.
|
||||
:param cls: the type for which that given callable is to be called.
|
||||
:param get_type_function: the callable to call for that type.
|
||||
:return: None.
|
||||
"""
|
||||
self.get_type_per_cls[cls] = get_type_function
|
||||
|
||||
|
||||
DEFAULT = State()
|
||||
|
||||
|
||||
def register_get_type(
|
||||
cls: T,
|
||||
get_type_function: Callable[[T], type],
|
||||
state: State = DEFAULT) -> None:
|
||||
"""
|
||||
Register a callable for some type that is to be used when calling
|
||||
typish.get_type.
|
||||
:param cls: the type for which that given callable is to be called.
|
||||
:param get_type_function: the callable to call for that type.
|
||||
:param state: any state that is used by typish.
|
||||
:return: None.
|
||||
"""
|
||||
state.register_get_type(cls, get_type_function)
|
||||
18
.CondaPkg/env/lib/python3.11/site-packages/typish/_types.py
vendored
Normal file
18
.CondaPkg/env/lib/python3.11/site-packages/typish/_types.py
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
"""
|
||||
PRIVATE MODULE: do not import (from) it directly.
|
||||
|
||||
This module contains types that are not available by default.
|
||||
"""
|
||||
import typing
|
||||
from inspect import Parameter
|
||||
|
||||
|
||||
T = typing.TypeVar('T')
|
||||
KT = typing.TypeVar('KT')
|
||||
VT = typing.TypeVar('VT')
|
||||
Empty = Parameter.empty
|
||||
Unknown = type('Unknown', (Empty, ), {})
|
||||
Module = type(typing)
|
||||
NoneType = type(None)
|
||||
Ellipsis_ = type(...) # Use EllipsisType instead.
|
||||
EllipsisType = type(...)
|
||||
0
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/__init__.py
vendored
Normal file
0
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/__init__.py
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/__pycache__/_cls_dict.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/__pycache__/_cls_dict.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/__pycache__/_cls_function.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/__pycache__/_cls_function.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/__pycache__/_literal.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/__pycache__/_literal.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/__pycache__/_something.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/__pycache__/_something.cpython-311.pyc
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/__pycache__/_union_type.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/__pycache__/_union_type.cpython-311.pyc
vendored
Normal file
Binary file not shown.
49
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/_cls_dict.py
vendored
Normal file
49
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/_cls_dict.py
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
from collections import OrderedDict
|
||||
from typing import Optional, Any
|
||||
|
||||
|
||||
class ClsDict(OrderedDict):
|
||||
"""
|
||||
ClsDict is a dict that accepts (only) types as keys and will return its
|
||||
values depending on instance checks rather than equality checks.
|
||||
"""
|
||||
def __new__(cls, *args, **kwargs):
|
||||
"""
|
||||
Construct a new instance of ``ClsDict``.
|
||||
:param args: a dict.
|
||||
:param kwargs: any kwargs that ``dict`` accepts.
|
||||
:return: a ``ClsDict``.
|
||||
"""
|
||||
from typish.functions._is_type_annotation import is_type_annotation
|
||||
|
||||
if len(args) > 1:
|
||||
raise TypeError('TypeDict accepts only one positional argument, '
|
||||
'which must be a dict.')
|
||||
if args and not isinstance(args[0], dict):
|
||||
raise TypeError('TypeDict accepts only a dict as positional '
|
||||
'argument.')
|
||||
if not all([is_type_annotation(key) for key in args[0]]):
|
||||
raise TypeError('The given dict must only hold types as keys.')
|
||||
return super().__new__(cls, args[0], **kwargs)
|
||||
|
||||
def __getitem__(self, item: Any) -> Any:
|
||||
"""
|
||||
Return the value of the first encounter of a key for which
|
||||
``is_instance(item, key)`` holds ``True``.
|
||||
:param item: any item.
|
||||
:return: the value of which the type corresponds with item.
|
||||
"""
|
||||
from typish.functions._get_type import get_type
|
||||
from typish.functions._subclass_of import subclass_of
|
||||
|
||||
item_type = get_type(item, use_union=True)
|
||||
for key, value in self.items():
|
||||
if subclass_of(item_type, key):
|
||||
return value
|
||||
raise KeyError('No match for {}'.format(item))
|
||||
|
||||
def get(self, item: Any, default: Any = None) -> Optional[Any]:
|
||||
try:
|
||||
return self.__getitem__(item)
|
||||
except KeyError:
|
||||
return default
|
||||
71
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/_cls_function.py
vendored
Normal file
71
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/_cls_function.py
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
import inspect
|
||||
from collections import OrderedDict
|
||||
from typing import Callable, Any, Union, Iterable, Dict, Tuple
|
||||
|
||||
from typish._types import Empty
|
||||
from typish.classes._cls_dict import ClsDict
|
||||
|
||||
|
||||
class ClsFunction:
|
||||
"""
|
||||
ClsDict is a callable that takes a ClsDict or a dict. When called, it uses
|
||||
the first argument to check for the right function in its body, executes it
|
||||
and returns the result.
|
||||
"""
|
||||
def __init__(self, body: Union[ClsDict,
|
||||
Dict[type, Callable],
|
||||
Iterable[Tuple[type, Callable]],
|
||||
Iterable[Callable]]):
|
||||
from typish.functions._instance_of import instance_of
|
||||
|
||||
if isinstance(body, ClsDict):
|
||||
self.body = body
|
||||
elif isinstance(body, dict):
|
||||
self.body = ClsDict(body)
|
||||
elif instance_of(body, Iterable[Callable]):
|
||||
list_of_tuples = []
|
||||
for func in body:
|
||||
signature = inspect.signature(func)
|
||||
params = list(signature.parameters.keys())
|
||||
if not params:
|
||||
raise TypeError('ClsFunction expects callables that take '
|
||||
'at least one parameter, {} does not.'
|
||||
.format(func.__name__))
|
||||
first_param = signature.parameters[params[0]]
|
||||
hint = first_param.annotation
|
||||
key = Any if hint == Empty else hint
|
||||
list_of_tuples.append((key, func))
|
||||
self.body = ClsDict(OrderedDict(list_of_tuples))
|
||||
elif instance_of(body, Iterable[Tuple[type, Callable]]):
|
||||
self.body = ClsDict(OrderedDict(body))
|
||||
else:
|
||||
raise TypeError('ClsFunction expects a ClsDict or a dict that can '
|
||||
'be turned to a ClsDict or an iterable of '
|
||||
'callables.')
|
||||
|
||||
if not all(isinstance(value, Callable) for value in self.body.values()):
|
||||
raise TypeError('ClsFunction expects a dict or ClsDict with only '
|
||||
'callables as values.')
|
||||
|
||||
def understands(self, item: Any) -> bool:
|
||||
"""
|
||||
Check to see if this ClsFunction can take item.
|
||||
:param item: the item that is checked.
|
||||
:return: True if this ClsFunction can take item.
|
||||
"""
|
||||
try:
|
||||
self.body[item]
|
||||
return True
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
if not args:
|
||||
raise TypeError('ClsFunction must be called with at least 1 '
|
||||
'positional argument.')
|
||||
callable_ = self.body[args[0]]
|
||||
try:
|
||||
return callable_(*args, **kwargs)
|
||||
except TypeError as err:
|
||||
raise TypeError('Unable to call function for \'{}\': {}'
|
||||
.format(args[0], err.args[0]))
|
||||
74
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/_literal.py
vendored
Normal file
74
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/_literal.py
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
import typing
|
||||
|
||||
from typish.classes._subscriptable_type import SubscriptableType
|
||||
|
||||
|
||||
def is_literal_type(cls: typing.Any) -> bool:
|
||||
"""
|
||||
Return whether cls is a Literal type.
|
||||
:param cls: the type that is to be checked.
|
||||
:return: True if cls is a Literal type.
|
||||
"""
|
||||
from typish.functions._get_simple_name import get_simple_name
|
||||
|
||||
return get_simple_name(cls) == 'Literal'
|
||||
|
||||
|
||||
class _LiteralMeta(SubscriptableType):
|
||||
"""
|
||||
A Metaclass that exists to serve Literal and alter the __args__ attribute.
|
||||
"""
|
||||
def __getattribute__(cls, item):
|
||||
"""
|
||||
This method makes sure that __args__ is a tuple, like with
|
||||
typing.Literal.
|
||||
:param item: the name of the attribute that is obtained.
|
||||
:return: the attribute.
|
||||
"""
|
||||
if item == '__args__':
|
||||
try:
|
||||
result = SubscriptableType.__getattribute__(cls, item)
|
||||
if (result and isinstance(result, tuple)
|
||||
and isinstance(result[0], tuple)):
|
||||
result = result[0] # result was a tuple in a tuple.
|
||||
if result and not isinstance(result, tuple):
|
||||
result = (result,)
|
||||
except AttributeError: # pragma: no cover
|
||||
# In case of Python 3.5
|
||||
result = tuple()
|
||||
elif item in ('__origin__', '__name__', '_name'):
|
||||
result = 'Literal'
|
||||
else:
|
||||
result = SubscriptableType.__getattribute__(cls, item)
|
||||
return result
|
||||
|
||||
def __instancecheck__(self, instance):
|
||||
return self.__args__ and instance in self.__args__
|
||||
|
||||
def __str__(self):
|
||||
args = ', '.join(str(arg) for arg in self.__args__)
|
||||
return '{}[{}]'.format(self.__name__, args)
|
||||
|
||||
def __subclasscheck__(self, subclass: typing.Any) -> bool:
|
||||
return is_literal_type(subclass)
|
||||
|
||||
|
||||
class LiteralAlias(type, metaclass=_LiteralMeta):
|
||||
"""
|
||||
This is a backwards compatible variant of typing.Literal (Python 3.8+).
|
||||
"""
|
||||
@staticmethod
|
||||
def from_literal(literal: typing.Any) -> typing.Type['LiteralAlias']:
|
||||
"""
|
||||
Create a LiteralAlias from the given typing.Literal.
|
||||
:param literal: the typing.Literal type.
|
||||
:return: a LiteralAlias type.
|
||||
"""
|
||||
from typish.functions._get_args import get_args
|
||||
|
||||
args = get_args(literal)
|
||||
return LiteralAlias[args] if args else LiteralAlias
|
||||
|
||||
|
||||
# If Literal is available (Python 3.8+), then return that type instead.
|
||||
Literal = getattr(typing, 'Literal', LiteralAlias)
|
||||
122
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/_something.py
vendored
Normal file
122
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/_something.py
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
import types
|
||||
from collections import OrderedDict
|
||||
from typing import Any, Dict, Callable, Tuple
|
||||
|
||||
from typish.classes._subscriptable_type import SubscriptableType
|
||||
|
||||
|
||||
class _SomethingMeta(SubscriptableType):
|
||||
"""
|
||||
This metaclass is coupled to ``Something``.
|
||||
"""
|
||||
def __instancecheck__(self, instance: object) -> bool:
|
||||
# Check if all attributes from self.signature are also present in
|
||||
# instance and also check that their types correspond.
|
||||
from typish.functions._instance_of import instance_of
|
||||
|
||||
sig = self.signature()
|
||||
for key in sig:
|
||||
attr = getattr(instance, key, None)
|
||||
if not attr or not instance_of(attr, sig[key]):
|
||||
return False
|
||||
return True
|
||||
|
||||
def __subclasscheck__(self, subclass: type) -> bool:
|
||||
# If an instance of type subclass is an instance of self, then subclass
|
||||
# is a sub class of self.
|
||||
from typish.functions._subclass_of import subclass_of
|
||||
from typish.functions._get_type_hints_of_callable import get_args_and_return_type
|
||||
|
||||
self_sig = self.signature()
|
||||
other_sig = Something.like(subclass).signature()
|
||||
for attr in self_sig:
|
||||
if attr in other_sig:
|
||||
attr_sig = other_sig[attr]
|
||||
if (not isinstance(subclass.__dict__[attr], staticmethod)
|
||||
and not isinstance(subclass.__dict__[attr], classmethod)
|
||||
and subclass_of(attr_sig, Callable)):
|
||||
# The attr must be a regular method or class method, so the
|
||||
# first parameter should be ignored.
|
||||
args, rt = get_args_and_return_type(attr_sig)
|
||||
attr_sig = Callable[list(args[1:]), rt]
|
||||
if not subclass_of(attr_sig, self_sig[attr]):
|
||||
return False
|
||||
return True
|
||||
|
||||
def __eq__(self, other: 'Something') -> bool:
|
||||
return (isinstance(other, _SomethingMeta)
|
||||
and self.signature() == other.signature())
|
||||
|
||||
def __repr__(self):
|
||||
sig = self.signature()
|
||||
sig_ = ', '.join(["'{}': {}".format(k, self._type_repr(sig[k]))
|
||||
for k in sig])
|
||||
return 'typish.Something[{}]'.format(sig_)
|
||||
|
||||
def __hash__(self):
|
||||
# This explicit super call is required for Python 3.5 and 3.6.
|
||||
return super.__hash__(self)
|
||||
|
||||
def _type_repr(self, obj):
|
||||
"""Return the repr() of an object, special-casing types (internal helper).
|
||||
|
||||
If obj is a type, we return a shorter version than the default
|
||||
type.__repr__, based on the module and qualified name, which is
|
||||
typically enough to uniquely identify a type. For everything
|
||||
else, we fall back on repr(obj).
|
||||
"""
|
||||
if isinstance(obj, type) and not issubclass(obj, Callable):
|
||||
return obj.__qualname__
|
||||
if obj is ...:
|
||||
return '...'
|
||||
if isinstance(obj, types.FunctionType):
|
||||
return obj.__name__
|
||||
return repr(obj)
|
||||
|
||||
|
||||
class Something(type, metaclass=_SomethingMeta):
|
||||
"""
|
||||
This class allows one to define an interface for something that has some
|
||||
attributes, such as objects or classes or maybe even modules.
|
||||
"""
|
||||
@classmethod
|
||||
def signature(mcs) -> Dict[str, type]:
|
||||
"""
|
||||
Return the signature of this ``Something`` as a dict.
|
||||
:return: a dict with attribute names as keys and types as values.
|
||||
"""
|
||||
result = OrderedDict()
|
||||
args = mcs.__args__
|
||||
if isinstance(mcs.__args__, slice):
|
||||
args = (mcs.__args__,)
|
||||
|
||||
arg_keys = sorted(args)
|
||||
if isinstance(mcs.__args__, dict):
|
||||
for key in arg_keys:
|
||||
result[key] = mcs.__args__[key]
|
||||
else:
|
||||
for slice_ in arg_keys:
|
||||
result[slice_.start] = slice_.stop
|
||||
return result
|
||||
|
||||
def __getattr__(cls, item):
|
||||
# This method exists solely to fool the IDE into believing that
|
||||
# Something can have any attribute.
|
||||
return type.__getattr__(cls, item) # pragma: no cover
|
||||
|
||||
@staticmethod
|
||||
def like(obj: Any, exclude_privates: bool = True) -> 'Something':
|
||||
"""
|
||||
Return a ``Something`` for the given ``obj``.
|
||||
:param obj: the object of which a ``Something`` is to be made.
|
||||
:param exclude_privates: if ``True``, private variables are excluded.
|
||||
:return: a ``Something`` that corresponds to ``obj``.
|
||||
"""
|
||||
from typish.functions._get_type import get_type
|
||||
|
||||
signature = {attr: get_type(getattr(obj, attr)) for attr in dir(obj)
|
||||
if not exclude_privates or not attr.startswith('_')}
|
||||
return Something[signature]
|
||||
|
||||
|
||||
TypingType = Something['__origin__': type, '__args__': Tuple[type, ...]]
|
||||
50
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/_subscriptable_type.py
vendored
Normal file
50
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/_subscriptable_type.py
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
class _SubscribedType(type):
|
||||
"""
|
||||
This class is a placeholder to let the IDE know the attributes of the
|
||||
returned type after a __getitem__.
|
||||
"""
|
||||
__origin__ = None
|
||||
__args__ = None
|
||||
|
||||
|
||||
class SubscriptableType(type):
|
||||
"""
|
||||
This metaclass will allow a type to become subscriptable.
|
||||
|
||||
>>> class SomeType(metaclass=SubscriptableType):
|
||||
... pass
|
||||
>>> SomeTypeSub = SomeType['some args']
|
||||
>>> SomeTypeSub.__args__
|
||||
'some args'
|
||||
>>> SomeTypeSub.__origin__.__name__
|
||||
'SomeType'
|
||||
"""
|
||||
def __init_subclass__(mcs, **kwargs):
|
||||
mcs._hash = None
|
||||
mcs.__args__ = None
|
||||
mcs.__origin__ = None
|
||||
|
||||
def __getitem__(self, item) -> _SubscribedType:
|
||||
body = {
|
||||
**self.__dict__,
|
||||
'__args__': item,
|
||||
'__origin__': self,
|
||||
}
|
||||
bases = self, *self.__bases__
|
||||
result = type(self.__name__, bases, body)
|
||||
if hasattr(result, '_after_subscription'):
|
||||
# TODO check if _after_subscription is static
|
||||
result._after_subscription(item)
|
||||
return result
|
||||
|
||||
def __eq__(self, other):
|
||||
self_args = getattr(self, '__args__', None)
|
||||
self_origin = getattr(self, '__origin__', None)
|
||||
other_args = getattr(other, '__args__', None)
|
||||
other_origin = getattr(other, '__origin__', None)
|
||||
return self_args == other_args and self_origin == other_origin
|
||||
|
||||
def __hash__(self):
|
||||
if not getattr(self, '_hash', None):
|
||||
self._hash = hash('{}{}'.format(self.__origin__, self.__args__))
|
||||
return self._hash
|
||||
7
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/_union_type.py
vendored
Normal file
7
.CondaPkg/env/lib/python3.11/site-packages/typish/classes/_union_type.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
class _UnionType(type):
|
||||
def __instancecheck__(self, instance):
|
||||
return str(instance).startswith('typing.Union')
|
||||
|
||||
|
||||
class UnionType(type, metaclass=_UnionType):
|
||||
...
|
||||
0
.CondaPkg/env/lib/python3.11/site-packages/typish/decorators/__init__.py
vendored
Normal file
0
.CondaPkg/env/lib/python3.11/site-packages/typish/decorators/__init__.py
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/decorators/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/decorators/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/decorators/__pycache__/_hintable.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/decorators/__pycache__/_hintable.cpython-311.pyc
vendored
Normal file
Binary file not shown.
109
.CondaPkg/env/lib/python3.11/site-packages/typish/decorators/_hintable.py
vendored
Normal file
109
.CondaPkg/env/lib/python3.11/site-packages/typish/decorators/_hintable.py
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
import inspect
|
||||
import re
|
||||
from functools import wraps
|
||||
from typing import Dict, Optional, Callable, List
|
||||
|
||||
_DEFAULT_PARAM_NAME = 'hint'
|
||||
|
||||
|
||||
class _Hintable:
|
||||
_hints_per_frame = {}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
decorated: Callable,
|
||||
param: str,
|
||||
stack_index: int) -> None:
|
||||
self._decorated = decorated
|
||||
self._param = param
|
||||
self._stack_index = stack_index
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
stack = inspect.stack()
|
||||
|
||||
previous_frame = stack[self._stack_index]
|
||||
frame_id = id(previous_frame.frame)
|
||||
|
||||
if not self._hints_per_frame.get(frame_id):
|
||||
code_context = previous_frame.code_context[0].strip()
|
||||
hint_strs = self._extract_hints(code_context)
|
||||
globals_ = previous_frame.frame.f_globals
|
||||
# Store the type hint if any, otherwise the string, otherwise None.
|
||||
hints = [self._to_cls(hint_str, globals_) or hint_str or None
|
||||
for hint_str in hint_strs]
|
||||
self._hints_per_frame[frame_id] = hints
|
||||
|
||||
hint = (self._hints_per_frame.get(frame_id) or [None]).pop()
|
||||
|
||||
kwargs_ = {**kwargs, self._param: kwargs.get(self._param, hint)}
|
||||
return self._decorated(*args, **kwargs_)
|
||||
|
||||
def _extract_hints(self, code_context: str) -> List[str]:
|
||||
result = []
|
||||
regex = (
|
||||
r'.+?(:(.+?))?=\s*' # e.g. 'x: int = ', $2 holds hint
|
||||
r'.*?{}\s*\(.*?\)\s*' # e.g. 'func(...) '
|
||||
r'(#\s*type\s*:\s*(\w+))?\s*' # e.g. '# type: int ', $4 holds hint
|
||||
).format(self._decorated.__name__)
|
||||
|
||||
# Find all matches and store them (reversed) in the resulting list.
|
||||
for _, group2, _, group4 in re.findall(regex, code_context):
|
||||
raw_hint = (group2 or group4).strip()
|
||||
if self._is_between(raw_hint, '\'') or self._is_between(raw_hint, '"'):
|
||||
# Remove any quotes that surround the hint.
|
||||
raw_hint = raw_hint[1:-1].strip()
|
||||
result.insert(0, raw_hint)
|
||||
|
||||
return result
|
||||
|
||||
def _is_between(self, subject: str, character: str) -> bool:
|
||||
return subject.startswith(character) and subject.endswith(character)
|
||||
|
||||
def _to_cls(self, hint: str, f_globals: Dict[str, type]) -> Optional[type]:
|
||||
return __builtins__.get(hint, f_globals.get(hint))
|
||||
|
||||
|
||||
def _get_wrapper(decorated, param: str, stack_index: int):
|
||||
@wraps(decorated)
|
||||
def _wrapper(*args, **kwargs):
|
||||
return _Hintable(decorated, param, stack_index)(*args, **kwargs)
|
||||
|
||||
if isinstance(decorated, type):
|
||||
raise TypeError('Only functions and methods should be decorated with '
|
||||
'\'hintable\', not classes.')
|
||||
|
||||
if param not in inspect.signature(decorated).parameters:
|
||||
raise TypeError('The decorated \'{}\' must accept a parameter with '
|
||||
'the name \'{}\'.'
|
||||
.format(decorated.__name__, param))
|
||||
|
||||
return _wrapper
|
||||
|
||||
|
||||
def hintable(decorated=None, *, param: str = _DEFAULT_PARAM_NAME) -> Callable:
|
||||
"""
|
||||
Allow a function or method to receive the type hint of a receiving
|
||||
variable.
|
||||
|
||||
Example:
|
||||
|
||||
>>> @hintable
|
||||
... def cast(value, hint):
|
||||
... return hint(value)
|
||||
>>> x: int = cast('42')
|
||||
42
|
||||
|
||||
Use this decorator wisely. If a variable was hinted with a type (e.g. int
|
||||
in the above example), your function should return a value of that type
|
||||
(in the above example, that would be an int value).
|
||||
|
||||
:param decorated: a function or method.
|
||||
:param param: the name of the parameter that receives the type hint.
|
||||
:return: the decorated function/method wrapped into a new function.
|
||||
"""
|
||||
if decorated is not None:
|
||||
wrapper = _get_wrapper(decorated, param, 2)
|
||||
else:
|
||||
wrapper = lambda decorated_: _get_wrapper(decorated_, param, 2)
|
||||
|
||||
return wrapper
|
||||
0
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/__init__.py
vendored
Normal file
0
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/__init__.py
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/__pycache__/_get_alias.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/__pycache__/_get_alias.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/__pycache__/_get_args.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/__pycache__/_get_args.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/__pycache__/_get_mro.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/__pycache__/_get_mro.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/__pycache__/_get_origin.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/__pycache__/_get_origin.cpython-311.pyc
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/__pycache__/_get_type.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/__pycache__/_get_type.cpython-311.pyc
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/__pycache__/_instance_of.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/__pycache__/_instance_of.cpython-311.pyc
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/__pycache__/_subclass_of.cpython-311.pyc
vendored
Normal file
BIN
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/__pycache__/_subclass_of.cpython-311.pyc
vendored
Normal file
Binary file not shown.
36
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_common_ancestor.py
vendored
Normal file
36
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_common_ancestor.py
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
import typing
|
||||
|
||||
|
||||
def common_ancestor(*args: object) -> type:
|
||||
"""
|
||||
Get the closest common ancestor of the given objects.
|
||||
:param args: any objects.
|
||||
:return: the ``type`` of the closest common ancestor of the given ``args``.
|
||||
"""
|
||||
return _common_ancestor(args, False)
|
||||
|
||||
|
||||
def common_ancestor_of_types(*args: type) -> type:
|
||||
"""
|
||||
Get the closest common ancestor of the given classes.
|
||||
:param args: any classes.
|
||||
:return: the ``type`` of the closest common ancestor of the given ``args``.
|
||||
"""
|
||||
return _common_ancestor(args, True)
|
||||
|
||||
|
||||
def _common_ancestor(args: typing.Sequence[object], types: bool) -> type:
|
||||
from typish.functions._get_type import get_type
|
||||
from typish.functions._get_mro import get_mro
|
||||
|
||||
if len(args) < 1:
|
||||
raise TypeError('common_ancestor() requires at least 1 argument')
|
||||
tmap = (lambda x: x) if types else get_type
|
||||
mros = [get_mro(tmap(elem)) for elem in args]
|
||||
for cls in mros[0]:
|
||||
for mro in mros:
|
||||
if cls not in mro:
|
||||
break
|
||||
else:
|
||||
# cls is in every mro; a common ancestor is found!
|
||||
return cls
|
||||
40
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_get_alias.py
vendored
Normal file
40
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_get_alias.py
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
import typing
|
||||
from functools import lru_cache
|
||||
|
||||
from typish.functions._is_from_typing import is_from_typing
|
||||
|
||||
from typish._types import T
|
||||
|
||||
|
||||
@lru_cache()
|
||||
def get_alias(cls: T) -> typing.Optional[T]:
|
||||
"""
|
||||
Return the alias from the ``typing`` module for ``cls``. For example, for
|
||||
``cls=list``, the result would be ``typing.List``. If ``cls`` is
|
||||
parameterized (>=3.9), then a parameterized ``typing`` equivalent is
|
||||
returned. If no alias exists for ``cls``, then ``None`` is returned.
|
||||
If ``cls`` already is from ``typing`` it is returned as is.
|
||||
:param cls: the type for which the ``typing`` equivalent is to be found.
|
||||
:return: the alias from ``typing``.
|
||||
"""
|
||||
if is_from_typing(cls):
|
||||
return cls
|
||||
alias = _alias_per_type.get(cls.__name__, None)
|
||||
if alias:
|
||||
args = getattr(cls, '__args__', tuple())
|
||||
if args:
|
||||
alias = alias[args]
|
||||
return alias
|
||||
|
||||
|
||||
_alias_per_type = {
|
||||
'list': typing.List,
|
||||
'tuple': typing.Tuple,
|
||||
'dict': typing.Dict,
|
||||
'set': typing.Set,
|
||||
'frozenset': typing.FrozenSet,
|
||||
'deque': typing.Deque,
|
||||
'defaultdict': typing.DefaultDict,
|
||||
'type': typing.Type,
|
||||
'Set': typing.AbstractSet,
|
||||
}
|
||||
14
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_get_args.py
vendored
Normal file
14
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_get_args.py
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import typing
|
||||
|
||||
|
||||
def get_args(t: type) -> typing.Tuple[type, ...]:
|
||||
"""
|
||||
Get the arguments from a collection type (e.g. ``typing.List[int]``) as a
|
||||
``tuple``.
|
||||
:param t: the collection type.
|
||||
:return: a ``tuple`` containing types.
|
||||
"""
|
||||
args_ = getattr(t, '__args__', tuple()) or tuple()
|
||||
args = tuple([attr for attr in args_
|
||||
if type(attr) != typing.TypeVar])
|
||||
return args
|
||||
31
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_get_mro.py
vendored
Normal file
31
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_get_mro.py
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
import typing
|
||||
from inspect import getmro
|
||||
|
||||
|
||||
def get_mro(obj: typing.Any) -> typing.Tuple[type, ...]:
|
||||
"""
|
||||
Return tuple of base classes (including that of obj) in method resolution
|
||||
order. Types from typing are supported as well.
|
||||
:param obj: object or type.
|
||||
:return: a tuple of base classes.
|
||||
"""
|
||||
from typish.functions._get_origin import get_origin
|
||||
|
||||
# Wrapper around ``getmro`` to allow types from ``typing``.
|
||||
if obj is ...:
|
||||
return Ellipsis, object
|
||||
elif obj is typing.Union:
|
||||
# For Python <3.7, we cannot use mro.
|
||||
super_cls = getattr(typing, '_GenericAlias',
|
||||
getattr(typing, 'GenericMeta', None))
|
||||
return typing.Union, super_cls, object
|
||||
|
||||
origin = get_origin(obj)
|
||||
if origin != obj:
|
||||
return get_mro(origin)
|
||||
|
||||
cls = obj
|
||||
if not isinstance(obj, type):
|
||||
cls = type(obj)
|
||||
|
||||
return getmro(cls)
|
||||
39
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_get_origin.py
vendored
Normal file
39
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_get_origin.py
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
import typing
|
||||
from collections import deque, defaultdict
|
||||
from collections.abc import Set
|
||||
from inspect import isclass
|
||||
|
||||
from typish.functions._is_from_typing import is_from_typing
|
||||
|
||||
|
||||
def get_origin(t: type) -> type:
|
||||
"""
|
||||
Return the origin of the given (generic) type. For example, for
|
||||
``t=List[str]``, the result would be ``list``.
|
||||
:param t: the type of which the origin is to be found.
|
||||
:return: the origin of ``t`` or ``t`` if it is not generic.
|
||||
"""
|
||||
from typish.functions._get_simple_name import get_simple_name
|
||||
|
||||
simple_name = get_simple_name(t)
|
||||
result = _type_per_alias.get(simple_name, None)
|
||||
if isclass(t) and not is_from_typing(t):
|
||||
# Get the origin in case of a parameterized generic.
|
||||
result = getattr(t, '__origin__', t)
|
||||
elif not result:
|
||||
result = getattr(typing, simple_name, t)
|
||||
return result
|
||||
|
||||
|
||||
_type_per_alias = {
|
||||
'List': list,
|
||||
'Tuple': tuple,
|
||||
'Dict': dict,
|
||||
'Set': set,
|
||||
'FrozenSet': frozenset,
|
||||
'Deque': deque,
|
||||
'DefaultDict': defaultdict,
|
||||
'Type': type,
|
||||
'AbstractSet': Set,
|
||||
'Optional': typing.Union,
|
||||
}
|
||||
17
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_get_simple_name.py
vendored
Normal file
17
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_get_simple_name.py
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
from functools import lru_cache
|
||||
|
||||
from typish._types import NoneType
|
||||
|
||||
|
||||
@lru_cache()
|
||||
def get_simple_name(cls: type) -> str:
|
||||
cls = cls or NoneType
|
||||
cls_name = getattr(cls, '__name__', None)
|
||||
if not cls_name:
|
||||
cls_name = getattr(cls, '_name', None)
|
||||
if not cls_name:
|
||||
cls_name = repr(cls)
|
||||
cls_name = cls_name.split('[')[0] # Remove generic types.
|
||||
cls_name = cls_name.split('.')[-1] # Remove any . caused by repr.
|
||||
cls_name = cls_name.split(r"'>")[0] # Remove any '>.
|
||||
return cls_name
|
||||
140
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_get_type.py
vendored
Normal file
140
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_get_type.py
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
import inspect
|
||||
import types
|
||||
import typing
|
||||
|
||||
from typish._state import DEFAULT, State
|
||||
from typish._types import T, Unknown, KT, NoneType, Empty, VT
|
||||
from typish.classes._union_type import UnionType
|
||||
|
||||
|
||||
def get_type(
|
||||
inst: T,
|
||||
use_union: bool = False,
|
||||
*,
|
||||
state: State = DEFAULT) -> typing.Type[T]:
|
||||
"""
|
||||
Return a type, complete with generics for the given ``inst``.
|
||||
:param inst: the instance for which a type is to be returned.
|
||||
:param use_union: if ``True``, the resulting type can contain a union.
|
||||
:param state: any state that is used by typish.
|
||||
:return: the type of ``inst``.
|
||||
"""
|
||||
|
||||
get_type_for_inst = state.get_type_per_cls.get(type(inst))
|
||||
if get_type_for_inst:
|
||||
return get_type_for_inst(inst)
|
||||
|
||||
if inst is typing.Any:
|
||||
return typing.Any
|
||||
|
||||
if isinstance(inst, UnionType):
|
||||
return UnionType
|
||||
|
||||
result = type(inst)
|
||||
super_types = [
|
||||
(dict, _get_type_dict),
|
||||
(tuple, _get_type_tuple),
|
||||
(str, lambda inst_, _, __: result),
|
||||
(typing.Iterable, _get_type_iterable),
|
||||
(types.FunctionType, _get_type_callable),
|
||||
(types.MethodType, _get_type_callable),
|
||||
(type, lambda inst_, _, __: typing.Type[inst]),
|
||||
]
|
||||
|
||||
try:
|
||||
for super_type, func in super_types:
|
||||
if isinstance(inst, super_type):
|
||||
result = func(inst, use_union, state)
|
||||
break
|
||||
except Exception:
|
||||
# If anything went wrong, return the regular type.
|
||||
# This is to support 3rd party libraries.
|
||||
return type(inst)
|
||||
return result
|
||||
|
||||
|
||||
def _get_type_iterable(
|
||||
inst: typing.Iterable,
|
||||
use_union: bool,
|
||||
state: State) -> type:
|
||||
from typish.functions._get_alias import get_alias
|
||||
from typish.functions._common_ancestor import common_ancestor
|
||||
|
||||
typing_type = get_alias(type(inst))
|
||||
common_cls = Unknown
|
||||
if inst:
|
||||
if use_union:
|
||||
types = [get_type(elem, state=state) for elem in inst]
|
||||
common_cls = typing.Union[tuple(types)]
|
||||
else:
|
||||
common_cls = common_ancestor(*inst)
|
||||
if typing_type:
|
||||
if issubclass(common_cls, typing.Iterable) and typing_type is not str:
|
||||
# Get to the bottom of it; obtain types recursively.
|
||||
common_cls = get_type(common_cls(_flatten(inst)), state=state)
|
||||
result = typing_type[common_cls]
|
||||
return result
|
||||
|
||||
|
||||
def _get_type_tuple(
|
||||
inst: tuple,
|
||||
use_union: bool,
|
||||
state: State) -> typing.Dict[KT, VT]:
|
||||
args = [get_type(elem, state) for elem in inst]
|
||||
return typing.Tuple[tuple(args)]
|
||||
|
||||
|
||||
def _get_type_callable(
|
||||
inst: typing.Callable,
|
||||
use_union: bool,
|
||||
state: State) -> typing.Type[typing.Dict[KT, VT]]:
|
||||
if 'lambda' in str(inst):
|
||||
result = _get_type_lambda(inst, use_union, state)
|
||||
else:
|
||||
result = typing.Callable
|
||||
sig = inspect.signature(inst)
|
||||
args = [_map_empty(param.annotation)
|
||||
for param in sig.parameters.values()]
|
||||
return_type = NoneType
|
||||
if sig.return_annotation != Empty:
|
||||
return_type = sig.return_annotation
|
||||
if args or return_type != NoneType:
|
||||
if inspect.iscoroutinefunction(inst):
|
||||
return_type = typing.Awaitable[return_type]
|
||||
result = typing.Callable[args, return_type]
|
||||
return result
|
||||
|
||||
|
||||
def _get_type_lambda(
|
||||
inst: typing.Callable,
|
||||
use_union: bool,
|
||||
state: State) -> typing.Type[typing.Dict[KT, VT]]:
|
||||
args = [Unknown for _ in inspect.signature(inst).parameters]
|
||||
return_type = Unknown
|
||||
return typing.Callable[args, return_type]
|
||||
|
||||
|
||||
def _get_type_dict(inst: typing.Dict[KT, VT],
|
||||
use_union: bool,
|
||||
state: State) -> typing.Type[typing.Dict[KT, VT]]:
|
||||
from typish.functions._get_args import get_args
|
||||
|
||||
t_list_k = _get_type_iterable(list(inst.keys()), use_union, state)
|
||||
t_list_v = _get_type_iterable(list(inst.values()), use_union, state)
|
||||
t_k_tuple = get_args(t_list_k)
|
||||
t_v_tuple = get_args(t_list_v)
|
||||
return typing.Dict[t_k_tuple[0], t_v_tuple[0]]
|
||||
|
||||
|
||||
def _flatten(l: typing.Iterable[typing.Iterable[typing.Any]]) -> typing.List[typing.Any]:
|
||||
result = []
|
||||
for x in l:
|
||||
result += [*x]
|
||||
return result
|
||||
|
||||
|
||||
def _map_empty(annotation: type) -> type:
|
||||
result = annotation
|
||||
if annotation == Empty:
|
||||
result = typing.Any
|
||||
return result
|
||||
50
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_get_type_hints_of_callable.py
vendored
Normal file
50
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_get_type_hints_of_callable.py
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
import typing
|
||||
|
||||
|
||||
def get_type_hints_of_callable(
|
||||
func: typing.Callable) -> typing.Dict[str, type]:
|
||||
"""
|
||||
Return the type hints of the parameters of the given callable.
|
||||
:param func: the callable of which the type hints are to be returned.
|
||||
:return: a dict with parameter names and their types.
|
||||
"""
|
||||
# Python3.5: get_type_hints raises on classes without explicit constructor
|
||||
try:
|
||||
result = typing.get_type_hints(func)
|
||||
except AttributeError:
|
||||
result = {}
|
||||
return result
|
||||
|
||||
|
||||
def get_args_and_return_type(hint: typing.Type[typing.Callable]) \
|
||||
-> typing.Tuple[typing.Optional[typing.Tuple[type]], typing.Optional[type]]:
|
||||
"""
|
||||
Get the argument types and the return type of a callable type hint
|
||||
(e.g. ``Callable[[int], str]``).
|
||||
|
||||
Example:
|
||||
```
|
||||
arg_types, return_type = get_args_and_return_type(Callable[[int], str])
|
||||
# args_types is (int, )
|
||||
# return_type is str
|
||||
```
|
||||
|
||||
Example for when ``hint`` has no generics:
|
||||
```
|
||||
arg_types, return_type = get_args_and_return_type(Callable)
|
||||
# args_types is None
|
||||
# return_type is None
|
||||
```
|
||||
:param hint: the callable type hint.
|
||||
:return: a tuple of the argument types (as a tuple) and the return type.
|
||||
"""
|
||||
if hint in (callable, typing.Callable):
|
||||
arg_types = None
|
||||
return_type = None
|
||||
elif hasattr(hint, '__result__'):
|
||||
arg_types = hint.__args__
|
||||
return_type = hint.__result__
|
||||
else:
|
||||
arg_types = hint.__args__[0:-1]
|
||||
return_type = hint.__args__[-1]
|
||||
return arg_types, return_type
|
||||
35
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_instance_of.py
vendored
Normal file
35
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_instance_of.py
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
from typish._state import DEFAULT, State
|
||||
|
||||
|
||||
def instance_of(obj: object, *args: object, state: State = DEFAULT) -> bool:
|
||||
"""
|
||||
Check whether ``obj`` is an instance of all types in ``args``, while also
|
||||
considering generics.
|
||||
|
||||
If you want the instance check to be customized for your type, then make
|
||||
sure it has a __instancecheck__ defined (not in a base class). You will
|
||||
also need to register the get_type function by calling
|
||||
typish.register_get_type with that particular type and a handling callable.
|
||||
:param obj: the object in subject.
|
||||
:param args: the type(s) of which ``obj`` is an instance or not.
|
||||
:param state: any state that is used by typish.
|
||||
:return: ``True`` if ``obj`` is an instance of all types in ``args``.
|
||||
"""
|
||||
return all(_instance_of(obj, clsinfo, state) for clsinfo in args)
|
||||
|
||||
|
||||
def _instance_of(obj: object, clsinfo: object, state: State = DEFAULT) -> bool:
|
||||
from typish.classes._literal import LiteralAlias, is_literal_type
|
||||
from typish.functions._subclass_of import subclass_of
|
||||
from typish.functions._get_type import get_type
|
||||
from typish.functions._is_from_typing import is_from_typing
|
||||
|
||||
if not is_from_typing(clsinfo) and '__instancecheck__' in dir(clsinfo):
|
||||
return isinstance(obj, clsinfo)
|
||||
|
||||
if is_literal_type(clsinfo):
|
||||
alias = LiteralAlias.from_literal(clsinfo)
|
||||
return isinstance(obj, alias)
|
||||
|
||||
type_ = get_type(obj, use_union=True, state=state)
|
||||
return subclass_of(type_, clsinfo)
|
||||
10
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_is_from_typing.py
vendored
Normal file
10
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_is_from_typing.py
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import typing
|
||||
|
||||
|
||||
def is_from_typing(cls: type) -> bool:
|
||||
"""
|
||||
Return True if the given class is from the typing module.
|
||||
:param cls: a type.
|
||||
:return: True if cls is from typing.
|
||||
"""
|
||||
return cls.__module__ == typing.__name__
|
||||
23
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_is_optional_type.py
vendored
Normal file
23
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_is_optional_type.py
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
import typing
|
||||
|
||||
from typish import get_origin, get_args, NoneType
|
||||
|
||||
|
||||
def is_optional_type(cls: type) -> bool:
|
||||
"""
|
||||
Return True if the given class is an optional type. A type is considered to
|
||||
be optional if it allows ``None`` as value.
|
||||
|
||||
Example:
|
||||
|
||||
is_optional_type(Optional[str]) # True
|
||||
is_optional_type(Union[str, int, None]) # True
|
||||
is_optional_type(str) # False
|
||||
is_optional_type(Union[str, int]) # False
|
||||
|
||||
:param cls: a type.
|
||||
:return: True if cls is an optional type.
|
||||
"""
|
||||
origin = get_origin(cls)
|
||||
args = get_args(cls)
|
||||
return origin == typing.Union and NoneType in args
|
||||
24
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_is_type_annotation.py
vendored
Normal file
24
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_is_type_annotation.py
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
import typing
|
||||
|
||||
from typish.classes._union_type import UnionType
|
||||
|
||||
|
||||
def is_type_annotation(item: typing.Any) -> bool:
|
||||
"""
|
||||
Return whether item is a type annotation (a ``type`` or a type from
|
||||
``typing``, such as ``List``).
|
||||
:param item: the item in question.
|
||||
:return: ``True`` is ``item`` is a type annotation.
|
||||
"""
|
||||
from typish.functions._instance_of import instance_of
|
||||
|
||||
# Use _GenericAlias for Python 3.7+ and use GenericMeta for the rest.
|
||||
super_cls = getattr(typing, '_GenericAlias',
|
||||
getattr(typing, 'GenericMeta', None))
|
||||
|
||||
return not isinstance(item, typing.TypeVar) and (
|
||||
item is typing.Any
|
||||
or instance_of(item, type)
|
||||
or instance_of(item, super_cls)
|
||||
or getattr(item, '__module__', None) == 'typing'
|
||||
or isinstance(item, UnionType))
|
||||
158
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_subclass_of.py
vendored
Normal file
158
.CondaPkg/env/lib/python3.11/site-packages/typish/functions/_subclass_of.py
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
import typing
|
||||
|
||||
from typish._types import Unknown
|
||||
from typish.functions._get_alias import get_alias
|
||||
|
||||
|
||||
def subclass_of(cls: object, *args: object) -> bool:
|
||||
"""
|
||||
Return whether ``cls`` is a subclass of all types in ``args`` while also
|
||||
considering generics.
|
||||
|
||||
If you want the subclass check to be customized for your type, then make
|
||||
sure it has a __subclasscheck__ defined (not in a base class).
|
||||
:param cls: the subject.
|
||||
:param args: the super types.
|
||||
:return: True if ``cls`` is a subclass of all types in ``args`` while also
|
||||
considering generics.
|
||||
"""
|
||||
return all(_subclass_of(cls, clsinfo) for clsinfo in args)
|
||||
|
||||
|
||||
def _subclass_of(cls: type, clsinfo: object) -> bool:
|
||||
# Check whether cls is a subtype of clsinfo.
|
||||
from typish.classes._literal import LiteralAlias
|
||||
|
||||
# Translate to typing type if possible.
|
||||
clsinfo = get_alias(clsinfo) or clsinfo
|
||||
|
||||
if _is_true_case(cls, clsinfo):
|
||||
result = True
|
||||
elif issubclass(clsinfo, LiteralAlias):
|
||||
return _check_literal(cls, subclass_of, clsinfo)
|
||||
elif is_issubclass_case(cls, clsinfo):
|
||||
result = issubclass(cls, clsinfo)
|
||||
else:
|
||||
result = _forward_subclass_check(cls, clsinfo)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _forward_subclass_check(cls: type, clsinfo: type) -> bool:
|
||||
# Forward the subclass check for cls and clsinfo to delegates that know how
|
||||
# to check that particular cls/clsinfo type.
|
||||
|
||||
from typish.functions._get_origin import get_origin
|
||||
from typish.functions._get_args import get_args
|
||||
|
||||
clsinfo_origin = get_origin(clsinfo)
|
||||
clsinfo_args = get_args(clsinfo)
|
||||
cls_origin = get_origin(cls)
|
||||
|
||||
if cls_origin is typing.Union:
|
||||
# cls is a Union; all options of that Union must subclass clsinfo.
|
||||
cls_args = get_args(cls)
|
||||
result = all([subclass_of(elem, clsinfo) for elem in cls_args])
|
||||
elif clsinfo_args:
|
||||
result = _subclass_of_generic(cls, clsinfo_origin, clsinfo_args)
|
||||
else:
|
||||
try:
|
||||
result = issubclass(cls_origin, clsinfo_origin)
|
||||
except TypeError:
|
||||
result = False
|
||||
return result
|
||||
|
||||
|
||||
def _subclass_of_generic(
|
||||
cls: type,
|
||||
info_generic_type: type,
|
||||
info_args: typing.Tuple[type, ...]) -> bool:
|
||||
# Check if cls is a subtype of info_generic_type, knowing that the latter
|
||||
# is a generic type.
|
||||
|
||||
from typish.functions._get_origin import get_origin
|
||||
from typish.functions._get_args import get_args
|
||||
|
||||
result = False
|
||||
cls_origin = get_origin(cls)
|
||||
cls_args = get_args(cls)
|
||||
if info_generic_type is tuple:
|
||||
# Special case.
|
||||
result = (subclass_of(cls_origin, tuple)
|
||||
and _subclass_of_tuple(cls_args, info_args))
|
||||
elif info_generic_type is typing.Union:
|
||||
# Another special case.
|
||||
result = any(subclass_of(cls, cls_) for cls_ in info_args)
|
||||
elif cls_origin is tuple and info_generic_type is typing.Iterable:
|
||||
# Another special case.
|
||||
args = _tuple_args(cls_args)
|
||||
|
||||
# Match the number of arguments of info to that of cls.
|
||||
matched_info_args = info_args * len(args)
|
||||
result = _subclass_of_tuple(args, matched_info_args)
|
||||
elif (subclass_of(cls_origin, info_generic_type) and cls_args
|
||||
and len(cls_args) == len(info_args)):
|
||||
result = all(subclass_of(*tup) for tup in zip(cls_args, info_args))
|
||||
# Note that issubtype(list, List[...]) is always False.
|
||||
# Note that the number of arguments must be equal.
|
||||
return result
|
||||
|
||||
|
||||
def _subclass_of_tuple(
|
||||
cls_args: typing.Tuple[type, ...],
|
||||
info_args: typing.Tuple[type, ...]) -> bool:
|
||||
from typish.functions._get_origin import get_origin
|
||||
from typish.functions._common_ancestor import common_ancestor_of_types
|
||||
|
||||
result = False
|
||||
if len(info_args) == 2 and info_args[1] is ...:
|
||||
type_ = get_origin(info_args[0])
|
||||
if type_ is typing.Union:
|
||||
# A heterogeneous tuple: check each element if it subclasses the
|
||||
# union.
|
||||
result = all([subclass_of(elem, info_args[0]) for elem in cls_args])
|
||||
else:
|
||||
result = subclass_of(common_ancestor_of_types(*cls_args), info_args[0])
|
||||
elif len(cls_args) == len(info_args):
|
||||
result = all(subclass_of(c1, c2)
|
||||
for c1, c2 in zip(cls_args, info_args))
|
||||
return result
|
||||
|
||||
|
||||
def _check_literal(obj: object, func: typing.Callable, *args: type) -> bool:
|
||||
# Instance or subclass check for Literal.
|
||||
literal = args[0]
|
||||
leftovers = args[1:]
|
||||
literal_args = getattr(literal, '__args__', None)
|
||||
result = False
|
||||
if literal_args:
|
||||
literal_arg = literal_args[0]
|
||||
result = (obj == literal_arg
|
||||
and (not leftovers or func(obj, *leftovers)))
|
||||
return result
|
||||
|
||||
|
||||
def _is_true_case(cls: type, clsinfo: type) -> bool:
|
||||
# Return whether subclass_of(cls, clsinfo) holds a case that must always be
|
||||
# True, without the need of further checking.
|
||||
return cls == clsinfo or cls is Unknown or clsinfo in (typing.Any, object)
|
||||
|
||||
|
||||
def is_issubclass_case(cls: type, clsinfo: type) -> bool:
|
||||
# Return whether subclass_of(cls, clsinfo) holds a case that can be handled
|
||||
# by the builtin issubclass.
|
||||
from typish.functions._is_from_typing import is_from_typing
|
||||
|
||||
return (not is_from_typing(clsinfo)
|
||||
and isinstance(cls, type)
|
||||
and clsinfo is not type
|
||||
and '__subclasscheck__' in dir(clsinfo))
|
||||
|
||||
|
||||
def _tuple_args(
|
||||
cls_args: typing.Iterable[typing.Any]) -> typing.Iterable[type]:
|
||||
# Get the argument types from a tuple, even if the form is Tuple[int, ...].
|
||||
result = cls_args
|
||||
if len(cls_args) > 1 and cls_args[1] is ...:
|
||||
result = [cls_args[0]]
|
||||
return result
|
||||
Reference in New Issue
Block a user