Author: Yannick Jadoul <[email protected]>
Branch: py3.7-bpo-31333
Changeset: r97913:1afc6d0f0699
Date: 2019-10-18 19:58 +0200
http://bitbucket.org/pypy/pypy/changeset/1afc6d0f0699/

Log:    Adding built-in module _abc

diff --git a/pypy/module/_abc/__init__.py b/pypy/module/_abc/__init__.py
new file mode 100644
diff --git a/pypy/module/_abc/app_abc.py b/pypy/module/_abc/app_abc.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_abc/app_abc.py
@@ -0,0 +1,139 @@
+# NOT_RPYTHON
+"""
+Plain Python definition of the builtin ABC-related functions.
+"""
+
+from _weakrefset import WeakSet
+
+
+_abc_invalidation_counter = 0
+
+
+def get_cache_token():
+    """Returns the current ABC cache token.
+
+    The token is an opaque object (supporting equality testing) identifying the
+    current version of the ABC cache for virtual subclasses. The token changes
+    with every call to ``register()`` on any ABC.
+    """
+    return _abc_invalidation_counter
+
+
+def _abc_init(cls):
+    """Internal ABC helper for class set-up. Should be never used outside abc 
module."""
+    namespace = cls.__dict__
+    abstracts = {name
+                for name, value in namespace.items()
+                if getattr(value, "__isabstractmethod__", False)}
+    bases = cls.__bases__
+    for base in bases:
+        for name in getattr(base, "__abstractmethods__", set()):
+            value = getattr(cls, name, None)
+            if getattr(value, "__isabstractmethod__", False):
+                abstracts.add(name)
+    cls.__abstractmethods__ = frozenset(abstracts)
+    # Set up inheritance registry
+    cls._abc_registry = WeakSet()
+    cls._abc_cache = WeakSet()
+    cls._abc_negative_cache = WeakSet()
+    cls._abc_negative_cache_version = _abc_invalidation_counter
+
+
+def _abc_register(cls, subclass):
+    """Internal ABC helper for subclasss registration. Should be never used 
outside abc module."""
+    if not isinstance(subclass, type):
+        raise TypeError("Can only register classes")
+    if issubclass(subclass, cls):
+        return subclass  # Already a subclass
+    # Subtle: test for cycles *after* testing for "already a subclass";
+    # this means we allow X.register(X) and interpret it as a no-op.
+    if issubclass(cls, subclass):
+        # This would create a cycle, which is bad for the algorithm below
+        raise RuntimeError("Refusing to create an inheritance cycle")
+    cls._abc_registry.add(subclass)
+    global _abc_invalidation_counter
+    _abc_invalidation_counter += 1  # Invalidate negative cache
+    return subclass
+
+
+def _abc_instancecheck(cls, instance):
+    """Internal ABC helper for instance checks. Should be never used outside 
abc module."""
+    # Inline the cache checking
+    subclass = instance.__class__
+    if subclass in cls._abc_cache:
+        return True
+    subtype = type(instance)
+    if subtype is subclass:
+        if (cls._abc_negative_cache_version ==
+            _abc_invalidation_counter and
+            subclass in cls._abc_negative_cache):
+            return False
+        # Fall back to the subclass check.
+        return cls.__subclasscheck__(subclass)
+    return any(cls.__subclasscheck__(c) for c in (subclass, subtype))
+
+
+def _abc_subclasscheck(cls, subclass):
+    """Internal ABC helper for subclasss checks. Should be never used outside 
abc module."""
+    if not isinstance(subclass, type):
+        raise TypeError('issubclass() arg 1 must be a class')
+    # Check cache
+    if subclass in cls._abc_cache:
+        return True
+    # Check negative cache; may have to invalidate
+    if cls._abc_negative_cache_version < _abc_invalidation_counter:
+        # Invalidate the negative cache
+        cls._abc_negative_cache = WeakSet()
+        cls._abc_negative_cache_version = _abc_invalidation_counter
+    elif subclass in cls._abc_negative_cache:
+        return False
+    # Check the subclass hook
+    ok = cls.__subclasshook__(subclass)
+    if ok is not NotImplemented:
+        assert isinstance(ok, bool)
+        if ok:
+            cls._abc_cache.add(subclass)
+        else:
+            cls._abc_negative_cache.add(subclass)
+        return ok
+    # Check if it's a direct subclass
+    if cls in getattr(subclass, '__mro__', ()):
+        cls._abc_cache.add(subclass)
+        return True
+    # Check if it's a subclass of a registered class (recursive)
+    for rcls in cls._abc_registry:
+        if issubclass(subclass, rcls):
+            cls._abc_cache.add(subclass)
+            return True
+    # Check if it's a subclass of a subclass (recursive)
+    for scls in cls.__subclasses__():
+        if issubclass(subclass, scls):
+            cls._abc_cache.add(subclass)
+            return True
+    # No dice; update negative cache
+    cls._abc_negative_cache.add(subclass)
+    return False
+
+
+def _get_dump(cls):
+    """Internal ABC helper for cache and registry debugging
+
+    Return shallow copies of registry, of both caches, and
+    negative cache version. Don't call this function directly,
+    instead use ABC._dump_registry() for a nice repr."""
+    return (cls._abc_registry, cls._abc_cache, cls._abc_negative_cache, 
cls._abc_negative_cache_version)
+
+
+def _reset_registry(cls):
+    """Internal ABC helper to reset registry of a given class.
+
+    Should be only used by refleak.py"""
+    cls._abc_registry.clear()
+
+
+def _reset_caches(cls):
+    """Internal ABC helper to reset both caches of a given class.
+
+    Should be only used by refleak.py"""
+    cls._abc_cache.clear()
+    cls._abc_negative_cache.clear()
diff --git a/pypy/module/_abc/moduledef.py b/pypy/module/_abc/moduledef.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_abc/moduledef.py
@@ -0,0 +1,17 @@
+from pypy.interpreter.mixedmodule import MixedModule
+
+class Module(MixedModule):
+
+    appleveldefs = {
+        "get_cache_token": "app_abc.get_cache_token",
+        "_abc_init": "app_abc._abc_init",
+        "_abc_register": "app_abc._abc_register",
+        "_abc_instancecheck": "app_abc._abc_instancecheck",
+        "_abc_subclasscheck": "app_abc._abc_subclasscheck",
+        "_get_dump": "app_abc._get_dump",
+        "_reset_registry": "app_abc._reset_registry",
+        "_reset_caches": "app_abc._reset_caches",
+    }
+
+    interpleveldefs = {
+    }
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to