|
15 | 15 | from abc import ABC, ABCMeta |
16 | 16 | from dataclasses import dataclass |
17 | 17 | from typing import Any |
| 18 | +from weakref import WeakKeyDictionary |
18 | 19 |
|
19 | 20 |
|
20 | 21 | ENABLED_FIELD = 'enabled' |
21 | 22 |
|
22 | 23 | _ENABLEABLE_TAG = object() |
| 24 | +_enableable_objects: WeakKeyDictionary[Any, object] = WeakKeyDictionary() |
| 25 | +_enableable_objects_by_id: dict[int, tuple[Any, object]] = {} |
| 26 | + |
| 27 | + |
| 28 | +def _remember_enableable(obj: Any) -> None: |
| 29 | + """Record explicit enableable branding without mutating the object.""" |
| 30 | + try: |
| 31 | + _enableable_objects[obj] = _ENABLEABLE_TAG |
| 32 | + except TypeError: |
| 33 | + _enableable_objects_by_id[id(obj)] = (obj, _ENABLEABLE_TAG) |
| 34 | + |
| 35 | + |
| 36 | +def _is_marked_enableable(obj: Any) -> bool: |
| 37 | + """Return whether an object was explicitly branded as enableable.""" |
| 38 | + try: |
| 39 | + if _enableable_objects.get(obj) is _ENABLEABLE_TAG: |
| 40 | + return True |
| 41 | + except TypeError: |
| 42 | + pass |
| 43 | + |
| 44 | + fallback_record = _enableable_objects_by_id.get(id(obj)) |
| 45 | + return fallback_record is not None and fallback_record[0] is obj |
23 | 46 |
|
24 | 47 |
|
25 | 48 | class EnableableMeta(ABCMeta): |
26 | 49 | """Metaclass enabling nominal isinstance checks for branded callables.""" |
27 | 50 |
|
28 | 51 | def __instancecheck__(cls, instance: Any) -> bool: # type: ignore[override] |
29 | | - if getattr(instance, '__enableable_tag__', None) is _ENABLEABLE_TAG: |
| 52 | + if _is_marked_enableable(instance): |
30 | 53 | return True |
31 | 54 | return super().__instancecheck__(instance) |
32 | 55 |
|
@@ -72,8 +95,8 @@ def mark_enableable(obj: Any, *, enabled_default: bool = True) -> Any: |
72 | 95 | sig = inspect.signature(obj) |
73 | 96 | if ENABLED_FIELD not in sig.parameters: |
74 | 97 | raise TypeError( |
75 | | - f"Enableable callable '{getattr(obj, '__name__', obj)}' must have an '{ENABLED_FIELD}' parameter" |
| 98 | + f"Enableable callable {obj!r} must have an '{ENABLED_FIELD}' parameter" |
76 | 99 | ) |
77 | 100 |
|
78 | | - setattr(obj, '__enableable_tag__', _ENABLEABLE_TAG) |
| 101 | + _remember_enableable(obj) |
79 | 102 | return obj |
0 commit comments