omserv 0.0.0.dev281__tar.gz → 0.0.0.dev283__tar.gz
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.
- {omserv-0.0.0.dev281/omserv.egg-info → omserv-0.0.0.dev283}/PKG-INFO +2 -2
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/apps/base.py +2 -2
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/apps/inject.py +18 -7
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/apps/markers.py +3 -3
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/apps/routes.py +56 -28
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/apps/sessions.py +3 -6
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283/omserv.egg-info}/PKG-INFO +2 -2
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv.egg-info/requires.txt +1 -1
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/pyproject.toml +2 -2
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/LICENSE +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/MANIFEST.in +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/README.rst +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/.manifests.json +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/__about__.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/__init__.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/apps/__init__.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/apps/templates.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/nginx/__init__.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/nginx/build.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/nginx/logs.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/nginx/patches/__init__.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/nginx/patches/nginx-1.27.4_http_status.patch +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/nginx/stubstatus.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/nodes/__init__.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/nodes/models.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/nodes/registry.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/nodes/sql.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/LICENSE +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/__init__.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/config.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/debug.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/default.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/events.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/headers.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/inject.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/lifespans.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/listener.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/multiprocess.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/protocols/__init__.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/protocols/h11.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/protocols/h2.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/protocols/protocols.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/protocols/types.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/resources/__init__.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/resources/favicon.ico +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/server.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/sockets.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/ssl.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/streams/__init__.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/streams/httpstream.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/streams/utils.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/streams/wsstream.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/taskspawner.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/types.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/server/workercontext.py +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv.egg-info/SOURCES.txt +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv.egg-info/dependency_links.txt +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv.egg-info/entry_points.txt +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv.egg-info/top_level.txt +0 -0
- {omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: omserv
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev283
|
4
4
|
Summary: omserv
|
5
5
|
Author: wrmsr
|
6
6
|
License: BSD-3-Clause
|
@@ -12,7 +12,7 @@ Classifier: Operating System :: OS Independent
|
|
12
12
|
Classifier: Operating System :: POSIX
|
13
13
|
Requires-Python: >=3.12
|
14
14
|
License-File: LICENSE
|
15
|
-
Requires-Dist: omlish==0.0.0.
|
15
|
+
Requires-Dist: omlish==0.0.0.dev283
|
16
16
|
Provides-Extra: all
|
17
17
|
Requires-Dist: h11~=0.14; extra == "all"
|
18
18
|
Requires-Dist: h2~=4.2; extra == "all"
|
@@ -1,13 +1,13 @@
|
|
1
1
|
import contextvars
|
2
2
|
import typing as ta
|
3
3
|
|
4
|
-
from omlish.http
|
4
|
+
from omlish.http import asgi
|
5
5
|
|
6
6
|
|
7
7
|
##
|
8
8
|
|
9
9
|
|
10
|
-
SCOPE: contextvars.ContextVar[
|
10
|
+
SCOPE: contextvars.ContextVar[asgi.Scope] = contextvars.ContextVar('scope')
|
11
11
|
|
12
12
|
|
13
13
|
##
|
@@ -1,14 +1,15 @@
|
|
1
1
|
import typing as ta
|
2
2
|
|
3
3
|
from omlish import inject as inj
|
4
|
+
from omlish.http import asgi
|
4
5
|
from omlish.http import sessions
|
5
|
-
from omlish.http.asgi import AsgiScope
|
6
6
|
|
7
7
|
from .base import SCOPE
|
8
8
|
from .markers import AppMarker
|
9
9
|
from .markers import AppMarkerProcessor
|
10
10
|
from .markers import NopAppMarkerProcessor
|
11
|
-
from .routes import
|
11
|
+
from .routes import Route
|
12
|
+
from .routes import RouteHandlerHolder
|
12
13
|
from .routes import _HandlesAppMarker
|
13
14
|
from .routes import build_route_handler_map
|
14
15
|
from .sessions import SESSION
|
@@ -18,10 +19,10 @@ from .templates import JinjaNamespace
|
|
18
19
|
from .templates import JinjaTemplates
|
19
20
|
|
20
21
|
|
21
|
-
def
|
22
|
+
def bind_route_handler_class(hc: type[RouteHandlerHolder]) -> inj.Elemental:
|
22
23
|
return inj.as_elements(
|
23
24
|
inj.bind(hc, singleton=True),
|
24
|
-
inj.set_binder[
|
25
|
+
inj.set_binder[RouteHandlerHolder]().bind(hc),
|
25
26
|
)
|
26
27
|
|
27
28
|
|
@@ -32,16 +33,26 @@ def bind_app_marker_processor(mc: type[AppMarker], pc: type[AppMarkerProcessor])
|
|
32
33
|
)
|
33
34
|
|
34
35
|
|
36
|
+
def _build_route_handler_map(
|
37
|
+
handler_holders: ta.AbstractSet[RouteHandlerHolder],
|
38
|
+
processors: ta.Mapping[type[AppMarker], AppMarkerProcessor],
|
39
|
+
) -> ta.Mapping[Route, asgi.App]:
|
40
|
+
return build_route_handler_map(
|
41
|
+
handler_holders,
|
42
|
+
processors,
|
43
|
+
)
|
44
|
+
|
45
|
+
|
35
46
|
def bind_route_handler_map() -> inj.Elemental:
|
36
47
|
return inj.as_elements(
|
37
|
-
inj.bind(
|
48
|
+
inj.bind(_build_route_handler_map, singleton=True),
|
38
49
|
inj.map_binder[type[AppMarker], AppMarkerProcessor](),
|
39
50
|
)
|
40
51
|
|
41
52
|
|
42
53
|
def bind() -> inj.Elemental:
|
43
54
|
return inj.as_elements(
|
44
|
-
inj.bind(ta.Callable[[],
|
55
|
+
inj.bind(ta.Callable[[], asgi.Scope], to_const=SCOPE.get),
|
45
56
|
inj.bind(ta.Callable[[], sessions.Session], to_const=SESSION.get),
|
46
57
|
|
47
58
|
##
|
@@ -53,7 +64,7 @@ def bind() -> inj.Elemental:
|
|
53
64
|
|
54
65
|
##
|
55
66
|
|
56
|
-
inj.set_binder[
|
67
|
+
inj.set_binder[RouteHandlerHolder](),
|
57
68
|
)
|
58
69
|
|
59
70
|
|
@@ -2,7 +2,7 @@ import abc
|
|
2
2
|
import typing as ta
|
3
3
|
|
4
4
|
from omlish import lang
|
5
|
-
from omlish.http
|
5
|
+
from omlish.http import asgi
|
6
6
|
from omlish.metadata import ObjectMetadata
|
7
7
|
from omlish.metadata import append_object_metadata
|
8
8
|
from omlish.metadata import get_object_metadata
|
@@ -35,12 +35,12 @@ def get_app_markers(obj: ta.Any) -> ta.Sequence[AppMarker]:
|
|
35
35
|
|
36
36
|
class AppMarkerProcessor(lang.Abstract):
|
37
37
|
@abc.abstractmethod
|
38
|
-
def
|
38
|
+
def process_app(self, app: asgi.App) -> asgi.App:
|
39
39
|
raise NotImplementedError
|
40
40
|
|
41
41
|
|
42
42
|
class NopAppMarkerProcessor(AppMarkerProcessor, lang.Final):
|
43
|
-
def
|
43
|
+
def process_app(self, app: asgi.App) -> asgi.App:
|
44
44
|
return app
|
45
45
|
|
46
46
|
|
@@ -1,3 +1,8 @@
|
|
1
|
+
"""
|
2
|
+
TODO:
|
3
|
+
- include route in process_app?
|
4
|
+
- or, deduplicate handlers and only process apps once?
|
5
|
+
"""
|
1
6
|
import contextlib
|
2
7
|
import dataclasses as dc
|
3
8
|
import logging
|
@@ -5,13 +10,7 @@ import typing as ta
|
|
5
10
|
|
6
11
|
from omlish import check
|
7
12
|
from omlish import lang
|
8
|
-
from omlish.http
|
9
|
-
from omlish.http.asgi import AsgiApp_
|
10
|
-
from omlish.http.asgi import AsgiRecv
|
11
|
-
from omlish.http.asgi import AsgiScope
|
12
|
-
from omlish.http.asgi import AsgiSend
|
13
|
-
from omlish.http.asgi import send_response
|
14
|
-
from omlish.http.asgi import stub_lifespan
|
13
|
+
from omlish.http import asgi
|
15
14
|
|
16
15
|
from .base import BASE_SERVER_URL
|
17
16
|
from .base import SCOPE
|
@@ -53,7 +52,7 @@ class Route(ta.NamedTuple):
|
|
53
52
|
|
54
53
|
class RouteHandler(ta.NamedTuple):
|
55
54
|
route: Route
|
56
|
-
handler:
|
55
|
+
handler: asgi.App
|
57
56
|
|
58
57
|
|
59
58
|
@dc.dataclass(frozen=True)
|
@@ -78,12 +77,12 @@ HANDLES_APP_MARKER_PROCESSORS: AppMarkerProcessorMap = {
|
|
78
77
|
##
|
79
78
|
|
80
79
|
|
81
|
-
class
|
80
|
+
class RouteHandlerHolder(lang.Abstract): # noqa
|
82
81
|
def get_route_handlers(self) -> ta.Iterable[RouteHandler]:
|
83
82
|
return get_marked_route_handlers(self)
|
84
83
|
|
85
84
|
|
86
|
-
def get_marked_route_handlers(h:
|
85
|
+
def get_marked_route_handlers(h: RouteHandlerHolder) -> ta.Sequence[RouteHandler]:
|
87
86
|
ret: list[RouteHandler] = []
|
88
87
|
|
89
88
|
cdct: dict[str, ta.Any] = {}
|
@@ -104,38 +103,67 @@ def get_marked_route_handlers(h: RouteHandler_) -> ta.Sequence[RouteHandler]:
|
|
104
103
|
return ret
|
105
104
|
|
106
105
|
|
106
|
+
@dc.dataclass()
|
107
|
+
class DuplicateRouteError(Exception):
|
108
|
+
route_handlers: ta.Sequence[RouteHandler]
|
109
|
+
|
110
|
+
|
107
111
|
def build_route_handler_map(
|
108
|
-
handlers: ta.
|
112
|
+
handlers: ta.Iterable[RouteHandler | RouteHandlerHolder],
|
109
113
|
processors: ta.Mapping[type[AppMarker], AppMarkerProcessor],
|
110
|
-
) -> ta.Mapping[Route,
|
111
|
-
|
114
|
+
) -> ta.Mapping[Route, asgi.App]:
|
115
|
+
rh_by_r: dict[Route, RouteHandler] = {}
|
112
116
|
for h in handlers:
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
117
|
+
if isinstance(h, RouteHandlerHolder):
|
118
|
+
rhs = list(h.get_route_handlers())
|
119
|
+
else:
|
120
|
+
rhs = [h]
|
121
|
+
|
122
|
+
for rh in rhs:
|
123
|
+
try:
|
124
|
+
ex = rh_by_r[rh.route]
|
125
|
+
except KeyError:
|
126
|
+
pass
|
127
|
+
else:
|
128
|
+
raise DuplicateRouteError([rh, ex])
|
129
|
+
|
130
|
+
rh_by_r[rh.route] = rh
|
131
|
+
|
132
|
+
app_by_r: dict[Route, asgi.App] = {}
|
133
|
+
for r, rh in rh_by_r.items():
|
134
|
+
app = rh.handler
|
135
|
+
|
136
|
+
markers = get_app_markers(rh.handler)
|
137
|
+
for m in markers:
|
138
|
+
mp = processors[type(m)]
|
139
|
+
if mp is not None:
|
140
|
+
app = mp.process_app(app)
|
141
|
+
|
142
|
+
app_by_r[r] = app
|
143
|
+
|
144
|
+
return app_by_r
|
122
145
|
|
123
146
|
|
124
147
|
##
|
125
148
|
|
126
149
|
|
127
150
|
@dc.dataclass(frozen=True)
|
128
|
-
class RouteHandlerApp(
|
129
|
-
route_handlers: ta.Mapping[Route,
|
151
|
+
class RouteHandlerApp(asgi.App_):
|
152
|
+
route_handlers: ta.Mapping[Route, asgi.App]
|
130
153
|
base_server_url: BaseServerUrl | None = None
|
131
154
|
|
132
|
-
|
155
|
+
URL_SCHEME_PORT_PAIRS: ta.ClassVar[ta.Collection[tuple[str, int]]] = (
|
156
|
+
('http', 80),
|
157
|
+
('https', 443),
|
158
|
+
)
|
159
|
+
|
160
|
+
async def __call__(self, scope: asgi.Scope, recv: asgi.Recv, send: asgi.Send) -> None:
|
133
161
|
with contextlib.ExitStack() as es:
|
134
162
|
es.enter_context(lang.context_var_setting(SCOPE, scope)) # noqa
|
135
163
|
|
136
164
|
match scope_ty := scope['type']:
|
137
165
|
case 'lifespan':
|
138
|
-
await stub_lifespan(scope, recv, send)
|
166
|
+
await asgi.stub_lifespan(scope, recv, send)
|
139
167
|
return
|
140
168
|
|
141
169
|
case 'http':
|
@@ -144,7 +172,7 @@ class RouteHandlerApp(AsgiApp_):
|
|
144
172
|
else:
|
145
173
|
sch = scope['scheme']
|
146
174
|
h, p = scope['server']
|
147
|
-
if (sch, p) not in
|
175
|
+
if (sch, p) not in self.URL_SCHEME_PORT_PAIRS:
|
148
176
|
ps = f':{p}'
|
149
177
|
else:
|
150
178
|
ps = ''
|
@@ -158,7 +186,7 @@ class RouteHandlerApp(AsgiApp_):
|
|
158
186
|
await handler(scope, recv, send)
|
159
187
|
|
160
188
|
else:
|
161
|
-
await send_response(send, 404)
|
189
|
+
await asgi.send_response(send, 404)
|
162
190
|
|
163
191
|
case _:
|
164
192
|
raise ValueError(f'Unhandled scope type: {scope_ty!r}')
|
@@ -3,11 +3,8 @@ import dataclasses as dc
|
|
3
3
|
import logging
|
4
4
|
|
5
5
|
from omlish import lang
|
6
|
+
from omlish.http import asgi
|
6
7
|
from omlish.http import sessions
|
7
|
-
from omlish.http.asgi import AsgiApp
|
8
|
-
from omlish.http.asgi import AsgiRecv
|
9
|
-
from omlish.http.asgi import AsgiScope
|
10
|
-
from omlish.http.asgi import AsgiSend
|
11
8
|
|
12
9
|
from .markers import AppMarker
|
13
10
|
from .markers import AppMarkerProcessor
|
@@ -35,7 +32,7 @@ def with_session(fn):
|
|
35
32
|
class _WithSessionAppMarkerProcessor(AppMarkerProcessor):
|
36
33
|
_ss: sessions.CookieSessionStore
|
37
34
|
|
38
|
-
async def _wrap(self, fn:
|
35
|
+
async def _wrap(self, fn: asgi.App, scope: asgi.Scope, recv: asgi.Recv, send: asgi.Send) -> None:
|
39
36
|
async def _send(obj):
|
40
37
|
if obj['type'] == 'http.response.start':
|
41
38
|
out_session = SESSION.get()
|
@@ -53,5 +50,5 @@ class _WithSessionAppMarkerProcessor(AppMarkerProcessor):
|
|
53
50
|
with lang.context_var_setting(SESSION, in_session):
|
54
51
|
await fn(scope, recv, _send)
|
55
52
|
|
56
|
-
def
|
53
|
+
def process_app(self, app: asgi.App) -> asgi.App:
|
57
54
|
return lang.decorator(self._wrap)(app) # noqa
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: omserv
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev283
|
4
4
|
Summary: omserv
|
5
5
|
Author: wrmsr
|
6
6
|
License: BSD-3-Clause
|
@@ -12,7 +12,7 @@ Classifier: Operating System :: OS Independent
|
|
12
12
|
Classifier: Operating System :: POSIX
|
13
13
|
Requires-Python: >=3.12
|
14
14
|
License-File: LICENSE
|
15
|
-
Requires-Dist: omlish==0.0.0.
|
15
|
+
Requires-Dist: omlish==0.0.0.dev283
|
16
16
|
Provides-Extra: all
|
17
17
|
Requires-Dist: h11~=0.14; extra == "all"
|
18
18
|
Requires-Dist: h2~=4.2; extra == "all"
|
@@ -12,7 +12,7 @@ authors = [
|
|
12
12
|
urls = {source = 'https://github.com/wrmsr/omlish'}
|
13
13
|
license = {text = 'BSD-3-Clause'}
|
14
14
|
requires-python = '>=3.12'
|
15
|
-
version = '0.0.0.
|
15
|
+
version = '0.0.0.dev283'
|
16
16
|
classifiers = [
|
17
17
|
'License :: OSI Approved :: BSD License',
|
18
18
|
'Development Status :: 2 - Pre-Alpha',
|
@@ -22,7 +22,7 @@ classifiers = [
|
|
22
22
|
]
|
23
23
|
description = 'omserv'
|
24
24
|
dependencies = [
|
25
|
-
'omlish == 0.0.0.
|
25
|
+
'omlish == 0.0.0.dev283',
|
26
26
|
]
|
27
27
|
|
28
28
|
[project.optional-dependencies]
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{omserv-0.0.0.dev281 → omserv-0.0.0.dev283}/omserv/nginx/patches/nginx-1.27.4_http_status.patch
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|