omlish 0.0.0.dev471__py3-none-any.whl → 0.0.0.dev472__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/lite/abstract.py +54 -24
- omlish/lite/dataclasses.py +14 -0
- omlish/testing/pytest/plugins/asyncs/fixtures.py +4 -1
- {omlish-0.0.0.dev471.dist-info → omlish-0.0.0.dev472.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev471.dist-info → omlish-0.0.0.dev472.dist-info}/RECORD +10 -10
- {omlish-0.0.0.dev471.dist-info → omlish-0.0.0.dev472.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev471.dist-info → omlish-0.0.0.dev472.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev471.dist-info → omlish-0.0.0.dev472.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev471.dist-info → omlish-0.0.0.dev472.dist-info}/top_level.txt +0 -0
omlish/__about__.py
CHANGED
omlish/lite/abstract.py
CHANGED
|
@@ -3,6 +3,9 @@ import abc
|
|
|
3
3
|
import typing as ta
|
|
4
4
|
|
|
5
5
|
|
|
6
|
+
T = ta.TypeVar('T')
|
|
7
|
+
|
|
8
|
+
|
|
6
9
|
##
|
|
7
10
|
|
|
8
11
|
|
|
@@ -14,25 +17,49 @@ def is_abstract_method(obj: ta.Any) -> bool:
|
|
|
14
17
|
return bool(getattr(obj, _IS_ABSTRACT_METHOD_ATTR, False))
|
|
15
18
|
|
|
16
19
|
|
|
17
|
-
def
|
|
20
|
+
def compute_abstract_methods(cls: type) -> ta.FrozenSet[str]:
|
|
21
|
+
# ~> https://github.com/python/cpython/blob/f3476c6507381ca860eec0989f53647b13517423/Modules/_abc.c#L358
|
|
22
|
+
|
|
23
|
+
# Stage 1: direct abstract methods
|
|
24
|
+
|
|
25
|
+
abstracts = {
|
|
26
|
+
a
|
|
27
|
+
# Get items as a list to avoid mutation issues during iteration
|
|
28
|
+
for a, v in list(cls.__dict__.items())
|
|
29
|
+
if is_abstract_method(v)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# Stage 2: inherited abstract methods
|
|
33
|
+
|
|
34
|
+
for base in cls.__bases__:
|
|
35
|
+
# Get __abstractmethods__ from base if it exists
|
|
36
|
+
if (base_abstracts := getattr(base, _ABSTRACT_METHODS_ATTR, None)) is None:
|
|
37
|
+
continue
|
|
38
|
+
|
|
39
|
+
# Iterate over abstract methods in base
|
|
40
|
+
for key in base_abstracts:
|
|
41
|
+
# Check if this class has an attribute with this name
|
|
42
|
+
try:
|
|
43
|
+
value = getattr(cls, key)
|
|
44
|
+
except AttributeError:
|
|
45
|
+
# Attribute not found in this class, skip
|
|
46
|
+
continue
|
|
47
|
+
|
|
48
|
+
# Check if it's still abstract
|
|
49
|
+
if is_abstract_method(value):
|
|
50
|
+
abstracts.add(key)
|
|
51
|
+
|
|
52
|
+
return frozenset(abstracts)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def update_abstracts(cls: ta.Type[T], *, force: bool = False) -> ta.Type[T]:
|
|
18
56
|
if not force and not hasattr(cls, _ABSTRACT_METHODS_ATTR):
|
|
19
57
|
# Per stdlib: We check for __abstractmethods__ here because cls might by a C implementation or a python
|
|
20
58
|
# implementation (especially during testing), and we want to handle both cases.
|
|
21
59
|
return cls
|
|
22
60
|
|
|
23
|
-
abstracts
|
|
24
|
-
|
|
25
|
-
for scls in cls.__bases__:
|
|
26
|
-
for name in getattr(scls, _ABSTRACT_METHODS_ATTR, ()):
|
|
27
|
-
value = getattr(cls, name, None)
|
|
28
|
-
if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
|
|
29
|
-
abstracts.add(name)
|
|
30
|
-
|
|
31
|
-
for name, value in cls.__dict__.items():
|
|
32
|
-
if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
|
|
33
|
-
abstracts.add(name)
|
|
34
|
-
|
|
35
|
-
setattr(cls, _ABSTRACT_METHODS_ATTR, frozenset(abstracts))
|
|
61
|
+
abstracts = compute_abstract_methods(cls)
|
|
62
|
+
setattr(cls, _ABSTRACT_METHODS_ATTR, abstracts)
|
|
36
63
|
return cls
|
|
37
64
|
|
|
38
65
|
|
|
@@ -86,23 +113,26 @@ class Abstract:
|
|
|
86
113
|
super().__init_subclass__(**kwargs)
|
|
87
114
|
|
|
88
115
|
if not (Abstract in cls.__bases__ or abc.ABC in cls.__bases__):
|
|
89
|
-
ams
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
116
|
+
if ams := compute_abstract_methods(cls):
|
|
117
|
+
amd = {
|
|
118
|
+
a: mcls
|
|
119
|
+
for mcls in cls.__mro__[::-1]
|
|
120
|
+
for a in ams
|
|
121
|
+
if a in mcls.__dict__
|
|
122
|
+
}
|
|
95
123
|
|
|
96
|
-
if ams:
|
|
97
124
|
raise AbstractTypeError(
|
|
98
125
|
f'Cannot subclass abstract class {cls.__name__} with abstract methods: ' +
|
|
99
126
|
', '.join(sorted([
|
|
100
127
|
'.'.join([
|
|
101
|
-
*([
|
|
102
|
-
|
|
128
|
+
*([
|
|
129
|
+
*([m] if (m := getattr(c, '__module__')) else []),
|
|
130
|
+
getattr(c, '__qualname__', getattr(c, '__name__')),
|
|
131
|
+
] if c is not None else '?'),
|
|
103
132
|
a,
|
|
104
133
|
])
|
|
105
|
-
for a
|
|
134
|
+
for a in ams
|
|
135
|
+
for c in [amd.get(a)]
|
|
106
136
|
])),
|
|
107
137
|
)
|
|
108
138
|
|
omlish/lite/dataclasses.py
CHANGED
|
@@ -191,3 +191,17 @@ def dataclass_kw_only_init():
|
|
|
191
191
|
return cls
|
|
192
192
|
|
|
193
193
|
return inner
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
##
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@dc.dataclass()
|
|
200
|
+
class DataclassFieldRequiredError(Exception):
|
|
201
|
+
name: str
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def dataclass_field_required(name: str) -> ta.Callable[[], ta.Any]:
|
|
205
|
+
def inner() -> ta.NoReturn:
|
|
206
|
+
raise DataclassFieldRequiredError(name)
|
|
207
|
+
return inner
|
|
@@ -141,7 +141,10 @@ class AsyncsFixture:
|
|
|
141
141
|
finally:
|
|
142
142
|
nursery_fixture.cancel_scope.cancel()
|
|
143
143
|
|
|
144
|
-
except
|
|
144
|
+
except* (Skipped, XFailed):
|
|
145
|
+
pass
|
|
146
|
+
|
|
147
|
+
except* BaseException as exc: # noqa
|
|
145
148
|
test_ctx.crash(self, exc)
|
|
146
149
|
|
|
147
150
|
finally:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
omlish/.omlish-manifests.json,sha256=FLw7xkPiSXuImZgqSP8BwrEib2R1doSzUPLUkc-QUIA,8410
|
|
2
|
-
omlish/__about__.py,sha256=
|
|
2
|
+
omlish/__about__.py,sha256=4-bUUNkRfpsKN_j34JrHTQA3yrraoqE3_gcf_eEzYFg,3611
|
|
3
3
|
omlish/__init__.py,sha256=SsyiITTuK0v74XpKV8dqNaCmjOlan1JZKrHQv5rWKPA,253
|
|
4
4
|
omlish/c3.py,sha256=ZNIMl1kwg3qdei4DiUrJPQe5M81S1e76N-GuNSwLBAE,8683
|
|
5
5
|
omlish/cached.py,sha256=MLap_p0rdGoDIMVhXVHm1tsbcWobJF0OanoodV03Ju8,542
|
|
@@ -479,7 +479,7 @@ omlish/lifecycles/manager.py,sha256=92s1IH_gDP25PM5tFuPMP2hD_6s5fPi_VzZiDS5549g,
|
|
|
479
479
|
omlish/lifecycles/states.py,sha256=6gTdY3hn7-1sJ60lA3GeMx5RVKvXtFBBXE4KEjoO1Hs,1297
|
|
480
480
|
omlish/lifecycles/transitions.py,sha256=3IFdWGtAeoy3XRlIyW7yCKV4e4Iof9ytkqklGMRFYQs,1944
|
|
481
481
|
omlish/lite/__init__.py,sha256=cyZEpGob7XjU8DohyNxVe5CQRk4CQ5vrHL42OdhQb8w,148
|
|
482
|
-
omlish/lite/abstract.py,sha256=
|
|
482
|
+
omlish/lite/abstract.py,sha256=uXKPgubjZmV3J_py2yZJRUyPtcYzlSGkZ5IqlT32_Dk,4926
|
|
483
483
|
omlish/lite/args.py,sha256=ILJXAiN3KjIoJwY42aKpYPngUdxHIy9ssVIExFVz3fE,978
|
|
484
484
|
omlish/lite/asyncs.py,sha256=ITnHvg1gq4Wl6PmhwK6DTKriNLBfxFfiVLE9QL6LEHk,3254
|
|
485
485
|
omlish/lite/attrops.py,sha256=02DNBjOl27NjznkwolgPwtWpA1q3UPUuwOjHsgG4oLo,11381
|
|
@@ -487,7 +487,7 @@ omlish/lite/cached.py,sha256=AF0PdB2k4h2dyNc5tzrmnNrb9zKnoMPQU3WA8KrhS_o,3108
|
|
|
487
487
|
omlish/lite/check.py,sha256=ytCkwZoKfOlJqylL-AGm8C2WfsWJd2q3kFbnZCzX3_M,13844
|
|
488
488
|
omlish/lite/configs.py,sha256=4-1uVxo-aNV7vMKa7PVNhM610eejG1WepB42-Dw2xQI,914
|
|
489
489
|
omlish/lite/contextmanagers.py,sha256=usDzBoNqJi98AccVlwgZoMvoBXOe9wyx2MreZtWhJy4,5863
|
|
490
|
-
omlish/lite/dataclasses.py,sha256=
|
|
490
|
+
omlish/lite/dataclasses.py,sha256=Kxr68nTinRAkdWFGeu8C2qLul8iw6bxpbqqp20yxZfg,5064
|
|
491
491
|
omlish/lite/imports.py,sha256=GyEDKL-WuHtdOKIL-cc8aFd0-bHwZFDEjAB52ItabX0,1341
|
|
492
492
|
omlish/lite/inject.py,sha256=BQgjBj2mzJgMimLam-loSpQzcb31-8NYPVRQgHVv3cQ,29159
|
|
493
493
|
omlish/lite/json.py,sha256=m0Ce9eqUZG23-H7-oOp8n1sf4fzno5vtK4AK_4Vc-Mg,706
|
|
@@ -800,7 +800,7 @@ omlish/testing/pytest/plugins/spacing.py,sha256=zgqJqH1EMFS--LmduSsatGhzaOK8bBGj
|
|
|
800
800
|
omlish/testing/pytest/plugins/utils.py,sha256=7NZIe_AiblFEm7fIOL66up4k0sdBL3RZgjRV7yzPrDs,266
|
|
801
801
|
omlish/testing/pytest/plugins/asyncs/__init__.py,sha256=TTNhFmP_krug1973sq_bpWBTIvg68-1nbuVLSs92Z6k,41
|
|
802
802
|
omlish/testing/pytest/plugins/asyncs/consts.py,sha256=0NOCkzV43dOu3u97BqYMQ4mPG8JuFncpWibkOZpCqX4,55
|
|
803
|
-
omlish/testing/pytest/plugins/asyncs/fixtures.py,sha256=
|
|
803
|
+
omlish/testing/pytest/plugins/asyncs/fixtures.py,sha256=2m0wdmvehLGI0JI1auNP1xxzjwlPrlsgGBlodMkxXOA,11319
|
|
804
804
|
omlish/testing/pytest/plugins/asyncs/plugin.py,sha256=cQEdInjYxXswOMexTdZTkcNpM3RKeQiKxdS7fjwIsq0,6088
|
|
805
805
|
omlish/testing/pytest/plugins/asyncs/utils.py,sha256=YYh6XW_WmHnQCWw1jUMi0HOX_PkRnM-u5_dlVth2tt8,299
|
|
806
806
|
omlish/testing/pytest/plugins/asyncs/backends/__init__.py,sha256=DpJGt5KA2N2pNXy59raVyJH1969M1AP80pJAqIlNEAs,359
|
|
@@ -842,9 +842,9 @@ omlish/typedvalues/marshal.py,sha256=2xqX6JllhtGpmeYkU7C-qzgU__0x-vd6CzYbAsocQlc
|
|
|
842
842
|
omlish/typedvalues/of_.py,sha256=UXkxSj504WI2UrFlqdZJbu2hyDwBhL7XVrc2qdR02GQ,1309
|
|
843
843
|
omlish/typedvalues/reflect.py,sha256=PAvKW6T4cW7u--iX80w3HWwZUS3SmIZ2_lQjT65uAyk,1026
|
|
844
844
|
omlish/typedvalues/values.py,sha256=ym46I-q2QJ_6l4UlERqv3yj87R-kp8nCKMRph0xQ3UA,1307
|
|
845
|
-
omlish-0.0.0.
|
|
846
|
-
omlish-0.0.0.
|
|
847
|
-
omlish-0.0.0.
|
|
848
|
-
omlish-0.0.0.
|
|
849
|
-
omlish-0.0.0.
|
|
850
|
-
omlish-0.0.0.
|
|
845
|
+
omlish-0.0.0.dev472.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
|
846
|
+
omlish-0.0.0.dev472.dist-info/METADATA,sha256=YdE7vkMrfcNoa_DIKW5K9O1_DbzdmLKAYEdiUS3kw2Y,18999
|
|
847
|
+
omlish-0.0.0.dev472.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
848
|
+
omlish-0.0.0.dev472.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
|
|
849
|
+
omlish-0.0.0.dev472.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
|
|
850
|
+
omlish-0.0.0.dev472.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|