Пример #1
1
 def test_isinstance_invalidation(self):
     class A(metaclass=abc.ABCMeta):
         pass
     class B:
         pass
     b = B()
     self.assertFalse(isinstance(b, A))
     self.assertFalse(isinstance(b, (A,)))
     token_old = abc.get_cache_token()
     A.register(B)
     token_new = abc.get_cache_token()
     self.assertNotEqual(token_old, token_new)
     self.assertTrue(isinstance(b, A))
     self.assertTrue(isinstance(b, (A,)))
Пример #2
0
    def dispatch(cls, role=None):
        """
        Return the implementation for the given type and role.

        If role is given, return a function that receives a single positional
        argument and any number of keyword arguments. If role is not given,
        the return function should receive both an object and a role as
        positional arguments.
        """
        # Invalidate cache when ABC cache is invalidated
        nonlocal cache_token
        if cache_token is not None and cache_token != get_cache_token():
            dispatch_cache.clear()
            cache_token = get_cache_token()

        try:
            return dispatch_cache[cls, role]
        except KeyError:
            pass

        # Find implementation, if not in cache
        if role is None:
            impl = no_roles.dispatch(cls)
        elif role in roles:
            impl = roles[role].dispatch(cls)
        else:
            impl = partial(no_roles.dispatch(cls), role=role)

        # Cache and return
        dispatch_cache[cls, role] = impl
        return impl
Пример #3
0
    def build_proxy_registry(cls):
        if cls.proxy_registry and abc.get_cache_token(
        ) == cls.last_cache_token:
            return

        cls.last_cache_token = abc.get_cache_token()
        registry = copy(cls.base_proxy_registry)
        MatrixProxy._register_subclasses(cls.__subclasses__(), registry)
        cls.proxy_registry = registry
Пример #4
0
 def test_isinstance_invalidation(self):
     class A(metaclass=abc.ABCMeta):
         pass
     class B:
         pass
     b = B()
     self.assertFalse(isinstance(b, A))
     self.assertFalse(isinstance(b, (A,)))
     token_old = abc.get_cache_token()
     A.register(B)
     token_new = abc.get_cache_token()
     self.assertNotEqual(token_old, token_new)
     self.assertTrue(isinstance(b, A))
     self.assertTrue(isinstance(b, (A,)))
Пример #5
0
    def register(cls, func=None):
        """generic_func.register(cls, func) -> func

        Registers a new implementation for the given *cls* on a *generic_func*.

        """
        nonlocal cache_token
        if func is None:
            if isinstance(cls, type):
                return lambda f: register(cls, f)
            ann = getattr(cls, '__annotations__', {})
            if not ann:
                raise TypeError(
                    f"Invalid first argument to `register()`: {cls!r}. "
                    f"Use either `@register(some_class)` or plain `@register` "
                    f"on an annotated function.")
            func = cls

            # only import typing if annotation parsing is necessary
            from typing import get_type_hints
            argname, cls = next(iter(get_type_hints(func).items()))
            assert isinstance(cls, type), (
                f"Invalid annotation for {argname!r}. {cls!r} is not a group.")
        registry[cls] = func
        if cache_token is None and hasattr(cls, '__abstractmethods__'):
            cache_token = get_cache_token()
        dispatch_cache.clear()
        return func
    def dispatch(cls):
        """generic_func.dispatch(cls) -> <function implementation>

        Runs the dispatch algorithm to return the best available implementation
        for the given *cls* registered on *generic_func*.

        """
        nonlocal cache_token
        if cache_token is not None:
            current_token = get_cache_token()
            if cache_token != current_token:
                dispatch_cache.clear()
                cache_token = current_token
        try:
            impl = dispatch_cache[cls]
        except KeyError:
            try:
                impl = registry[cls]
            except KeyError:
                impl = find_implementation(cls, registry)
                if impl is func and lazy_registry:
                    for qualname in possible_qualnames(cls):
                        if qualname in lazy_registry:
                            impl = lazy_registry.pop(qualname)
                            register(cls)(impl)
                            break

            dispatch_cache[cls] = impl
        return impl
