omlish 0.0.0.dev219__py3-none-any.whl → 0.0.0.dev220__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/antlr/dot.py +13 -6
- omlish/dataclasses/__init__.py +1 -0
- omlish/dataclasses/impl/api.py +10 -0
- omlish/dataclasses/impl/fields.py +8 -1
- omlish/dataclasses/impl/init.py +1 -1
- omlish/dataclasses/impl/main.py +1 -1
- omlish/dataclasses/impl/metaclass.py +112 -29
- omlish/dataclasses/impl/overrides.py +53 -0
- omlish/dataclasses/impl/params.py +3 -0
- omlish/dataclasses/impl/reflect.py +17 -5
- omlish/dataclasses/impl/simple.py +0 -42
- omlish/http/coro/server.py +58 -38
- omlish/http/handlers.py +8 -0
- omlish/io/fileno.py +11 -0
- omlish/lang/__init__.py +4 -1
- omlish/lang/cached.py +0 -1
- omlish/lang/classes/__init__.py +3 -1
- omlish/lang/classes/abstract.py +14 -1
- omlish/lang/classes/restrict.py +5 -5
- omlish/lang/classes/virtual.py +0 -1
- omlish/lang/clsdct.py +0 -1
- omlish/lang/contextmanagers.py +0 -8
- omlish/lang/descriptors.py +0 -1
- omlish/lang/maybes.py +0 -1
- omlish/lang/objects.py +0 -2
- omlish/secrets/ssl.py +9 -0
- omlish/secrets/tempssl.py +50 -0
- omlish/sockets/bind.py +6 -1
- omlish/sockets/server/server.py +18 -5
- {omlish-0.0.0.dev219.dist-info → omlish-0.0.0.dev220.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev219.dist-info → omlish-0.0.0.dev220.dist-info}/RECORD +36 -32
- {omlish-0.0.0.dev219.dist-info → omlish-0.0.0.dev220.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev219.dist-info → omlish-0.0.0.dev220.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev219.dist-info → omlish-0.0.0.dev220.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev219.dist-info → omlish-0.0.0.dev220.dist-info}/top_level.txt +0 -0
omlish/__about__.py
CHANGED
omlish/antlr/dot.py
CHANGED
@@ -1,12 +1,19 @@
|
|
1
|
+
import typing as ta
|
2
|
+
|
1
3
|
from ..graphs import dot
|
2
4
|
from . import runtime as antlr4
|
3
5
|
from .utils import yield_contexts
|
4
6
|
|
5
7
|
|
6
|
-
def dot_ctx(
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
def dot_ctx(
|
9
|
+
root: antlr4.ParserRuleContext,
|
10
|
+
*,
|
11
|
+
left_to_right: bool = False,
|
12
|
+
) -> dot.Graph:
|
13
|
+
stmts: list[dot.Stmt] = []
|
14
|
+
|
15
|
+
if left_to_right:
|
16
|
+
stmts.append(dot.RawStmt('rankdir=LR;'))
|
10
17
|
|
11
18
|
for c in yield_contexts(root):
|
12
19
|
if isinstance(c, antlr4.TerminalNode):
|
@@ -27,5 +34,5 @@ def dot_ctx(root: antlr4.ParserRuleContext) -> dot.Graph:
|
|
27
34
|
return dot.Graph(stmts)
|
28
35
|
|
29
36
|
|
30
|
-
def open_dot_ctx(root: antlr4.ParserRuleContext) -> None:
|
31
|
-
dot.open_dot(dot.render(dot_ctx(root)))
|
37
|
+
def open_dot_ctx(root: antlr4.ParserRuleContext, **kwargs: ta.Any) -> None:
|
38
|
+
dot.open_dot(dot.render(dot_ctx(root)), **kwargs)
|
omlish/dataclasses/__init__.py
CHANGED
omlish/dataclasses/impl/api.py
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
"""
|
2
|
+
TODO:
|
3
|
+
- fix code redundancy
|
4
|
+
"""
|
1
5
|
import collections.abc
|
2
6
|
import contextlib
|
3
7
|
import dataclasses as dc
|
@@ -91,6 +95,7 @@ def dataclass( # noqa
|
|
91
95
|
reorder=MISSING,
|
92
96
|
cache_hash=MISSING,
|
93
97
|
generic_init=MISSING,
|
98
|
+
override=MISSING,
|
94
99
|
):
|
95
100
|
def wrap(cls):
|
96
101
|
pkw = dict(
|
@@ -113,6 +118,7 @@ def dataclass( # noqa
|
|
113
118
|
reorder=reorder,
|
114
119
|
cache_hash=cache_hash,
|
115
120
|
generic_init=generic_init,
|
121
|
+
override=override,
|
116
122
|
)))
|
117
123
|
pex = ParamsExtras(**epk)
|
118
124
|
|
@@ -161,6 +167,7 @@ def make_dataclass( # noqa
|
|
161
167
|
reorder=MISSING,
|
162
168
|
cache_hash=MISSING,
|
163
169
|
generic_init=MISSING,
|
170
|
+
override=MISSING,
|
164
171
|
):
|
165
172
|
if namespace is None:
|
166
173
|
namespace = {}
|
@@ -221,6 +228,7 @@ def make_dataclass( # noqa
|
|
221
228
|
reorder=reorder,
|
222
229
|
cache_hash=cache_hash,
|
223
230
|
generic_init=generic_init,
|
231
|
+
override=override,
|
224
232
|
)
|
225
233
|
|
226
234
|
|
@@ -233,6 +241,7 @@ def extra_params( # noqa
|
|
233
241
|
reorder=MISSING,
|
234
242
|
cache_hash=MISSING,
|
235
243
|
generic_init=MISSING,
|
244
|
+
override=MISSING,
|
236
245
|
):
|
237
246
|
def inner(cls):
|
238
247
|
if PARAMS_ATTR in cls.__dict__:
|
@@ -249,6 +258,7 @@ def extra_params( # noqa
|
|
249
258
|
reorder=reorder,
|
250
259
|
cache_hash=cache_hash,
|
251
260
|
generic_init=generic_init,
|
261
|
+
override=override,
|
252
262
|
))
|
253
263
|
|
254
264
|
return cls
|
@@ -165,6 +165,7 @@ def field_init(
|
|
165
165
|
locals: dict[str, ta.Any], # noqa
|
166
166
|
self_name: str,
|
167
167
|
slots: bool,
|
168
|
+
cls_override: bool,
|
168
169
|
) -> ta.Sequence[str]:
|
169
170
|
default_name = f'__dataclass_dflt_{f.name}__'
|
170
171
|
fx = get_field_extras(f)
|
@@ -235,6 +236,12 @@ def field_init(
|
|
235
236
|
)
|
236
237
|
|
237
238
|
if value is not None and field_type(f) is not FieldType.INIT:
|
238
|
-
lines.append(field_assign(
|
239
|
+
lines.append(field_assign(
|
240
|
+
frozen,
|
241
|
+
f.name,
|
242
|
+
value,
|
243
|
+
self_name,
|
244
|
+
fx.override or cls_override,
|
245
|
+
))
|
239
246
|
|
240
247
|
return lines
|
omlish/dataclasses/impl/init.py
CHANGED
@@ -74,7 +74,6 @@ def init_param(f: dc.Field) -> str:
|
|
74
74
|
|
75
75
|
|
76
76
|
class InitBuilder:
|
77
|
-
|
78
77
|
def __init__(
|
79
78
|
self,
|
80
79
|
info: ClassInfo,
|
@@ -128,6 +127,7 @@ class InitBuilder:
|
|
128
127
|
locals,
|
129
128
|
self._self_name,
|
130
129
|
self._info.params.slots,
|
130
|
+
self._info.params_extras.override,
|
131
131
|
)
|
132
132
|
|
133
133
|
if f_lines:
|
omlish/dataclasses/impl/main.py
CHANGED
@@ -13,6 +13,7 @@ from .internals import FIELDS_ATTR
|
|
13
13
|
from .internals import PARAMS_ATTR
|
14
14
|
from .internals import Params
|
15
15
|
from .order import OrderProcessor
|
16
|
+
from .overrides import OverridesProcessor
|
16
17
|
from .params import ParamsExtras
|
17
18
|
from .processing import Processor
|
18
19
|
from .reflect import ClassInfo
|
@@ -21,7 +22,6 @@ from .repr import ReprProcessor
|
|
21
22
|
from .simple import DocProcessor
|
22
23
|
from .simple import EqProcessor
|
23
24
|
from .simple import MatchArgsProcessor
|
24
|
-
from .simple import OverridesProcessor
|
25
25
|
from .slots import add_slots
|
26
26
|
|
27
27
|
|
@@ -9,6 +9,7 @@ import dataclasses as dc
|
|
9
9
|
import typing as ta
|
10
10
|
|
11
11
|
from ... import lang
|
12
|
+
from .api import MISSING
|
12
13
|
from .api import dataclass
|
13
14
|
from .api import field # noqa
|
14
15
|
from .params import MetaclassParams
|
@@ -20,6 +21,28 @@ from .params import get_params_extras
|
|
20
21
|
T = ta.TypeVar('T')
|
21
22
|
|
22
23
|
|
24
|
+
##
|
25
|
+
|
26
|
+
|
27
|
+
_CONFER_PARAMS: tuple[str, ...] = (
|
28
|
+
'frozen',
|
29
|
+
'kw_only',
|
30
|
+
)
|
31
|
+
|
32
|
+
_CONFER_PARAMS_EXTRAS: tuple[str, ...] = (
|
33
|
+
'reorder',
|
34
|
+
'cache_hash',
|
35
|
+
'generic_init',
|
36
|
+
'override',
|
37
|
+
)
|
38
|
+
|
39
|
+
_CONFER_METACLASS_PARAMS: tuple[str, ...] = (
|
40
|
+
'confer',
|
41
|
+
'final_subclasses',
|
42
|
+
'abstract_immediate_subclasses',
|
43
|
+
)
|
44
|
+
|
45
|
+
|
23
46
|
def confer_kwarg(out: dict[str, ta.Any], k: str, v: ta.Any) -> None:
|
24
47
|
if k in out:
|
25
48
|
if out[k] != v:
|
@@ -44,22 +67,13 @@ def confer_kwargs(
|
|
44
67
|
if ck in kwargs:
|
45
68
|
continue
|
46
69
|
|
47
|
-
if ck in
|
48
|
-
'frozen',
|
49
|
-
'kw_only',
|
50
|
-
):
|
70
|
+
if ck in _CONFER_PARAMS:
|
51
71
|
confer_kwarg(out, ck, getattr(get_params(base), ck))
|
52
72
|
|
53
|
-
elif ck in
|
54
|
-
'cache_hash',
|
55
|
-
'generic_init',
|
56
|
-
'reorder',
|
57
|
-
):
|
73
|
+
elif ck in _CONFER_PARAMS_EXTRAS:
|
58
74
|
confer_kwarg(out, ck, getattr(get_params_extras(base), ck))
|
59
75
|
|
60
|
-
elif ck in
|
61
|
-
'confer',
|
62
|
-
):
|
76
|
+
elif ck in _CONFER_METACLASS_PARAMS:
|
63
77
|
confer_kwarg(out, ck, getattr(bmp, ck))
|
64
78
|
|
65
79
|
else:
|
@@ -68,6 +82,9 @@ def confer_kwargs(
|
|
68
82
|
return out
|
69
83
|
|
70
84
|
|
85
|
+
##
|
86
|
+
|
87
|
+
|
71
88
|
class DataMeta(abc.ABCMeta):
|
72
89
|
def __new__(
|
73
90
|
mcls,
|
@@ -76,25 +93,21 @@ class DataMeta(abc.ABCMeta):
|
|
76
93
|
namespace,
|
77
94
|
*,
|
78
95
|
|
79
|
-
|
96
|
+
abstract=False,
|
97
|
+
sealed=False,
|
98
|
+
final=False,
|
80
99
|
|
81
100
|
metadata=None,
|
82
101
|
**kwargs,
|
83
102
|
):
|
84
|
-
cls = lang.super_meta(
|
85
|
-
super(),
|
86
|
-
mcls,
|
87
|
-
name,
|
88
|
-
bases,
|
89
|
-
namespace,
|
90
|
-
)
|
91
|
-
|
92
103
|
ckw = confer_kwargs(bases, kwargs)
|
93
104
|
nkw = {**kwargs, **ckw}
|
94
105
|
|
95
|
-
mcp = MetaclassParams(
|
96
|
-
|
97
|
-
|
106
|
+
mcp = MetaclassParams(**{
|
107
|
+
mpa: nkw.pop(mpa)
|
108
|
+
for mpa in _CONFER_METACLASS_PARAMS
|
109
|
+
if mpa in nkw
|
110
|
+
})
|
98
111
|
|
99
112
|
mmd = {
|
100
113
|
MetaclassParams: mcp,
|
@@ -104,13 +117,74 @@ class DataMeta(abc.ABCMeta):
|
|
104
117
|
else:
|
105
118
|
metadata = mmd
|
106
119
|
|
120
|
+
#
|
121
|
+
|
122
|
+
xbs: list[type] = []
|
123
|
+
|
124
|
+
if any(get_metaclass_params(b).abstract_immediate_subclasses for b in bases if dc.is_dataclass(b)):
|
125
|
+
abstract = True
|
126
|
+
|
127
|
+
final |= (mcp.final_subclasses and not abstract)
|
128
|
+
|
129
|
+
if final and abstract:
|
130
|
+
raise TypeError(f'Class cannot be abstract and final: {name!r}')
|
131
|
+
|
132
|
+
if abstract:
|
133
|
+
xbs.append(lang.Abstract)
|
134
|
+
if sealed:
|
135
|
+
xbs.append(lang.Sealed)
|
136
|
+
if final:
|
137
|
+
xbs.append(lang.Final)
|
138
|
+
|
139
|
+
if xbs:
|
140
|
+
if bases and bases[-1] is ta.Generic:
|
141
|
+
bases = (*bases[:-1], *xbs, bases[-1])
|
142
|
+
else:
|
143
|
+
bases = (*bases, *xbs)
|
144
|
+
if ob := namespace.get('__orig_bases__'):
|
145
|
+
if getattr(ob[-1], '__origin__', None) is ta.Generic:
|
146
|
+
namespace['__orig_bases__'] = (*ob[:-1], *xbs, ob[-1])
|
147
|
+
else:
|
148
|
+
namespace['__orig_bases__'] = (*ob, *xbs)
|
149
|
+
|
150
|
+
#
|
151
|
+
|
152
|
+
ofs: set[str] = set()
|
153
|
+
if any(issubclass(b, lang.Abstract) for b in bases) and nkw.get('override'):
|
154
|
+
ofs.update(a for a in namespace.get('__annotations__', []) if a not in namespace)
|
155
|
+
namespace.update((a, MISSING) for a in ofs)
|
156
|
+
|
157
|
+
#
|
158
|
+
|
159
|
+
cls = lang.super_meta(
|
160
|
+
super(),
|
161
|
+
mcls,
|
162
|
+
name,
|
163
|
+
bases,
|
164
|
+
namespace,
|
165
|
+
)
|
166
|
+
|
167
|
+
#
|
168
|
+
|
169
|
+
for a in ofs:
|
170
|
+
delattr(cls, a)
|
171
|
+
|
172
|
+
#
|
173
|
+
|
107
174
|
return dataclass(cls, metadata=metadata, **nkw)
|
108
175
|
|
109
176
|
|
177
|
+
##
|
178
|
+
|
179
|
+
|
110
180
|
# @ta.dataclass_transform(field_specifiers=(field,)) # FIXME: ctor
|
111
181
|
class Data(
|
112
182
|
eq=False,
|
113
183
|
order=False,
|
184
|
+
confer=frozenset([
|
185
|
+
'confer',
|
186
|
+
'final_subclasses',
|
187
|
+
]),
|
114
188
|
metaclass=DataMeta,
|
115
189
|
):
|
116
190
|
def __init__(self, *args, **kwargs):
|
@@ -132,24 +206,33 @@ class Frozen(
|
|
132
206
|
eq=False,
|
133
207
|
order=False,
|
134
208
|
confer=frozenset([
|
209
|
+
*get_metaclass_params(Data).confer,
|
135
210
|
'frozen',
|
136
|
-
'cache_hash',
|
137
|
-
'confer',
|
138
211
|
'reorder',
|
212
|
+
'cache_hash',
|
213
|
+
'override',
|
139
214
|
]),
|
140
215
|
):
|
141
216
|
pass
|
142
217
|
|
143
218
|
|
219
|
+
class Case(
|
220
|
+
Frozen,
|
221
|
+
abstract=True,
|
222
|
+
override=True,
|
223
|
+
final_subclasses=True,
|
224
|
+
abstract_immediate_subclasses=True,
|
225
|
+
):
|
226
|
+
pass
|
227
|
+
|
228
|
+
|
144
229
|
class Box(
|
145
230
|
Frozen,
|
146
231
|
ta.Generic[T],
|
147
232
|
generic_init=True,
|
148
233
|
confer=frozenset([
|
149
|
-
|
150
|
-
'cache_hash',
|
234
|
+
*get_metaclass_params(Frozen).confer,
|
151
235
|
'generic_init',
|
152
|
-
'confer',
|
153
236
|
]),
|
154
237
|
):
|
155
238
|
v: T
|
@@ -0,0 +1,53 @@
|
|
1
|
+
from ... import lang
|
2
|
+
from .fields import field_assign
|
3
|
+
from .params import get_field_extras
|
4
|
+
from .processing import Processor
|
5
|
+
from .utils import create_fn
|
6
|
+
from .utils import set_new_attribute
|
7
|
+
|
8
|
+
|
9
|
+
class OverridesProcessor(Processor):
|
10
|
+
def _process(self) -> None:
|
11
|
+
for f in self._info.instance_fields:
|
12
|
+
fx = get_field_extras(f)
|
13
|
+
if not (fx.override or self._info.params_extras.override):
|
14
|
+
continue
|
15
|
+
|
16
|
+
if self._info.params.slots:
|
17
|
+
raise TypeError
|
18
|
+
|
19
|
+
self_name = '__dataclass_self__' if 'self' in self._info.fields else 'self'
|
20
|
+
|
21
|
+
getter = create_fn(
|
22
|
+
f.name,
|
23
|
+
(self_name,),
|
24
|
+
[f'return {self_name}.__dict__[{f.name!r}]'],
|
25
|
+
globals=self._info.globals,
|
26
|
+
return_type=lang.just(f.type),
|
27
|
+
)
|
28
|
+
prop = property(getter)
|
29
|
+
|
30
|
+
if not self._info.params.frozen:
|
31
|
+
setter = create_fn(
|
32
|
+
f.name,
|
33
|
+
(self_name, f'{f.name}: __dataclass_type_{f.name}__'),
|
34
|
+
[
|
35
|
+
field_assign(
|
36
|
+
self._info.params.frozen,
|
37
|
+
f.name,
|
38
|
+
f.name,
|
39
|
+
self_name,
|
40
|
+
True,
|
41
|
+
),
|
42
|
+
],
|
43
|
+
globals=self._info.globals,
|
44
|
+
locals={f'__dataclass_type_{f.name}__': f.type},
|
45
|
+
return_type=lang.just(None),
|
46
|
+
)
|
47
|
+
prop = prop.setter(setter)
|
48
|
+
|
49
|
+
set_new_attribute(
|
50
|
+
self._cls,
|
51
|
+
f.name,
|
52
|
+
prop,
|
53
|
+
)
|
@@ -91,6 +91,7 @@ class ParamsExtras(lang.Final):
|
|
91
91
|
reorder: bool = False
|
92
92
|
cache_hash: bool = False
|
93
93
|
generic_init: bool = False
|
94
|
+
override: bool = False
|
94
95
|
|
95
96
|
|
96
97
|
DEFAULT_PARAMS_EXTRAS = ParamsExtras()
|
@@ -110,6 +111,8 @@ def get_params_extras(obj: ta.Any) -> ParamsExtras:
|
|
110
111
|
@dc.dataclass(frozen=True)
|
111
112
|
class MetaclassParams:
|
112
113
|
confer: frozenset[str] = frozenset()
|
114
|
+
final_subclasses: bool = False
|
115
|
+
abstract_immediate_subclasses: bool = False
|
113
116
|
|
114
117
|
|
115
118
|
DEFAULT_METACLASS_PARAMS = MetaclassParams()
|
@@ -30,8 +30,20 @@ from .utils import Namespace
|
|
30
30
|
MISSING = dc.MISSING
|
31
31
|
|
32
32
|
|
33
|
-
|
33
|
+
##
|
34
|
+
|
35
|
+
|
36
|
+
def get_cls_annotations(cls: type) -> ta.Mapping[str, ta.Any]:
|
37
|
+
# Does not use ta.get_type_hints because that's what std dataclasses do [1]. Might be worth revisiting? A part
|
38
|
+
# of why they don't is to not import typing for efficiency but we don't care about that degree of startup speed.
|
39
|
+
# [1]: https://github.com/python/cpython/blob/54c63a32d06cb5f07a66245c375eac7d7efb964a/Lib/dataclasses.py#L985-L986 # noqa
|
40
|
+
return rfl.get_annotations(cls)
|
41
|
+
|
42
|
+
|
43
|
+
##
|
34
44
|
|
45
|
+
|
46
|
+
class ClassInfo:
|
35
47
|
def __init__(self, cls: type, *, _constructing: bool = False) -> None:
|
36
48
|
check.isinstance(cls, type)
|
37
49
|
self._constructing = _constructing
|
@@ -53,10 +65,7 @@ class ClassInfo:
|
|
53
65
|
|
54
66
|
@cached.property
|
55
67
|
def cls_annotations(self) -> ta.Mapping[str, ta.Any]:
|
56
|
-
|
57
|
-
# of why they don't is to not import typing for efficiency but we don't care about that degree of startup speed.
|
58
|
-
# [1]: https://github.com/python/cpython/blob/54c63a32d06cb5f07a66245c375eac7d7efb964a/Lib/dataclasses.py#L985-L986 # noqa
|
59
|
-
return rfl.get_annotations(self._cls)
|
68
|
+
return get_cls_annotations(self._cls)
|
60
69
|
|
61
70
|
##
|
62
71
|
|
@@ -157,6 +166,9 @@ class ClassInfo:
|
|
157
166
|
return {k: rfl.to_annotation(v) for k, v in self.generic_replaced_field_types.items()}
|
158
167
|
|
159
168
|
|
169
|
+
##
|
170
|
+
|
171
|
+
|
160
172
|
_CLASS_INFO_CACHE: ta.MutableMapping[type, ClassInfo] = weakref.WeakKeyDictionary()
|
161
173
|
|
162
174
|
|
@@ -1,53 +1,11 @@
|
|
1
1
|
import inspect
|
2
2
|
|
3
|
-
from ... import lang
|
4
|
-
from .fields import field_assign
|
5
3
|
from .init import get_init_fields
|
6
|
-
from .params import get_field_extras
|
7
4
|
from .processing import Processor
|
8
5
|
from .utils import create_fn
|
9
6
|
from .utils import set_new_attribute
|
10
7
|
|
11
8
|
|
12
|
-
class OverridesProcessor(Processor):
|
13
|
-
def _process(self) -> None:
|
14
|
-
for f in self._info.instance_fields:
|
15
|
-
fx = get_field_extras(f)
|
16
|
-
if not fx.override:
|
17
|
-
continue
|
18
|
-
|
19
|
-
if self._info.params.slots:
|
20
|
-
raise TypeError
|
21
|
-
|
22
|
-
self_name = '__dataclass_self__' if 'self' in self._info.fields else 'self'
|
23
|
-
|
24
|
-
getter = create_fn(
|
25
|
-
f.name,
|
26
|
-
(self_name,),
|
27
|
-
[f'return {self_name}.__dict__[{f.name!r}]'],
|
28
|
-
globals=self._info.globals,
|
29
|
-
return_type=lang.just(f.type),
|
30
|
-
)
|
31
|
-
prop = property(getter)
|
32
|
-
|
33
|
-
if not self._info.params.frozen:
|
34
|
-
setter = create_fn(
|
35
|
-
f.name,
|
36
|
-
(self_name, f'{f.name}: __dataclass_type_{f.name}__'),
|
37
|
-
[field_assign(self._info.params.frozen, f.name, f.name, self_name, fx.override)],
|
38
|
-
globals=self._info.globals,
|
39
|
-
locals={f'__dataclass_type_{f.name}__': f.type},
|
40
|
-
return_type=lang.just(None),
|
41
|
-
)
|
42
|
-
prop = prop.setter(setter)
|
43
|
-
|
44
|
-
set_new_attribute(
|
45
|
-
self._cls,
|
46
|
-
f.name,
|
47
|
-
prop,
|
48
|
-
)
|
49
|
-
|
50
|
-
|
51
9
|
class EqProcessor(Processor):
|
52
10
|
def _process(self) -> None:
|
53
11
|
if not self._info.params.eq:
|
omlish/http/coro/server.py
CHANGED
@@ -205,6 +205,10 @@ class CoroHttpServer:
|
|
205
205
|
return h
|
206
206
|
return None
|
207
207
|
|
208
|
+
def close(self) -> None:
|
209
|
+
if isinstance(d := self.data, HttpHandlerResponseStreamedData):
|
210
|
+
d.close()
|
211
|
+
|
208
212
|
#
|
209
213
|
|
210
214
|
def _build_response_head_bytes(self, a: _Response) -> bytes:
|
@@ -420,35 +424,45 @@ class CoroHttpServer:
|
|
420
424
|
while True:
|
421
425
|
gen = self.coro_handle_one()
|
422
426
|
|
423
|
-
o = next(gen)
|
424
427
|
i: ta.Optional[bytes]
|
428
|
+
o: ta.Any = next(gen)
|
425
429
|
while True:
|
426
|
-
|
427
|
-
|
428
|
-
|
430
|
+
try:
|
431
|
+
if isinstance(o, self.AnyLogIo):
|
432
|
+
i = None
|
433
|
+
yield o
|
429
434
|
|
430
|
-
|
431
|
-
|
435
|
+
elif isinstance(o, self.AnyReadIo):
|
436
|
+
i = check.isinstance((yield o), bytes)
|
432
437
|
|
433
|
-
|
434
|
-
|
438
|
+
elif isinstance(o, self._Response):
|
439
|
+
i = None
|
435
440
|
|
436
|
-
|
437
|
-
|
438
|
-
|
441
|
+
r = self._preprocess_response(o)
|
442
|
+
hb = self._build_response_head_bytes(r)
|
443
|
+
check.none((yield self.WriteIo(hb)))
|
439
444
|
|
440
|
-
|
441
|
-
|
445
|
+
for b in self._yield_response_data(r):
|
446
|
+
yield self.WriteIo(b)
|
442
447
|
|
443
|
-
|
444
|
-
|
448
|
+
o.close()
|
449
|
+
o = None
|
445
450
|
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
451
|
+
else:
|
452
|
+
raise TypeError(o) # noqa
|
453
|
+
|
454
|
+
try:
|
455
|
+
o = gen.send(i)
|
456
|
+
except EOFError:
|
457
|
+
return
|
458
|
+
except StopIteration:
|
459
|
+
break
|
460
|
+
|
461
|
+
except Exception: # noqa
|
462
|
+
if hasattr(o, 'close'):
|
463
|
+
o.close()
|
464
|
+
|
465
|
+
raise
|
452
466
|
|
453
467
|
def coro_handle_one(self) -> ta.Generator[
|
454
468
|
ta.Union[AnyLogIo, AnyReadIo, _Response],
|
@@ -530,28 +544,34 @@ class CoroHttpServer:
|
|
530
544
|
yield self._build_error_response(err)
|
531
545
|
return
|
532
546
|
|
533
|
-
|
547
|
+
try:
|
548
|
+
# Build internal response
|
534
549
|
|
535
|
-
|
536
|
-
|
550
|
+
response_headers = handler_response.headers or {}
|
551
|
+
response_data = handler_response.data
|
537
552
|
|
538
|
-
|
539
|
-
|
540
|
-
|
553
|
+
headers: ta.List[CoroHttpServer._Header] = [
|
554
|
+
*self._make_default_headers(),
|
555
|
+
]
|
541
556
|
|
542
|
-
|
543
|
-
|
557
|
+
for k, v in response_headers.items():
|
558
|
+
headers.append(self._Header(k, v))
|
544
559
|
|
545
|
-
|
546
|
-
|
560
|
+
if handler_response.close_connection and 'Connection' not in headers:
|
561
|
+
headers.append(self._Header('Connection', 'close'))
|
547
562
|
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
563
|
+
yield self._Response(
|
564
|
+
version=parsed.version,
|
565
|
+
code=http.HTTPStatus(handler_response.status),
|
566
|
+
headers=headers,
|
567
|
+
data=response_data,
|
568
|
+
close_connection=handler_response.close_connection,
|
569
|
+
)
|
570
|
+
|
571
|
+
except Exception: # noqa
|
572
|
+
handler_response.close()
|
573
|
+
|
574
|
+
raise
|
555
575
|
|
556
576
|
|
557
577
|
##
|