diff --git a/Doc/library/abc.rst b/Doc/library/abc.rst index 27abb605fd7..1f21b5750d4 100644 --- a/Doc/library/abc.rst +++ b/Doc/library/abc.rst @@ -58,6 +58,10 @@ This module provides the following classes: .. versionchanged:: 3.3 Returns the registered subclass, to allow usage as a class decorator. + .. versionchanged:: 3.4 + To detect calls to :meth:`register`, you can use the + :func:`get_cache_token` function. + You can also override this method in an abstract base class: .. method:: __subclasshook__(subclass) @@ -308,6 +312,19 @@ The :mod:`abc` module also provides the following decorators: :func:`abstractmethod`, making this decorator redundant. +The :mod:`abc` module also provides the following functions: + +.. function:: get_cache_token() + + Returns the current abstract base class cache token. + + The token is an opaque integer identifying the current version of the + abstract base class cache for virtual subclasses. This number changes + with every call to :meth:`ABCMeta.register` on any ABC. + + .. versionadded:: 3.4 + + .. rubric:: Footnotes .. [#] C++ programmers should note that Python's virtual base class diff --git a/Lib/abc.py b/Lib/abc.py index e807895da3e..264c60c428b 100644 --- a/Lib/abc.py +++ b/Lib/abc.py @@ -5,6 +5,7 @@ from _weakrefset import WeakSet + def abstractmethod(funcobj): """A decorator indicating abstract methods. @@ -124,6 +125,8 @@ class ABCMeta(type): # A global counter that is incremented each time a class is # registered as a virtual subclass of anything. It forces the # negative cache to be cleared before its next use. + # Note: this counter is private. Use `abc.get_cache_token()` for + # external code. _abc_invalidation_counter = 0 def __new__(mcls, name, bases, namespace): @@ -227,8 +230,19 @@ class ABCMeta(type): cls._abc_negative_cache.add(subclass) return False + class ABC(metaclass=ABCMeta): """Helper class that provides a standard way to create an ABC using inheritance. """ pass + + +def get_cache_token(): + """Returns the current ABC cache token. + + The token is an opaque integer identifying the current version of + the ABC cache for virtual subclasses. This number changes with + every call to ``register()`` on any ABC. + """ + return ABCMeta._abc_invalidation_counter diff --git a/Lib/test/test_abc.py b/Lib/test/test_abc.py index 34985245018..4b151575ba4 100644 --- a/Lib/test/test_abc.py +++ b/Lib/test/test_abc.py @@ -329,7 +329,10 @@ class TestABC(unittest.TestCase): 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,)))