Пример #7
0
def _dispatch(cls, vcls):
    global _cache_token
    if _cache_token is not None:
        current_token = get_cache_token()
        if _cache_token != current_token:
            _dispatch_cache.clear()
            _cache_token = current_token

    try:
        func = _dispatch_cache[(cls, vcls)]
    except KeyError:
        try:
            vreg = _registry[cls]
        except KeyError:
            vreg = _find_impl(cls, _registry)
            if not vreg:
                raise NotImplementedError(
                    f"No implementation found for '{cls.__qualname__}'")

        try:
            return vreg[vcls]
        except KeyError:
            func = _find_impl(vcls, vreg)
            if not func:
                raise TypeError(
                    f"No implementation found for '{cls.__qualname__}' from {vcls.__qualname__}")
        _dispatch_cache[(cls, vcls)] = func

    return func
    def register(cls, impl=None):
        """generic_func.register(cls, impl) -> impl

        Registers a new implementation for the given *cls* on a *generic_func*.
        """
        nonlocal cache_token

        # First argument is a list of classes: iterate over all classes
        # registering one at a time.
        if not isinstance(cls, (type, str)):
            cls_list = list(cls)
            if impl is not None:
                for cls in cls_list:
                    register(cls, impl)
                return

        # Single class
        if impl is None:
            return lambda f: register(cls, f)
        if isinstance(cls, str):
            lazy_registry[cls] = impl
        else:
            registry[cls] = impl
        if cache_token is None and hasattr(cls, "__abstractmethods__"):
            cache_token = get_cache_token()
        dispatch_cache.clear()
        return impl
Пример #9
0
    def register(cls, func=None):
        """generic_func.register(cls, func) -> func

        Registers a new implementation for the given *cls* on a *generic_func*.

        """
        nonlocal cache_token
        if func is None:
            if isinstance(cls, type):
                return lambda f: register(cls, f)
            ann = getattr(cls, '__annotations__', {})
            if not ann:
                raise TypeError(
                    f"Invalid first argument to `register()`: {cls!r}. "
                    f"Use either `@register(some_class)` or plain `@register` "
                    f"on an annotated function."
                )
            func = cls

            # only import typing if annotation parsing is necessary
            from typing import get_type_hints
            argname, cls = next(iter(get_type_hints(func).items()))
            assert isinstance(cls, type), (
                f"Invalid annotation for {argname!r}. {cls!r} is not a class."
            )
        registry[cls] = func
        if cache_token is None and hasattr(cls, '__abstractmethods__'):
            cache_token = get_cache_token()
        dispatch_cache.clear()
        return func
Пример #10
0
    def __init__(self, default_callback: Callable[..., T]):
        self.default_callback = default_callback
        self.__name__ = default_callback.__name__
        self.candidate_sets: Dict[int, Set[Candidate]] = defaultdict(set)

        self._cache_token = get_cache_token()
        self._layers_cache: Dict[int, List[Set[Candidate]]] = {}
        self._lookup_cache: Dict[
            int, WeakTupleDict[List[LookupLayer]]] = defaultdict(WeakTupleDict)
Пример #11
0
        def decorator(implementation):
            container = self._protocols if is_protocol else self._instances
            container[type_argument] = implementation  # type: ignore

            if self._cache_token is None:  # pragma: no cover
                if getattr(type_argument, '__abstractmethods__', None):
                    self._cache_token = get_cache_token()

            self._dispatch_cache.clear()
            return implementation
Пример #12
0
def test_isinstance_invalidation(abc):  # pylint: disable=unused-argument
    """Test after-the-fact registration behavior.

    Adapted from Python's test suite.
    """
    class AClass(metaclass=abc.NamespaceableABCMeta):
        """A throwaway test class."""

    class BClass:
        """A throwaway test class."""

    b_instance = BClass()
    assert not isinstance(b_instance, AClass)
    assert not isinstance(b_instance, (AClass, ))
    token_old = abc_main.get_cache_token()
    AClass.register(BClass)
    token_new = abc_main.get_cache_token()
    assert token_old != token_new
    assert isinstance(b_instance, AClass)
    assert isinstance(b_instance, (AClass, ))
