diff options
author | shmel1k <shmel1k@ydb.tech> | 2023-11-26 18:16:14 +0300 |
---|---|---|
committer | shmel1k <shmel1k@ydb.tech> | 2023-11-26 18:43:30 +0300 |
commit | b8cf9e88f4c5c64d9406af533d8948deb050d695 (patch) | |
tree | 218eb61fb3c3b96ec08b4d8cdfef383104a87d63 /contrib/python/zope.interface/py3/zope/interface/common/__init__.py | |
parent | 523f645a83a0ec97a0332dbc3863bb354c92a328 (diff) | |
download | ydb-b8cf9e88f4c5c64d9406af533d8948deb050d695.tar.gz |
add kikimr_configure
Diffstat (limited to 'contrib/python/zope.interface/py3/zope/interface/common/__init__.py')
-rw-r--r-- | contrib/python/zope.interface/py3/zope/interface/common/__init__.py | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/contrib/python/zope.interface/py3/zope/interface/common/__init__.py b/contrib/python/zope.interface/py3/zope/interface/common/__init__.py new file mode 100644 index 0000000000..56f4566a24 --- /dev/null +++ b/contrib/python/zope.interface/py3/zope/interface/common/__init__.py @@ -0,0 +1,272 @@ +############################################################################## +# Copyright (c) 2020 Zope Foundation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +############################################################################## + +import itertools +from types import FunctionType + +from zope.interface import classImplements +from zope.interface import Interface +from zope.interface.interface import fromFunction +from zope.interface.interface import InterfaceClass +from zope.interface.interface import _decorator_non_return + +__all__ = [ + # Nothing public here. +] + + +# pylint:disable=inherit-non-class, +# pylint:disable=no-self-argument,no-method-argument +# pylint:disable=unexpected-special-method-signature + +class optional: + # Apply this decorator to a method definition to make it + # optional (remove it from the list of required names), overriding + # the definition inherited from the ABC. + def __init__(self, method): + self.__doc__ = method.__doc__ + + +class ABCInterfaceClass(InterfaceClass): + """ + An interface that is automatically derived from a + :class:`abc.ABCMeta` type. + + Internal use only. + + The body of the interface definition *must* define + a property ``abc`` that is the ABC to base the interface on. + + If ``abc`` is *not* in the interface definition, a regular + interface will be defined instead (but ``extra_classes`` is still + respected). + + Use the ``@optional`` decorator on method definitions if + the ABC defines methods that are not actually required in all cases + because the Python language has multiple ways to implement a protocol. + For example, the ``iter()`` protocol can be implemented with + ``__iter__`` or the pair ``__len__`` and ``__getitem__``. + + When created, any existing classes that are registered to conform + to the ABC are declared to implement this interface. This is *not* + automatically updated as the ABC registry changes. If the body of the + interface definition defines ``extra_classes``, it should be a + tuple giving additional classes to declare implement the interface. + + Note that this is not fully symmetric. For example, it is usually + the case that a subclass relationship carries the interface + declarations over:: + + >>> from zope.interface import Interface + >>> class I1(Interface): + ... pass + ... + >>> from zope.interface import implementer + >>> @implementer(I1) + ... class Root(object): + ... pass + ... + >>> class Child(Root): + ... pass + ... + >>> child = Child() + >>> isinstance(child, Root) + True + >>> from zope.interface import providedBy + >>> list(providedBy(child)) + [<InterfaceClass __main__.I1>] + + However, that's not the case with ABCs and ABC interfaces. Just + because ``isinstance(A(), AnABC)`` and ``isinstance(B(), AnABC)`` + are both true, that doesn't mean there's any class hierarchy + relationship between ``A`` and ``B``, or between either of them + and ``AnABC``. Thus, if ``AnABC`` implemented ``IAnABC``, it would + not follow that either ``A`` or ``B`` implements ``IAnABC`` (nor + their instances provide it):: + + >>> class SizedClass(object): + ... def __len__(self): return 1 + ... + >>> from collections.abc import Sized + >>> isinstance(SizedClass(), Sized) + True + >>> from zope.interface import classImplements + >>> classImplements(Sized, I1) + None + >>> list(providedBy(SizedClass())) + [] + + Thus, to avoid conflicting assumptions, ABCs should not be + declared to implement their parallel ABC interface. Only concrete + classes specifically registered with the ABC should be declared to + do so. + + .. versionadded:: 5.0.0 + """ + + # If we could figure out invalidation, and used some special + # Specification/Declaration instances, and override the method ``providedBy`` here, + # perhaps we could more closely integrate with ABC virtual inheritance? + + def __init__(self, name, bases, attrs): + # go ahead and give us a name to ease debugging. + self.__name__ = name + extra_classes = attrs.pop('extra_classes', ()) + ignored_classes = attrs.pop('ignored_classes', ()) + + if 'abc' not in attrs: + # Something like ``IList(ISequence)``: We're extending + # abc interfaces but not an ABC interface ourself. + InterfaceClass.__init__(self, name, bases, attrs) + ABCInterfaceClass.__register_classes(self, extra_classes, ignored_classes) + self.__class__ = InterfaceClass + return + + based_on = attrs.pop('abc') + self.__abc = based_on + self.__extra_classes = tuple(extra_classes) + self.__ignored_classes = tuple(ignored_classes) + + assert name[1:] == based_on.__name__, (name, based_on) + methods = { + # Passing the name is important in case of aliases, + # e.g., ``__ror__ = __or__``. + k: self.__method_from_function(v, k) + for k, v in vars(based_on).items() + if isinstance(v, FunctionType) and not self.__is_private_name(k) + and not self.__is_reverse_protocol_name(k) + } + + methods['__doc__'] = self.__create_class_doc(attrs) + # Anything specified in the body takes precedence. + methods.update(attrs) + InterfaceClass.__init__(self, name, bases, methods) + self.__register_classes() + + @staticmethod + def __optional_methods_to_docs(attrs): + optionals = {k: v for k, v in attrs.items() if isinstance(v, optional)} + for k in optionals: + attrs[k] = _decorator_non_return + + if not optionals: + return '' + + docs = "\n\nThe following methods are optional:\n - " + "\n-".join( + "{}\n{}".format(k, v.__doc__) for k, v in optionals.items() + ) + return docs + + def __create_class_doc(self, attrs): + based_on = self.__abc + def ref(c): + mod = c.__module__ + name = c.__name__ + if mod == str.__module__: + return "`%s`" % name + if mod == '_io': + mod = 'io' + return "`{}.{}`".format(mod, name) + implementations_doc = "\n - ".join( + ref(c) + for c in sorted(self.getRegisteredConformers(), key=ref) + ) + if implementations_doc: + implementations_doc = "\n\nKnown implementations are:\n\n - " + implementations_doc + + based_on_doc = (based_on.__doc__ or '') + based_on_doc = based_on_doc.splitlines() + based_on_doc = based_on_doc[0] if based_on_doc else '' + + doc = """Interface for the ABC `{}.{}`.\n\n{}{}{}""".format( + based_on.__module__, based_on.__name__, + attrs.get('__doc__', based_on_doc), + self.__optional_methods_to_docs(attrs), + implementations_doc + ) + return doc + + + @staticmethod + def __is_private_name(name): + if name.startswith('__') and name.endswith('__'): + return False + return name.startswith('_') + + @staticmethod + def __is_reverse_protocol_name(name): + # The reverse names, like __rand__, + # aren't really part of the protocol. The interpreter has + # very complex behaviour around invoking those. PyPy + # doesn't always even expose them as attributes. + return name.startswith('__r') and name.endswith('__') + + def __method_from_function(self, function, name): + method = fromFunction(function, self, name=name) + # Eliminate the leading *self*, which is implied in + # an interface, but explicit in an ABC. + method.positional = method.positional[1:] + return method + + def __register_classes(self, conformers=None, ignored_classes=None): + # Make the concrete classes already present in our ABC's registry + # declare that they implement this interface. + conformers = conformers if conformers is not None else self.getRegisteredConformers() + ignored = ignored_classes if ignored_classes is not None else self.__ignored_classes + for cls in conformers: + if cls in ignored: + continue + classImplements(cls, self) + + def getABC(self): + """ + Return the ABC this interface represents. + """ + return self.__abc + + def getRegisteredConformers(self): + """ + Return an iterable of the classes that are known to conform to + the ABC this interface parallels. + """ + based_on = self.__abc + + # The registry only contains things that aren't already + # known to be subclasses of the ABC. But the ABC is in charge + # of checking that, so its quite possible that registrations + # are in fact ignored, winding up just in the _abc_cache. + try: + registered = list(based_on._abc_registry) + list(based_on._abc_cache) + except AttributeError: + # Rewritten in C in CPython 3.7. + # These expose the underlying weakref. + from abc import _get_dump + data = _get_dump(based_on) + registry = data[0] + cache = data[1] + registered = [x() for x in itertools.chain(registry, cache)] + registered = [x for x in registered if x is not None] + + return set(itertools.chain(registered, self.__extra_classes)) + + +def _create_ABCInterface(): + # It's a two-step process to create the root ABCInterface, because + # without specifying a corresponding ABC, using the normal constructor + # gets us a plain InterfaceClass object, and there is no ABC to associate with the + # root. + abc_name_bases_attrs = ('ABCInterface', (Interface,), {}) + instance = ABCInterfaceClass.__new__(ABCInterfaceClass, *abc_name_bases_attrs) + InterfaceClass.__init__(instance, *abc_name_bases_attrs) + return instance + +ABCInterface = _create_ABCInterface() |