omlish 0.0.0.dev452__py3-none-any.whl → 0.0.0.dev454__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omlish/__about__.py +2 -2
- omlish/collections/__init__.py +7 -1
- omlish/collections/attrregistry.py +182 -0
- omlish/collections/identity.py +1 -0
- omlish/collections/mappings.py +25 -0
- omlish/dataclasses/__init__.py +2 -0
- omlish/dispatch/methods.py +50 -140
- omlish/dom/rendering.py +1 -1
- omlish/funcs/guard.py +225 -0
- omlish/graphs/dot/rendering.py +1 -1
- omlish/lang/__init__.py +1 -0
- omlish/lang/iterables.py +8 -0
- omlish/lite/attrops.py +2 -0
- omlish/lite/dataclasses.py +30 -0
- omlish/lite/maybes.py +8 -0
- omlish/marshal/__init__.py +12 -11
- omlish/marshal/base/contexts.py +4 -7
- omlish/marshal/base/funcs.py +16 -11
- omlish/marshal/base/types.py +17 -7
- omlish/marshal/composite/iterables.py +31 -20
- omlish/marshal/composite/literals.py +14 -18
- omlish/marshal/composite/mappings.py +34 -23
- omlish/marshal/composite/maybes.py +27 -19
- omlish/marshal/composite/newtypes.py +14 -14
- omlish/marshal/composite/optionals.py +12 -14
- omlish/marshal/composite/special.py +13 -13
- omlish/marshal/composite/unions/__init__.py +0 -0
- omlish/marshal/composite/unions/literals.py +91 -0
- omlish/marshal/composite/unions/primitives.py +101 -0
- omlish/marshal/factories/invalidate.py +16 -66
- omlish/marshal/factories/method.py +28 -0
- omlish/marshal/factories/moduleimport/factories.py +13 -54
- omlish/marshal/factories/multi.py +11 -23
- omlish/marshal/factories/recursive.py +40 -56
- omlish/marshal/factories/typecache.py +23 -75
- omlish/marshal/factories/typemap.py +40 -41
- omlish/marshal/objects/dataclasses.py +106 -97
- omlish/marshal/objects/marshal.py +15 -12
- omlish/marshal/objects/namedtuples.py +46 -40
- omlish/marshal/objects/unmarshal.py +16 -13
- omlish/marshal/polymorphism/marshal.py +6 -9
- omlish/marshal/polymorphism/unions.py +15 -9
- omlish/marshal/polymorphism/unmarshal.py +6 -8
- omlish/marshal/singular/enums.py +12 -18
- omlish/marshal/standard.py +8 -8
- omlish/marshal/trivial/forbidden.py +19 -24
- omlish/os/forkhooks.py +4 -0
- omlish/specs/jsonrpc/_marshal.py +33 -24
- omlish/specs/openapi/_marshal.py +20 -17
- omlish/sql/queries/rendering.py +1 -1
- omlish/text/parts.py +2 -2
- omlish/typedvalues/marshal.py +81 -55
- {omlish-0.0.0.dev452.dist-info → omlish-0.0.0.dev454.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev452.dist-info → omlish-0.0.0.dev454.dist-info}/RECORD +58 -55
- omlish/marshal/composite/unions.py +0 -213
- omlish/marshal/factories/match.py +0 -34
- omlish/marshal/factories/simple.py +0 -28
- {omlish-0.0.0.dev452.dist-info → omlish-0.0.0.dev454.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev452.dist-info → omlish-0.0.0.dev454.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev452.dist-info → omlish-0.0.0.dev454.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev452.dist-info → omlish-0.0.0.dev454.dist-info}/top_level.txt +0 -0
omlish/__about__.py
CHANGED
omlish/collections/__init__.py
CHANGED
@@ -6,6 +6,11 @@ from .. import lang as _lang
|
|
6
6
|
with _lang.auto_proxy_init(globals()):
|
7
7
|
##
|
8
8
|
|
9
|
+
from .attrregistry import ( # noqa
|
10
|
+
AttrRegistry,
|
11
|
+
AttrRegistryCache,
|
12
|
+
)
|
13
|
+
|
9
14
|
from .bimap import ( # noqa
|
10
15
|
BiMap,
|
11
16
|
|
@@ -64,9 +69,10 @@ with _lang.auto_proxy_init(globals()):
|
|
64
69
|
from . import kv # noqa
|
65
70
|
|
66
71
|
from .mappings import ( # noqa
|
72
|
+
DynamicTypeMap,
|
67
73
|
MissingDict,
|
68
74
|
TypeMap,
|
69
|
-
|
75
|
+
dict_factory,
|
70
76
|
guarded_map_update,
|
71
77
|
multikey_dict,
|
72
78
|
)
|
@@ -0,0 +1,182 @@
|
|
1
|
+
import dataclasses as dc
|
2
|
+
import typing as ta
|
3
|
+
import weakref
|
4
|
+
|
5
|
+
from .. import check
|
6
|
+
from .. import lang
|
7
|
+
from .mappings import dict_factory
|
8
|
+
|
9
|
+
|
10
|
+
T = ta.TypeVar('T')
|
11
|
+
K = ta.TypeVar('K')
|
12
|
+
V = ta.TypeVar('V')
|
13
|
+
|
14
|
+
|
15
|
+
##
|
16
|
+
|
17
|
+
|
18
|
+
class AttrRegistry(ta.Generic[K, V]):
|
19
|
+
"""
|
20
|
+
MRO-honoring class member registry. There are many ways to do this, and this one is attr name based: a class is
|
21
|
+
considered to have objects registered to it based on whether or not they are accessible by a non-shadowed,
|
22
|
+
MRO-resolved named attribute on that class.
|
23
|
+
|
24
|
+
Care must be taken when overriding registered objects from superclasses in subclasses - shadowing the attribute name
|
25
|
+
of the superclass member will not automatically register the new member with the same name to the registry - it must
|
26
|
+
be explicitly registered itself. This is a feature, allowing for selective de-registration of objects in subclasses
|
27
|
+
via name shadowing.
|
28
|
+
"""
|
29
|
+
|
30
|
+
def __init__(
|
31
|
+
self,
|
32
|
+
*,
|
33
|
+
requires_override: bool = False,
|
34
|
+
is_override: ta.Callable[[ta.Any], bool] | None = None,
|
35
|
+
forbid_duplicates: bool = False,
|
36
|
+
identity: bool = False,
|
37
|
+
weak: bool = False,
|
38
|
+
) -> None:
|
39
|
+
super().__init__()
|
40
|
+
|
41
|
+
self._requires_override = requires_override
|
42
|
+
self._is_override = is_override
|
43
|
+
self._forbid_duplicates = forbid_duplicates
|
44
|
+
self._identity = identity
|
45
|
+
self._weak = weak
|
46
|
+
|
47
|
+
self._objs: ta.MutableMapping[K, V] = dict_factory(identity=identity, weak=weak)()
|
48
|
+
self._invalidate_callbacks: list[ta.Callable[[], None]] = []
|
49
|
+
|
50
|
+
def add_invalidate_callback(self, callback: ta.Callable[[], None]) -> None:
|
51
|
+
self._invalidate_callbacks.append(callback)
|
52
|
+
|
53
|
+
def register(self, obj: K, val: V) -> None:
|
54
|
+
check.not_in(obj, self._objs)
|
55
|
+
|
56
|
+
self._objs[obj] = val
|
57
|
+
|
58
|
+
for iv in self._invalidate_callbacks:
|
59
|
+
iv()
|
60
|
+
|
61
|
+
def _lookup(self, obj: ta.Any) -> lang.Maybe[V]:
|
62
|
+
if not self._identity:
|
63
|
+
try:
|
64
|
+
hash(obj)
|
65
|
+
except TypeError:
|
66
|
+
return lang.empty()
|
67
|
+
|
68
|
+
try:
|
69
|
+
val = self._objs[obj]
|
70
|
+
except KeyError:
|
71
|
+
return lang.empty()
|
72
|
+
else:
|
73
|
+
return lang.just(val)
|
74
|
+
|
75
|
+
@dc.dataclass()
|
76
|
+
class DuplicatesForbiddenError(Exception):
|
77
|
+
owner_cls: type
|
78
|
+
instance_cls: type
|
79
|
+
att: str
|
80
|
+
ex_att: str
|
81
|
+
|
82
|
+
def collect(self, instance_cls: type, owner_cls: type | None = None) -> dict[str, tuple[K, V]]:
|
83
|
+
if owner_cls is None:
|
84
|
+
owner_cls = instance_cls
|
85
|
+
|
86
|
+
mro = instance_cls.__mro__[-2::-1]
|
87
|
+
try:
|
88
|
+
mro_pos = mro.index(owner_cls)
|
89
|
+
except ValueError:
|
90
|
+
raise TypeError(f'Owner class {owner_cls} not in mro of instance class {instance_cls}') from None
|
91
|
+
|
92
|
+
mro_dct: dict[str, list[tuple[type, ta.Any]]] = {}
|
93
|
+
for cur_cls in mro[:mro_pos + 1]:
|
94
|
+
for att, obj in cur_cls.__dict__.items():
|
95
|
+
if att not in mro_dct:
|
96
|
+
if not self._lookup(obj).present:
|
97
|
+
continue
|
98
|
+
|
99
|
+
try:
|
100
|
+
lst = mro_dct[att]
|
101
|
+
except KeyError:
|
102
|
+
lst = mro_dct[att] = []
|
103
|
+
lst.append((cur_cls, obj))
|
104
|
+
|
105
|
+
#
|
106
|
+
|
107
|
+
seen: ta.MutableMapping[ta.Any, str] | None = None
|
108
|
+
if self._forbid_duplicates:
|
109
|
+
seen = dict_factory(identity=self._identity)()
|
110
|
+
|
111
|
+
out: dict[str, tuple[K, V]] = {}
|
112
|
+
for att, lst in mro_dct.items():
|
113
|
+
if not lst:
|
114
|
+
raise RuntimeError
|
115
|
+
_, obj = lst[-1]
|
116
|
+
|
117
|
+
if len(lst) > 1:
|
118
|
+
if self._requires_override and not (self._is_override or lang.is_override)(obj):
|
119
|
+
raise lang.RequiresOverrideError(
|
120
|
+
att,
|
121
|
+
instance_cls,
|
122
|
+
lst[-1][0],
|
123
|
+
lst[0][0],
|
124
|
+
)
|
125
|
+
|
126
|
+
if not (mv := self._lookup(obj)).present:
|
127
|
+
continue
|
128
|
+
|
129
|
+
if seen is not None:
|
130
|
+
try:
|
131
|
+
ex_att = seen[obj]
|
132
|
+
except KeyError:
|
133
|
+
pass
|
134
|
+
else:
|
135
|
+
raise AttrRegistry.DuplicatesForbiddenError(owner_cls, instance_cls, att, ex_att) # noqa
|
136
|
+
seen[obj] = att
|
137
|
+
|
138
|
+
out[att] = (obj, mv.must())
|
139
|
+
|
140
|
+
return out
|
141
|
+
|
142
|
+
|
143
|
+
##
|
144
|
+
|
145
|
+
|
146
|
+
class AttrRegistryCache(ta.Generic[K, V, T]):
|
147
|
+
def __init__(
|
148
|
+
self,
|
149
|
+
registry: AttrRegistry[K, V],
|
150
|
+
prepare: ta.Callable[[type, dict[str, tuple[K, V]]], T],
|
151
|
+
) -> None:
|
152
|
+
super().__init__()
|
153
|
+
|
154
|
+
self._registry = registry
|
155
|
+
self._prepare = prepare
|
156
|
+
|
157
|
+
self._cache: dict[ta.Any, T] = {}
|
158
|
+
|
159
|
+
def cache_remove(k, self_ref=weakref.ref(self)):
|
160
|
+
if (ref_self := self_ref()) is not None:
|
161
|
+
cache = ref_self._cache # noqa
|
162
|
+
try:
|
163
|
+
del cache[k]
|
164
|
+
except KeyError:
|
165
|
+
pass
|
166
|
+
|
167
|
+
self._cache_remove = cache_remove
|
168
|
+
|
169
|
+
registry.add_invalidate_callback(self._cache.clear)
|
170
|
+
|
171
|
+
def get(self, instance_cls: type) -> T:
|
172
|
+
cls_ref = weakref.ref(instance_cls)
|
173
|
+
try:
|
174
|
+
return self._cache[cls_ref]
|
175
|
+
except KeyError:
|
176
|
+
pass
|
177
|
+
del cls_ref
|
178
|
+
|
179
|
+
collected = self._registry.collect(instance_cls)
|
180
|
+
out = self._prepare(instance_cls, collected)
|
181
|
+
self._cache[weakref.ref(instance_cls, self._cache_remove)] = out
|
182
|
+
return out
|
omlish/collections/identity.py
CHANGED
omlish/collections/mappings.py
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
import typing as ta
|
2
2
|
import weakref
|
3
3
|
|
4
|
+
from .. import lang
|
5
|
+
|
6
|
+
|
7
|
+
with lang.auto_proxy_import(globals()):
|
8
|
+
from . import identity as _identity
|
9
|
+
|
4
10
|
|
5
11
|
T = ta.TypeVar('T')
|
6
12
|
K = ta.TypeVar('K')
|
@@ -141,3 +147,22 @@ class MissingDict(dict[K, V]):
|
|
141
147
|
def __missing__(self, key):
|
142
148
|
v = self[key] = self._missing_fn(key)
|
143
149
|
return v
|
150
|
+
|
151
|
+
|
152
|
+
##
|
153
|
+
|
154
|
+
|
155
|
+
def dict_factory[K, V](
|
156
|
+
*,
|
157
|
+
identity: bool = False,
|
158
|
+
weak: bool = False,
|
159
|
+
) -> ta.Callable[..., ta.MutableMapping[K, V]]:
|
160
|
+
if identity:
|
161
|
+
if weak:
|
162
|
+
return _identity.IdentityWeakKeyDictionary
|
163
|
+
else:
|
164
|
+
return _identity.IdentityKeyDict
|
165
|
+
elif weak:
|
166
|
+
return weakref.WeakKeyDictionary
|
167
|
+
else:
|
168
|
+
return dict
|
omlish/dataclasses/__init__.py
CHANGED
omlish/dispatch/methods.py
CHANGED
@@ -4,13 +4,11 @@ TODO:
|
|
4
4
|
- ALT: A.f(super(), ... ? :/
|
5
5
|
- classmethod/staticmethod
|
6
6
|
"""
|
7
|
-
import contextlib
|
8
7
|
import functools
|
9
8
|
import typing as ta
|
10
|
-
import weakref
|
11
9
|
|
12
10
|
from .. import check
|
13
|
-
from .. import
|
11
|
+
from .. import collections as col
|
14
12
|
from .dispatch import Dispatcher
|
15
13
|
from .impls import get_impl_func_cls_set
|
16
14
|
|
@@ -34,9 +32,8 @@ class Method(ta.Generic[P, R]):
|
|
34
32
|
it must be explicitly `@register`'ed itself. This is a feature, allowing for selective de-registration of
|
35
33
|
implementations in subclasses via name shadowing.
|
36
34
|
|
37
|
-
Methods
|
38
|
-
|
39
|
-
visitors.
|
35
|
+
Methods can choose to allow external installation of implementations outside of direct subclasses. This is to be
|
36
|
+
used *extremely* rarely - basically only in the rare case of externally extensible type hierarchies with visitors.
|
40
37
|
"""
|
41
38
|
|
42
39
|
def __init__(
|
@@ -45,6 +42,7 @@ class Method(ta.Generic[P, R]):
|
|
45
42
|
*,
|
46
43
|
installable: bool = False,
|
47
44
|
requires_override: bool = False,
|
45
|
+
instance_cache: bool = False,
|
48
46
|
) -> None:
|
49
47
|
super().__init__()
|
50
48
|
|
@@ -53,9 +51,16 @@ class Method(ta.Generic[P, R]):
|
|
53
51
|
|
54
52
|
self._func = func
|
55
53
|
self._installable = installable
|
56
|
-
self.
|
54
|
+
self._instance_cache = instance_cache
|
57
55
|
|
58
|
-
self.
|
56
|
+
self._registry: col.AttrRegistry[ta.Callable, Method._Entry] = col.AttrRegistry(
|
57
|
+
requires_override=requires_override,
|
58
|
+
)
|
59
|
+
|
60
|
+
self._cache: col.AttrRegistryCache[ta.Callable, Method._Entry, ta.Callable] = col.AttrRegistryCache(
|
61
|
+
self._registry,
|
62
|
+
self._prepare,
|
63
|
+
)
|
59
64
|
|
60
65
|
# bpo-45678: special-casing for classmethod/staticmethod in Python <=3.9, as functools.update_wrapper doesn't
|
61
66
|
# work properly in singledispatchmethod.__get__ if it is applied to an unbound classmethod/staticmethod
|
@@ -68,19 +73,12 @@ class Method(ta.Generic[P, R]):
|
|
68
73
|
self._is_abstractmethod = getattr(func, '__isabstractmethod__', False) # noqa
|
69
74
|
self.update_wrapper(self)
|
70
75
|
|
71
|
-
self._dispatch_func_cache: dict[ta.Any, ta.Callable] = {}
|
72
|
-
|
73
|
-
def dispatch_func_cache_remove(k, self_ref=weakref.ref(self)):
|
74
|
-
if (ref_self := self_ref()) is not None:
|
75
|
-
cache = ref_self._dispatch_func_cache # noqa
|
76
|
-
with contextlib.suppress(KeyError):
|
77
|
-
del cache[k]
|
78
|
-
|
79
|
-
self._dispatch_func_cache_remove = dispatch_func_cache_remove
|
80
|
-
|
81
76
|
self._owner: type | None = None
|
82
77
|
self._name: str | None = None
|
83
78
|
|
79
|
+
class _Entry:
|
80
|
+
cls_set: frozenset[type]
|
81
|
+
|
84
82
|
def __set_name__(self, owner, name):
|
85
83
|
if self._owner is None:
|
86
84
|
self._owner = owner
|
@@ -102,83 +100,29 @@ class Method(ta.Generic[P, R]):
|
|
102
100
|
|
103
101
|
def register(self, impl: T, cls_set: frozenset[type] | None = None) -> T:
|
104
102
|
check.callable(impl)
|
105
|
-
if impl not in self._impls:
|
106
|
-
self._impls[impl] = cls_set # type: ignore
|
107
|
-
self._dispatch_func_cache.clear()
|
108
|
-
|
109
|
-
return impl
|
110
|
-
|
111
|
-
def _is_impl(self, obj: ta.Any) -> bool:
|
112
|
-
try:
|
113
|
-
hash(obj)
|
114
|
-
except TypeError:
|
115
|
-
return False
|
116
|
-
|
117
|
-
return obj in self._impls
|
118
103
|
|
119
|
-
|
120
|
-
if
|
121
|
-
|
104
|
+
entry = Method._Entry()
|
105
|
+
if cls_set is not None:
|
106
|
+
entry.cls_set = cls_set
|
122
107
|
|
123
|
-
|
124
|
-
try:
|
125
|
-
mro_pos = mro.index(owner_cls)
|
126
|
-
except ValueError:
|
127
|
-
raise TypeError(f'Owner class {owner_cls} not in mro of instance class {instance_cls}') from None
|
108
|
+
self._registry.register(ta.cast(ta.Callable, impl), entry)
|
128
109
|
|
129
|
-
|
130
|
-
for cur_cls in mro[:mro_pos + 1]:
|
131
|
-
for att, obj in cur_cls.__dict__.items():
|
132
|
-
if att not in mro_dct:
|
133
|
-
if not self._is_impl(obj):
|
134
|
-
continue
|
135
|
-
|
136
|
-
try:
|
137
|
-
lst = mro_dct[att]
|
138
|
-
except KeyError:
|
139
|
-
lst = mro_dct[att] = []
|
140
|
-
lst.append((cur_cls, obj))
|
141
|
-
|
142
|
-
#
|
110
|
+
return impl
|
143
111
|
|
112
|
+
def _build_dispatcher(self, collected: ta.Mapping[str, tuple[ta.Callable, _Entry]]) -> Dispatcher[str]:
|
144
113
|
disp: Dispatcher[str] = Dispatcher()
|
145
114
|
|
146
|
-
|
147
|
-
for att, lst in mro_dct.items():
|
148
|
-
if not lst:
|
149
|
-
raise RuntimeError
|
150
|
-
_, obj = lst[-1]
|
151
|
-
|
152
|
-
if len(lst) > 1:
|
153
|
-
if self._requires_override and not lang.is_override(obj):
|
154
|
-
raise lang.RequiresOverrideError(
|
155
|
-
att,
|
156
|
-
instance_cls,
|
157
|
-
lst[-1][0],
|
158
|
-
lst[0][0],
|
159
|
-
)
|
160
|
-
|
161
|
-
if not self._is_impl(obj):
|
162
|
-
continue
|
163
|
-
|
164
|
-
cls_set = self._impls[obj]
|
165
|
-
if cls_set is None:
|
166
|
-
cls_set = get_impl_func_cls_set(obj, arg_offset=1)
|
167
|
-
self._impls[obj] = cls_set
|
168
|
-
|
115
|
+
for a, (f, e) in collected.items():
|
169
116
|
try:
|
170
|
-
|
171
|
-
except
|
172
|
-
|
173
|
-
else:
|
174
|
-
raise TypeError(f'Duplicate impl: {owner_cls} {instance_cls} {att} {ex_att}')
|
175
|
-
seen[obj] = att
|
117
|
+
cls_set = e.cls_set
|
118
|
+
except AttributeError:
|
119
|
+
cls_set = e.cls_set = get_impl_func_cls_set(f, arg_offset=1)
|
176
120
|
|
177
|
-
disp.register(
|
121
|
+
disp.register(a, cls_set)
|
178
122
|
|
179
123
|
return disp
|
180
124
|
|
181
|
-
def
|
125
|
+
def _build_dispatch_func(self, disp: Dispatcher[str]) -> ta.Callable:
|
182
126
|
dispatch = disp.dispatch
|
183
127
|
type_ = type
|
184
128
|
getattr_ = getattr
|
@@ -190,25 +134,16 @@ class Method(ta.Generic[P, R]):
|
|
190
134
|
raise TypeError(f'{func_name} requires at least 1 positional argument')
|
191
135
|
|
192
136
|
if (impl_att := dispatch(type_(args[0]))) is not None:
|
193
|
-
|
194
|
-
return fn(*args, **kwargs)
|
137
|
+
return getattr_(self, impl_att)(*args, **kwargs)
|
195
138
|
|
196
139
|
return base_func.__get__(self)(*args, **kwargs) # noqa
|
197
140
|
|
198
141
|
self.update_wrapper(__call__)
|
199
142
|
return __call__
|
200
143
|
|
201
|
-
def
|
202
|
-
|
203
|
-
|
204
|
-
return self._dispatch_func_cache[cls_ref]
|
205
|
-
except KeyError:
|
206
|
-
pass
|
207
|
-
del cls_ref
|
208
|
-
|
209
|
-
att_disp = self.build_attr_dispatcher(instance_cls)
|
210
|
-
func = self.build_dispatch_func(att_disp)
|
211
|
-
self._dispatch_func_cache[weakref.ref(instance_cls, self._dispatch_func_cache_remove)] = func
|
144
|
+
def _prepare(self, instance_cls: type, collected: ta.Mapping[str, tuple[ta.Callable, _Entry]]) -> ta.Callable:
|
145
|
+
disp = self._build_dispatcher(collected)
|
146
|
+
func = self._build_dispatch_func(disp)
|
212
147
|
return func
|
213
148
|
|
214
149
|
def __get__(self, instance, owner=None):
|
@@ -216,16 +151,21 @@ class Method(ta.Generic[P, R]):
|
|
216
151
|
# FIXME: classmethod/staticmethod
|
217
152
|
return self
|
218
153
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
154
|
+
if self._instance_cache:
|
155
|
+
try:
|
156
|
+
return instance.__dict__[self._name]
|
157
|
+
except KeyError:
|
158
|
+
pass
|
159
|
+
|
160
|
+
bound = self._cache.get(type(instance)).__get__(instance, owner) # noqa
|
161
|
+
|
162
|
+
if self._instance_cache:
|
163
|
+
instance.__dict__[self._name] = bound
|
164
|
+
|
165
|
+
return bound
|
225
166
|
|
226
167
|
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R:
|
227
168
|
instance, *rest = args
|
228
|
-
instance_cls = type(instance)
|
229
169
|
|
230
170
|
# if instance_cls is super:
|
231
171
|
# owner = instance.__self_class__.__mro__[instance.__self_class__.__mro__.index(instance.__thisclass__) + 1]
|
@@ -233,55 +173,25 @@ class Method(ta.Generic[P, R]):
|
|
233
173
|
# func = self.build_dispatch_func(att_disp)
|
234
174
|
# return func.__get__(instance, instance.__thisclass__)(*rest, **kwargs)
|
235
175
|
|
236
|
-
|
237
|
-
func = self._dispatch_func_cache[weakref.ref(instance_cls)]
|
238
|
-
except KeyError:
|
239
|
-
func = self.get_dispatch_func(instance_cls)
|
240
|
-
return func.__get__(instance)(*rest, **kwargs) # noqa
|
176
|
+
return self.__get__(instance)(*rest, **kwargs)
|
241
177
|
|
242
178
|
|
243
179
|
##
|
244
180
|
|
245
181
|
|
246
|
-
@ta.overload
|
247
|
-
def method(
|
248
|
-
func: ta.Callable[P, R],
|
249
|
-
/,
|
250
|
-
*,
|
251
|
-
installable: bool = False,
|
252
|
-
requires_override: bool = False,
|
253
|
-
) -> Method[P, R]: # noqa
|
254
|
-
...
|
255
|
-
|
256
|
-
|
257
|
-
@ta.overload
|
258
182
|
def method(
|
259
|
-
func: None = None,
|
260
|
-
/,
|
261
183
|
*,
|
262
184
|
installable: bool = False,
|
263
185
|
requires_override: bool = False,
|
186
|
+
instance_cache: bool = False,
|
264
187
|
) -> ta.Callable[[ta.Callable[P, R]], Method[P, R]]: # noqa
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
def method(
|
269
|
-
func=None,
|
270
|
-
/,
|
271
|
-
*,
|
272
|
-
installable=False,
|
273
|
-
requires_override=False,
|
274
|
-
):
|
275
|
-
kw = dict(
|
188
|
+
return functools.partial(
|
189
|
+
Method, # type: ignore[arg-type]
|
276
190
|
installable=installable,
|
277
191
|
requires_override=requires_override,
|
192
|
+
instance_cache=instance_cache,
|
278
193
|
)
|
279
194
|
|
280
|
-
if func is None:
|
281
|
-
return functools.partial(Method, **kw)
|
282
|
-
|
283
|
-
return Method(func, **kw)
|
284
|
-
|
285
195
|
|
286
196
|
#
|
287
197
|
|
@@ -305,7 +215,7 @@ def install_method(
|
|
305
215
|
if on is None:
|
306
216
|
cls = owner
|
307
217
|
else:
|
308
|
-
cls = check.issubclass(on, owner)
|
218
|
+
cls = check.issubclass(on, owner) # noqa
|
309
219
|
|
310
220
|
check.arg(not hasattr(cls, a))
|
311
221
|
setattr(cls, a, fn)
|