Пример #13
0
    def _control_abc_cache(self) -> None:
        """
        Required to drop cache if ``abc`` type got new subtypes in runtime.

        Copied from ``cpython``.
        """
        if self._cache_token is not None:
            current_token = get_cache_token()
            if self._cache_token != current_token:
                self._dispatch_cache.clear()
                self._cache_token = current_token
Пример #14
0
 def register(cls, func=None):
     """generic_func.register(cls, func) -> func
     Registers a new implementation for the given *cls* on a *generic_func*.
     """
     nonlocal cache_token
     if func is None:
         return lambda f: register(cls, f)
     registry[cls] = func
     if cache_token is None and hasattr(cls, '__abstractmethods__'):
         cache_token = get_cache_token()
     dispatch_cache.clear()
     return func
Пример #15
0
    def register(cls, func=None):
        """generic_func.register(cls, func) -> func

        Registers a new implementation for the given *cls* on a *generic_func*.

        """
        nonlocal cache_token
        if func is None:
            return lambda f: register(cls, f)
        registry[cls] = func
        if cache_token is None and hasattr(cls, '__abstractmethods__'):
            cache_token = get_cache_token()
        dispatch_cache.clear()
        return func
Пример #16
0
    def __call__(self, *args, **kwargs):
        new_cache_token = get_cache_token()
        if new_cache_token != self._cache_token:
            # our cache is out of date and must be rebuilt
            self.clear_cache()
            self._cache_token = new_cache_token

        t_args = tuple(type(a) for a in args)
        ll = self._get_lookup_layers(t_args)
        for layer in ll:
            if isinstance(layer, Exception):
                raise layer
            ret = layer.callback(*args, **kwargs)
            if ret is not NotImplemented:
                return ret
        return self.default_callback(*args, **kwargs)
Пример #17
0
def _register(func):
    global _cache_token
    sig = signature(func)
    if len(sig.parameters) < 3:
        raise TypeError(
            f"{func!r}() takes {len(sig.parameters)} arguments but 3 required")
    it = iter(sig.parameters.items())
    argname, parameter = next(it)
    hints = get_type_hints(func)
    typ = hints.get(argname)
    if typ:
        type_args = _get_type_args(typ)
        if get_origin(typ) is not type or not type_args:
            raise TypeError(
                f"Invalid first argument to `cast.register()`: {typ!r}. "
                f"Use either typing.Type[] annotation or return type annotation."
            )
        cls = type_args[0]
    else:
        cls = hints.get('return')
        if cls is None:
            raise TypeError(
                f"Invalid signature to `cast.register()`. "
                f"Use either typing.Type[] annotation or return type annotation."
            )

    argname, parameter = next(it)
    vcls = hints.get(argname)
    if not vcls:
        vcls = Any
    if vcls == Any:
        vcls = object

    if cls in _registry:
        if vcls in _registry[cls]:
            raise RuntimeError(f"Ambiguous `cast.register()`")
        _registry[cls][vcls] = func
    else:
        _registry[cls] = {vcls: func}
    setattr(func, _TYPES, (cls, vcls))

    if _cache_token is None:
        if hasattr(cls, '__abstractmethods__') or hasattr(vcls, '__abstractmethods__'):
            _cache_token = get_cache_token()
    _dispatch_cache.clear()

    return func
