__init__.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. ##############################################################################
  2. # Copyright (c) 2020 Zope Foundation and Contributors.
  3. # All Rights Reserved.
  4. #
  5. # This software is subject to the provisions of the Zope Public License,
  6. # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
  7. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
  8. # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  9. # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
  10. # FOR A PARTICULAR PURPOSE.
  11. ##############################################################################
  12. import itertools
  13. from types import FunctionType
  14. from zope.interface import classImplements
  15. from zope.interface import Interface
  16. from zope.interface.interface import fromFunction
  17. from zope.interface.interface import InterfaceClass
  18. from zope.interface.interface import _decorator_non_return
  19. __all__ = [
  20. # Nothing public here.
  21. ]
  22. # pylint:disable=inherit-non-class,
  23. # pylint:disable=no-self-argument,no-method-argument
  24. # pylint:disable=unexpected-special-method-signature
  25. class optional(object):
  26. # Apply this decorator to a method definition to make it
  27. # optional (remove it from the list of required names), overriding
  28. # the definition inherited from the ABC.
  29. def __init__(self, method):
  30. self.__doc__ = method.__doc__
  31. class ABCInterfaceClass(InterfaceClass):
  32. """
  33. An interface that is automatically derived from a
  34. :class:`abc.ABCMeta` type.
  35. Internal use only.
  36. The body of the interface definition *must* define
  37. a property ``abc`` that is the ABC to base the interface on.
  38. If ``abc`` is *not* in the interface definition, a regular
  39. interface will be defined instead (but ``extra_classes`` is still
  40. respected).
  41. Use the ``@optional`` decorator on method definitions if
  42. the ABC defines methods that are not actually required in all cases
  43. because the Python language has multiple ways to implement a protocol.
  44. For example, the ``iter()`` protocol can be implemented with
  45. ``__iter__`` or the pair ``__len__`` and ``__getitem__``.
  46. When created, any existing classes that are registered to conform
  47. to the ABC are declared to implement this interface. This is *not*
  48. automatically updated as the ABC registry changes. If the body of the
  49. interface definition defines ``extra_classes``, it should be a
  50. tuple giving additional classes to declare implement the interface.
  51. Note that this is not fully symmetric. For example, it is usually
  52. the case that a subclass relationship carries the interface
  53. declarations over::
  54. >>> from zope.interface import Interface
  55. >>> class I1(Interface):
  56. ... pass
  57. ...
  58. >>> from zope.interface import implementer
  59. >>> @implementer(I1)
  60. ... class Root(object):
  61. ... pass
  62. ...
  63. >>> class Child(Root):
  64. ... pass
  65. ...
  66. >>> child = Child()
  67. >>> isinstance(child, Root)
  68. True
  69. >>> from zope.interface import providedBy
  70. >>> list(providedBy(child))
  71. [<InterfaceClass __main__.I1>]
  72. However, that's not the case with ABCs and ABC interfaces. Just
  73. because ``isinstance(A(), AnABC)`` and ``isinstance(B(), AnABC)``
  74. are both true, that doesn't mean there's any class hierarchy
  75. relationship between ``A`` and ``B``, or between either of them
  76. and ``AnABC``. Thus, if ``AnABC`` implemented ``IAnABC``, it would
  77. not follow that either ``A`` or ``B`` implements ``IAnABC`` (nor
  78. their instances provide it)::
  79. >>> class SizedClass(object):
  80. ... def __len__(self): return 1
  81. ...
  82. >>> from collections.abc import Sized
  83. >>> isinstance(SizedClass(), Sized)
  84. True
  85. >>> from zope.interface import classImplements
  86. >>> classImplements(Sized, I1)
  87. None
  88. >>> list(providedBy(SizedClass()))
  89. []
  90. Thus, to avoid conflicting assumptions, ABCs should not be
  91. declared to implement their parallel ABC interface. Only concrete
  92. classes specifically registered with the ABC should be declared to
  93. do so.
  94. .. versionadded:: 5.0.0
  95. """
  96. # If we could figure out invalidation, and used some special
  97. # Specification/Declaration instances, and override the method ``providedBy`` here,
  98. # perhaps we could more closely integrate with ABC virtual inheritance?
  99. def __init__(self, name, bases, attrs):
  100. # go ahead and give us a name to ease debugging.
  101. self.__name__ = name
  102. extra_classes = attrs.pop('extra_classes', ())
  103. ignored_classes = attrs.pop('ignored_classes', ())
  104. if 'abc' not in attrs:
  105. # Something like ``IList(ISequence)``: We're extending
  106. # abc interfaces but not an ABC interface ourself.
  107. InterfaceClass.__init__(self, name, bases, attrs)
  108. ABCInterfaceClass.__register_classes(self, extra_classes, ignored_classes)
  109. self.__class__ = InterfaceClass
  110. return
  111. based_on = attrs.pop('abc')
  112. self.__abc = based_on
  113. self.__extra_classes = tuple(extra_classes)
  114. self.__ignored_classes = tuple(ignored_classes)
  115. assert name[1:] == based_on.__name__, (name, based_on)
  116. methods = {
  117. # Passing the name is important in case of aliases,
  118. # e.g., ``__ror__ = __or__``.
  119. k: self.__method_from_function(v, k)
  120. for k, v in vars(based_on).items()
  121. if isinstance(v, FunctionType) and not self.__is_private_name(k)
  122. and not self.__is_reverse_protocol_name(k)
  123. }
  124. methods['__doc__'] = self.__create_class_doc(attrs)
  125. # Anything specified in the body takes precedence.
  126. methods.update(attrs)
  127. InterfaceClass.__init__(self, name, bases, methods)
  128. self.__register_classes()
  129. @staticmethod
  130. def __optional_methods_to_docs(attrs):
  131. optionals = {k: v for k, v in attrs.items() if isinstance(v, optional)}
  132. for k in optionals:
  133. attrs[k] = _decorator_non_return
  134. if not optionals:
  135. return ''
  136. docs = "\n\nThe following methods are optional:\n - " + "\n-".join(
  137. "%s\n%s" % (k, v.__doc__) for k, v in optionals.items()
  138. )
  139. return docs
  140. def __create_class_doc(self, attrs):
  141. based_on = self.__abc
  142. def ref(c):
  143. mod = c.__module__
  144. name = c.__name__
  145. if mod == str.__module__:
  146. return "`%s`" % name
  147. if mod == '_io':
  148. mod = 'io'
  149. return "`%s.%s`" % (mod, name)
  150. implementations_doc = "\n - ".join(
  151. ref(c)
  152. for c in sorted(self.getRegisteredConformers(), key=ref)
  153. )
  154. if implementations_doc:
  155. implementations_doc = "\n\nKnown implementations are:\n\n - " + implementations_doc
  156. based_on_doc = (based_on.__doc__ or '')
  157. based_on_doc = based_on_doc.splitlines()
  158. based_on_doc = based_on_doc[0] if based_on_doc else ''
  159. doc = """Interface for the ABC `%s.%s`.\n\n%s%s%s""" % (
  160. based_on.__module__, based_on.__name__,
  161. attrs.get('__doc__', based_on_doc),
  162. self.__optional_methods_to_docs(attrs),
  163. implementations_doc
  164. )
  165. return doc
  166. @staticmethod
  167. def __is_private_name(name):
  168. if name.startswith('__') and name.endswith('__'):
  169. return False
  170. return name.startswith('_')
  171. @staticmethod
  172. def __is_reverse_protocol_name(name):
  173. # The reverse names, like __rand__,
  174. # aren't really part of the protocol. The interpreter has
  175. # very complex behaviour around invoking those. PyPy
  176. # doesn't always even expose them as attributes.
  177. return name.startswith('__r') and name.endswith('__')
  178. def __method_from_function(self, function, name):
  179. method = fromFunction(function, self, name=name)
  180. # Eliminate the leading *self*, which is implied in
  181. # an interface, but explicit in an ABC.
  182. method.positional = method.positional[1:]
  183. return method
  184. def __register_classes(self, conformers=None, ignored_classes=None):
  185. # Make the concrete classes already present in our ABC's registry
  186. # declare that they implement this interface.
  187. conformers = conformers if conformers is not None else self.getRegisteredConformers()
  188. ignored = ignored_classes if ignored_classes is not None else self.__ignored_classes
  189. for cls in conformers:
  190. if cls in ignored:
  191. continue
  192. classImplements(cls, self)
  193. def getABC(self):
  194. """
  195. Return the ABC this interface represents.
  196. """
  197. return self.__abc
  198. def getRegisteredConformers(self):
  199. """
  200. Return an iterable of the classes that are known to conform to
  201. the ABC this interface parallels.
  202. """
  203. based_on = self.__abc
  204. # The registry only contains things that aren't already
  205. # known to be subclasses of the ABC. But the ABC is in charge
  206. # of checking that, so its quite possible that registrations
  207. # are in fact ignored, winding up just in the _abc_cache.
  208. try:
  209. registered = list(based_on._abc_registry) + list(based_on._abc_cache)
  210. except AttributeError:
  211. # Rewritten in C in CPython 3.7.
  212. # These expose the underlying weakref.
  213. from abc import _get_dump
  214. data = _get_dump(based_on)
  215. registry = data[0]
  216. cache = data[1]
  217. registered = [x() for x in itertools.chain(registry, cache)]
  218. registered = [x for x in registered if x is not None]
  219. return set(itertools.chain(registered, self.__extra_classes))
  220. def _create_ABCInterface():
  221. # It's a two-step process to create the root ABCInterface, because
  222. # without specifying a corresponding ABC, using the normal constructor
  223. # gets us a plain InterfaceClass object, and there is no ABC to associate with the
  224. # root.
  225. abc_name_bases_attrs = ('ABCInterface', (Interface,), {})
  226. instance = ABCInterfaceClass.__new__(ABCInterfaceClass, *abc_name_bases_attrs)
  227. InterfaceClass.__init__(instance, *abc_name_bases_attrs)
  228. return instance
  229. ABCInterface = _create_ABCInterface()