Skip to content

Commit

Permalink
Merge branch 'migrate'
Browse files Browse the repository at this point in the history
  • Loading branch information
jaraco committed Aug 28, 2023
2 parents 55e3c63 + 7c092fb commit 2c260c4
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 425 deletions.
1 change: 1 addition & 0 deletions newsfragments/+abaf87af.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Re-synced implementation with CPython 3.8, removing the compatibility code introduced for compatibility with older Pythons.
62 changes: 23 additions & 39 deletions singledispatch/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
__all__ = ['singledispatch', 'singledispatchmethod']

from weakref import WeakKeyDictionary

from .helpers import MappingProxyType, get_cache_token, get_type_hints, update_wrapper
from abc import get_cache_token
from functools import update_wrapper

################################################################################
# singledispatch() - single-dispatch generic function decorator
Expand Down Expand Up @@ -161,25 +160,6 @@ def _find_impl(cls, registry):
return registry.get(match)


def _validate_annotation(annotation):
"""Determine if an annotation is valid for registration.
An annotation is considered valid for use in registration if it is an
instance of ``type`` and not a generic type from ``typing``.
"""
try:
# In Python earlier than 3.7, the classes in typing are considered
# instances of type, but they invalid for registering single dispatch
# functions so check against GenericMeta instead.
from typing import GenericMeta

valid = not isinstance(annotation, GenericMeta)
except ImportError:
# In Python 3.7+, classes in typing are not instances of type.
valid = isinstance(annotation, type)
return valid


def singledispatch(func): # noqa: C901
"""Single-dispatch generic function decorator.
Expand All @@ -189,13 +169,14 @@ def singledispatch(func): # noqa: C901
implementations can be registered using the register() attribute of the
generic function.
"""
registry = {}
dispatch_cache = WeakKeyDictionary()

def ns():
pass
# There are many programs that use functools without singledispatch, so we
# trade-off making singledispatch marginally slower for the benefit of
# making start-up of such applications slightly faster.
import types, weakref # noqa: E401

ns.cache_token = None
registry = {}
dispatch_cache = weakref.WeakKeyDictionary()
cache_token = None

def dispatch(cls):
"""generic_func.dispatch(cls) -> <function implementation>
Expand All @@ -204,11 +185,12 @@ def dispatch(cls):
for the given *cls* registered on *generic_func*.
"""
if ns.cache_token is not None:
nonlocal cache_token
if cache_token is not None:
current_token = get_cache_token()
if ns.cache_token != current_token:
if cache_token != current_token:
dispatch_cache.clear()
ns.cache_token = current_token
cache_token = current_token
try:
impl = dispatch_cache[cls]
except KeyError:
Expand All @@ -225,6 +207,7 @@ def register(cls, func=None):
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)
Expand All @@ -237,30 +220,31 @@ def register(cls, func=None):
)
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 _validate_annotation(cls):
if not isinstance(cls, type):
raise TypeError(
f"Invalid annotation for {argname!r}. " f"{cls!r} is not a class."
)
registry[cls] = func
if ns.cache_token is None and hasattr(cls, '__abstractmethods__'):
ns.cache_token = get_cache_token()
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(
'{} requires at least ' '1 positional argument'.format(funcname)
)
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 = MappingProxyType(registry)
wrapper.registry = types.MappingProxyType(registry)
wrapper._clear_cache = dispatch_cache.clear
update_wrapper(wrapper, func)
return wrapper
Expand All @@ -282,7 +266,7 @@ def __init__(self, func):
self.func = func

def register(self, cls, method=None):
"""generic_method.register(cls, method) -> Callable
"""generic_method.register(cls, func) -> func
Registers a new implementation for the given *cls* on a *generic_method*.
"""
Expand Down
208 changes: 0 additions & 208 deletions singledispatch/helpers.py

This file was deleted.

Loading

0 comments on commit 2c260c4

Please sign in to comment.