$49 GRAYBYTE WORDPRESS FILE MANAGER $99

SERVER : in-mum-web1330.main-hosting.eu #1 SMP Mon Feb 10 22:45:17 UTC 2025
SERVER IP : 147.79.69.208 | ADMIN IP 216.73.216.215
OPTIONS : CRL = ON | WGT = ON | SDO = OFF | PKEX = OFF
DEACTIVATED : NONE

/opt/alt/python311/lib/python3.11/site-packages/typish/

HOME
Current File : /opt/alt/python311/lib/python3.11/site-packages/typish//_classes.py
"""
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'

Current_dir [ NOT WRITEABLE ] Document_root [ WRITEABLE ]


[ Back ]
NAME
SIZE
LAST TOUCH
USER
CAN-I?
FUNCTIONS
..
--
5 Sep 2025 9.32 AM
root / 996
0755
__pycache__
--
8 May 2024 6.34 PM
root / root
0755
classes
--
8 May 2024 6.34 PM
root / root
0755
decorators
--
8 May 2024 6.34 PM
root / root
0755
functions
--
8 May 2024 6.34 PM
root / root
0755
__init__.py
1.452 KB
8 May 2024 6.34 PM
root / root
0644
_classes.py
11.346 KB
8 May 2024 6.34 PM
root / root
0644
_decorators.py
0.717 KB
8 May 2024 6.34 PM
root / root
0644
_functions.py
15.254 KB
8 May 2024 6.34 PM
root / root
0644
_meta.py
0.239 KB
8 May 2024 6.34 PM
root / root
0644
_state.py
1.271 KB
8 May 2024 6.34 PM
root / root
0644
_types.py
0.436 KB
8 May 2024 6.34 PM
root / root
0644
effe.py
0.821 KB
8 May 2024 6.34 PM
root / root
0644

GRAYBYTE WORDPRESS FILE MANAGER @ 2026 CONTACT ME
Static GIF