Пример #18
0
    def register(cls, func=None):
        """generic_func.register(cls, func) -> func

        Registers a new implementation for the given *cls* on a *generic_func*.

        """
        nonlocal cache_token
        if _is_valid_dispatch_type(cls):
            if func is None:
                return lambda f: register(cls, f)
        else:
            if func is not None:
                raise TypeError(f"Invalid first argument to `register()`. "
                                f"{cls!r} is not a class or union type.")
            ann = getattr(cls, '__annotations__', {})
            if not ann:
                raise TypeError(
                    f"Invalid first argument to `register()`: {cls!r}. "
                    f"Use either `@register(some_class)` or plain `@register` "
                    f"on an annotated function.")
            func = cls

            # only import typing if annotation parsing is necessary
            from typing import get_type_hints
            argname, cls = next(iter(get_type_hints(func).items()))
            if not _is_valid_dispatch_type(cls):
                if _is_union_type(cls):
                    raise TypeError(f"Invalid annotation for {argname!r}. "
                                    f"{cls!r} not all arguments are classes.")
                else:
                    raise TypeError(f"Invalid annotation for {argname!r}. "
                                    f"{cls!r} is not a class.")

        if _is_union_type(cls):
            from typing import get_args

            for arg in get_args(cls):
                registry[arg] = func
        else:
            registry[cls] = func
        if cache_token is None and hasattr(cls, '__abstractmethods__'):
            cache_token = get_cache_token()
        dispatch_cache.clear()
        return func
    def register(cls=None, func=None):
        """generic_func.register(cls, func) -> func

        Registers a new implementation for the given *cls* on a *generic_func*.

        """
        nonlocal cache_token
        if func is None:
            return lambda f: register(cls, f)

        if cls is None:
            sign = inspect.signature(func)
            params = sign.parameters
            cls = list(params.values())[disp_param].annotation

        registry[cls] = func
        if cache_token is None and hasattr(cls, '__abstractmethods__'):
            cache_token = get_cache_token()
        dispatch_cache.clear()
        return func
Пример #20
0
 def dispatch(cls):
     """generic_func.dispatch(cls) -> <function implementation>
     Runs the dispatch algorithm to return the best available implementation
     for the given *cls* registered on *generic_func*.
     """
     nonlocal cache_token
     if cache_token is not None:
         current_token = get_cache_token()
         if cache_token != current_token:
             dispatch_cache.clear()
             cache_token = current_token
     try:
         impl = dispatch_cache[cls]
     except KeyError:
         try:
             impl = registry[cls]
         except KeyError:
             impl = _find_impl(cls, registry)
         dispatch_cache[cls] = impl
     return impl
Пример #21
0
    def dispatch(cls):
        """generic_func.dispatch(cls) -> <function implementation>

        Runs the dispatch algorithm to return the best available implementation
        for the given *cls* registered on *generic_func*.

        """
        nonlocal cache_token
        if cache_token is not None:
            current_token = get_cache_token()
            if cache_token != current_token:
                dispatch_cache.clear()
                cache_token = current_token
        try:
            impl = dispatch_cache[cls]
        except KeyError:
            try:
                impl = registry[cls]
            except KeyError:
                impl = _find_impl(cls, registry)
            dispatch_cache[cls] = impl
        return impl
Пример #22
0
 def get_token(self):
     return abc.get_cache_token()
            from typing import get_type_hints
            argname, cls = next(iter(get_type_hints(func).items()))
<<<<<<< HEAD
            assert isinstance(cls, type), (
                f"Invalid annotation for {argname!r}. {cls!r} is not a class."
            )
=======
            if not isinstance(cls, type):
                raise TypeError(
                    f"Invalid annotation for {argname!r}. "
                    f"{cls!r} is not a class."
                )
>>>>>>> 716b15a33aed978ded8a6bde17855cb6c6aa7f78
        registry[cls] = func
        if cache_token is None and hasattr(cls, '__abstractmethods__'):
            cache_token = get_cache_token()
        dispatch_cache.clear()
        return func

    def wrapper(*args, **kw):
        if not args:
            raise TypeError(f'{funcname} requires at least '
                            '1 positional argument')

        return dispatch(args[0].__class__)(*args, **kw)

    funcname = getattr(func, '__name__', 'singledispatch function')
    registry[object] = func
    wrapper.register = register
    wrapper.dispatch = dispatch
    wrapper.registry = types.MappingProxyType(registry)
Пример #24
0
 def update_event(self, inp=-1):
     self.set_output_val(0, abc.get_cache_token())