OXIESEC PANEL
- Current Dir:
/
/
opt
/
alt
/
python311
/
lib
/
python3.11
/
site-packages
/
typish
Server IP: 2a02:4780:11:1084:0:327f:3464:10
Upload:
Create Dir:
Name
Size
Modified
Perms
📁
..
-
09/05/2025 09:34:01 AM
rwxr-xr-x
📄
__init__.py
1.45 KB
05/08/2024 06:42:59 PM
rw-r--r--
📁
__pycache__
-
05/08/2024 06:42:59 PM
rwxr-xr-x
📄
_classes.py
11.35 KB
05/08/2024 06:42:59 PM
rw-r--r--
📄
_decorators.py
734 bytes
05/08/2024 06:42:59 PM
rw-r--r--
📄
_functions.py
15.25 KB
05/08/2024 06:42:59 PM
rw-r--r--
📄
_meta.py
245 bytes
05/08/2024 06:42:59 PM
rw-r--r--
📄
_state.py
1.27 KB
05/08/2024 06:42:59 PM
rw-r--r--
📄
_types.py
446 bytes
05/08/2024 06:42:59 PM
rw-r--r--
📁
classes
-
05/08/2024 06:42:59 PM
rwxr-xr-x
📁
decorators
-
05/08/2024 06:42:59 PM
rwxr-xr-x
📄
effe.py
841 bytes
05/08/2024 06:42:59 PM
rw-r--r--
📁
functions
-
05/08/2024 06:42:59 PM
rwxr-xr-x
Editing: _classes.py
Close
""" PRIVATE MODULE: do not import (from) it directly. This module contains class implementations. """ import inspect import types from collections import OrderedDict from typing import Any, Callable, Dict, Tuple, Optional, Union, List, Iterable from typish._types import Empty from typish._functions import ( get_type, subclass_of, instance_of, get_args_and_return_type, is_type_annotation, ) 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 class _SomethingMeta(SubscriptableType): """ This metaclass is coupled to ``Interface``. """ 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. 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. 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): if obj.__module__ == 'builtins': return obj.__qualname__ return '{}.{}'.format(obj.__module__, 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) @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``. """ signature = {attr: get_type(getattr(obj, attr)) for attr in dir(obj) if not exclude_privates or not attr.startswith('_')} return Something[signature] 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``. """ 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. """ 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 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, Iterable[Callable]]): 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)) 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])) 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), except AttributeError: # In case of Python 3.5 result = tuple() elif item == '__origin__': result = 'Literal' else: result = SubscriptableType.__getattribute__(cls, item) return result class Literal(metaclass=_LiteralMeta): """ This is a backwards compatible variant of typing.Literal (Python 3.8+). """ _name = 'Literal'