fastapi-extra 0.2.0__cp312-cp312-win_amd64.whl → 0.2.2__cp312-cp312-win_amd64.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.
- fastapi_extra/__init__.py +1 -1
- fastapi_extra/cursor.cp312-win_amd64.pyd +0 -0
- fastapi_extra/cursor.pyi +8 -0
- fastapi_extra/database/service.py +2 -2
- fastapi_extra/native/cursor.pyx +2 -2
- fastapi_extra/native/routing.pyx +134 -78
- fastapi_extra/routing.cp312-win_amd64.pyd +0 -0
- fastapi_extra/routing.pyi +16 -0
- {fastapi_extra-0.2.0.dist-info → fastapi_extra-0.2.2.dist-info}/METADATA +1 -1
- {fastapi_extra-0.2.0.dist-info → fastapi_extra-0.2.2.dist-info}/RECORD +13 -11
- {fastapi_extra-0.2.0.dist-info → fastapi_extra-0.2.2.dist-info}/WHEEL +1 -1
- {fastapi_extra-0.2.0.dist-info → fastapi_extra-0.2.2.dist-info}/licenses/LICENSE +0 -0
- {fastapi_extra-0.2.0.dist-info → fastapi_extra-0.2.2.dist-info}/top_level.txt +0 -0
fastapi_extra/__init__.py
CHANGED
|
Binary file
|
fastapi_extra/cursor.pyi
ADDED
|
@@ -5,7 +5,7 @@ from contextvars import ContextVar
|
|
|
5
5
|
from typing import Any, Generic, Self, TypeVar
|
|
6
6
|
|
|
7
7
|
from fastapi_extra.database.model import SQLModel
|
|
8
|
-
from fastapi_extra.database.session import DefaultSession
|
|
8
|
+
from fastapi_extra.database.session import AsyncSession, DefaultSession
|
|
9
9
|
from fastapi_extra.dependency import AbstractService
|
|
10
10
|
|
|
11
11
|
Model = TypeVar("Model", bound=SQLModel)
|
|
@@ -32,7 +32,7 @@ class ModelService(AbstractService, Generic[Model], abstract=True):
|
|
|
32
32
|
self.__session_container__.set(session)
|
|
33
33
|
|
|
34
34
|
@property
|
|
35
|
-
def session(self):
|
|
35
|
+
def session(self) -> AsyncSession:
|
|
36
36
|
_session = self.__session_container__.get()
|
|
37
37
|
assert _session is not None, "Session is not initialized"
|
|
38
38
|
return _session
|
fastapi_extra/native/cursor.pyx
CHANGED
|
@@ -37,8 +37,8 @@ cdef class Cursor:
|
|
|
37
37
|
self.cursor = count
|
|
38
38
|
return (point << (_sequence_length + 4)) + (self.seed << _sequence_length) + count
|
|
39
39
|
|
|
40
|
-
def next_val(self) ->
|
|
40
|
+
def next_val(self) -> int:
|
|
41
41
|
index = self.fetch()
|
|
42
42
|
while index == 0:
|
|
43
43
|
index = self.fetch()
|
|
44
|
-
return
|
|
44
|
+
return index
|
fastapi_extra/native/routing.pyx
CHANGED
|
@@ -3,80 +3,113 @@ __describe__ = ""
|
|
|
3
3
|
|
|
4
4
|
cimport cython
|
|
5
5
|
|
|
6
|
-
from typing import MutableMapping
|
|
7
|
-
|
|
8
6
|
from starlette import _utils as starlette_utils
|
|
9
7
|
from starlette.datastructures import URL
|
|
10
8
|
from starlette.responses import RedirectResponse
|
|
11
9
|
|
|
12
10
|
|
|
11
|
+
cdef int find_params(unicode path):
|
|
12
|
+
for i, ch in enumerate(path):
|
|
13
|
+
if ch == "{":
|
|
14
|
+
return i
|
|
15
|
+
return -1
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
cdef int get_longest_common_prefix(unicode path, unicode node_path):
|
|
19
|
+
cdef int i
|
|
20
|
+
cdef int max_len = min(len(path), len(node_path))
|
|
21
|
+
for i in range(max_len):
|
|
22
|
+
if path[i] != node_path[i]:
|
|
23
|
+
return i
|
|
24
|
+
return max_len
|
|
25
|
+
|
|
26
|
+
|
|
13
27
|
@cython.no_gc
|
|
14
28
|
cdef class RouteNode:
|
|
29
|
+
|
|
15
30
|
cdef readonly:
|
|
16
|
-
list routes
|
|
17
|
-
dict leaves
|
|
18
31
|
unicode prefix
|
|
32
|
+
list params_routes
|
|
33
|
+
list static_routes
|
|
34
|
+
dict children
|
|
35
|
+
|
|
36
|
+
cdef public object parent
|
|
19
37
|
|
|
20
|
-
def __cinit__(self, prefix):
|
|
38
|
+
def __cinit__(self, prefix: str):
|
|
21
39
|
self.prefix = prefix
|
|
22
|
-
self.
|
|
23
|
-
self.
|
|
40
|
+
self.params_routes = []
|
|
41
|
+
self.static_routes = []
|
|
42
|
+
self.children = {}
|
|
43
|
+
self.parent = None
|
|
44
|
+
|
|
45
|
+
def add_route(self, fullpath: str, handler: object):
|
|
46
|
+
wild_child = False
|
|
47
|
+
if (index := find_params(fullpath)) >= 0:
|
|
48
|
+
wild_child = True
|
|
49
|
+
path = fullpath[:index]
|
|
50
|
+
else:
|
|
51
|
+
path = fullpath
|
|
52
|
+
insert_route(self, path, wild_child, handler)
|
|
24
53
|
|
|
25
|
-
def add_route(self, route):
|
|
26
|
-
self.routes.append(route)
|
|
27
54
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
self.leaves[node.prefix] = node
|
|
55
|
+
cdef void insert_route(RouteNode node, unicode path, bint wild_child, object handler):
|
|
56
|
+
if node.prefix == path:
|
|
57
|
+
add_node(node, wild_child, handler)
|
|
58
|
+
return
|
|
33
59
|
|
|
60
|
+
cdef Py_UCS4 key = path.removeprefix(node.prefix)[0]
|
|
61
|
+
if key not in node.children:
|
|
62
|
+
add_child_node(node, key, path, wild_child, handler)
|
|
63
|
+
return
|
|
34
64
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
65
|
+
child_node = node.children[key]
|
|
66
|
+
i = get_longest_common_prefix(child_node.prefix, path)
|
|
67
|
+
longest_prefix = child_node.prefix[0: i]
|
|
68
|
+
if i == len(child_node.prefix):
|
|
69
|
+
insert_route(node.children[key], path, wild_child, handler)
|
|
70
|
+
return
|
|
71
|
+
next_node = RouteNode.__new__(RouteNode, longest_prefix)
|
|
72
|
+
next_node.parent = node
|
|
73
|
+
node.children[key] = next_node
|
|
74
|
+
next_node.children[child_node.prefix[i]] = child_node
|
|
75
|
+
child_node.parent = next_node
|
|
76
|
+
insert_route(next_node, path, wild_child, handler)
|
|
38
77
|
|
|
39
78
|
|
|
40
|
-
cdef void
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
current_node.add_leaf(next_node)
|
|
53
|
-
current_node = next_node
|
|
54
|
-
current_node.add_route(route)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
cdef list find_routes(unicode path, RouteNode root):
|
|
58
|
-
current_node = root
|
|
59
|
-
ranks = change_path_to_ranks(path)
|
|
60
|
-
|
|
61
|
-
routes = []
|
|
62
|
-
if current_node.routes:
|
|
63
|
-
routes += current_node.routes
|
|
64
|
-
for r in ranks:
|
|
65
|
-
if not r:
|
|
66
|
-
continue
|
|
67
|
-
if r in current_node.leaves:
|
|
68
|
-
current_node = current_node.leaves[r]
|
|
69
|
-
if current_node.routes:
|
|
70
|
-
routes += current_node.routes
|
|
71
|
-
continue
|
|
72
|
-
break
|
|
73
|
-
return routes
|
|
79
|
+
cdef inline void add_child_node(RouteNode node, Py_UCS4 key, unicode path, bint wild_child, object handler):
|
|
80
|
+
child = RouteNode.__new__(RouteNode, path)
|
|
81
|
+
child.parent = node
|
|
82
|
+
add_node(child, wild_child, handler)
|
|
83
|
+
node.children[key] = child
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
cdef inline void add_node(RouteNode node, bint wild_child, object handler):
|
|
87
|
+
if wild_child:
|
|
88
|
+
node.params_routes.append(handler)
|
|
89
|
+
else:
|
|
90
|
+
node.static_routes.append(handler)
|
|
74
91
|
|
|
75
92
|
|
|
76
93
|
root_node = RouteNode.__new__(RouteNode, "")
|
|
77
94
|
|
|
78
95
|
|
|
79
|
-
|
|
96
|
+
cdef RouteNode search_node(unicode url):
|
|
97
|
+
cdef RouteNode current_node = root_node
|
|
98
|
+
cdef int n = len(url)
|
|
99
|
+
cdef int i = get_longest_common_prefix(url, current_node.prefix)
|
|
100
|
+
|
|
101
|
+
while i < n:
|
|
102
|
+
key = url[i]
|
|
103
|
+
if key not in current_node.children:
|
|
104
|
+
break
|
|
105
|
+
current_node = current_node.children[key]
|
|
106
|
+
i = get_longest_common_prefix(url, current_node.prefix)
|
|
107
|
+
|
|
108
|
+
return current_node
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
async def handle(scope, receive, send):
|
|
112
|
+
router = scope["app"].router
|
|
80
113
|
assert scope["type"] in ("http", "websocket", "lifespan")
|
|
81
114
|
|
|
82
115
|
if "router" not in scope:
|
|
@@ -89,47 +122,70 @@ async def handle(router, scope, receive, send):
|
|
|
89
122
|
partial = None
|
|
90
123
|
|
|
91
124
|
scope["path"] = route_path = starlette_utils.get_route_path(scope)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
125
|
+
leaf_node = search_node(route_path)
|
|
126
|
+
|
|
127
|
+
if leaf_node.prefix == route_path:
|
|
128
|
+
for route in leaf_node.static_routes:
|
|
129
|
+
match, child_scope = route.matches(scope)
|
|
130
|
+
if match.value == 2:
|
|
131
|
+
scope.update(child_scope)
|
|
132
|
+
await route.handle(scope, receive, send)
|
|
133
|
+
return
|
|
134
|
+
elif match.value == 1 and partial is None:
|
|
135
|
+
partial = route
|
|
136
|
+
partial_scope = child_scope
|
|
137
|
+
else:
|
|
138
|
+
current_node = leaf_node
|
|
139
|
+
routes = current_node.params_routes
|
|
140
|
+
while current_node.parent:
|
|
141
|
+
for route in routes:
|
|
142
|
+
match, child_scope = route.matches(scope)
|
|
143
|
+
if match.value == 2:
|
|
144
|
+
scope.update(child_scope)
|
|
145
|
+
await route.handle(scope, receive, send)
|
|
146
|
+
return
|
|
147
|
+
elif match.value == 1 and partial is None:
|
|
148
|
+
partial = route
|
|
149
|
+
partial_scope = child_scope
|
|
150
|
+
current_node = current_node.parent
|
|
106
151
|
|
|
107
152
|
if partial is not None:
|
|
108
153
|
scope.update(partial_scope)
|
|
109
154
|
await partial.handle(scope, receive, send)
|
|
110
155
|
return
|
|
111
156
|
|
|
112
|
-
|
|
113
157
|
if scope["type"] == "http" and router.redirect_slashes and route_path != "/":
|
|
114
158
|
redirect_scope = dict(scope)
|
|
115
159
|
if route_path.endswith("/"):
|
|
116
160
|
redirect_scope["path"] = redirect_scope["path"].rstrip("/")
|
|
117
161
|
else:
|
|
118
162
|
redirect_scope["path"] = redirect_scope["path"] + "/"
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
route
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
163
|
+
|
|
164
|
+
if leaf_node.prefix == redirect_scope["path"]:
|
|
165
|
+
for route in leaf_node.static_routes:
|
|
166
|
+
match, child_scope = route.matches(redirect_scope)
|
|
167
|
+
if match.value != 0:
|
|
168
|
+
redirect_url = URL(scope=redirect_scope)
|
|
169
|
+
response = RedirectResponse(url=str(redirect_url))
|
|
170
|
+
await response(scope, receive, send)
|
|
171
|
+
return
|
|
172
|
+
else:
|
|
173
|
+
current_node = leaf_node
|
|
174
|
+
routes = current_node.params_routes
|
|
175
|
+
while current_node.parent:
|
|
176
|
+
for route in routes:
|
|
177
|
+
if match.value != 0:
|
|
178
|
+
redirect_url = URL(scope=redirect_scope)
|
|
179
|
+
response = RedirectResponse(url=str(redirect_url))
|
|
180
|
+
await response(scope, receive, send)
|
|
181
|
+
return
|
|
182
|
+
current_node = current_node.parent
|
|
128
183
|
|
|
129
184
|
await router.default(scope, receive, send)
|
|
130
185
|
|
|
131
186
|
|
|
132
187
|
def install(app):
|
|
133
188
|
for route in app.routes:
|
|
134
|
-
add_route(route.path,
|
|
135
|
-
|
|
189
|
+
root_node.add_route(route.path, route)
|
|
190
|
+
|
|
191
|
+
app.router.middleware_stack = handle
|
|
Binary file
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
fastapi_extra/__init__.py,sha256=
|
|
2
|
-
fastapi_extra/cursor.cp312-win_amd64.pyd,sha256=
|
|
1
|
+
fastapi_extra/__init__.py,sha256=15p7teY89i6qSlOfYqQjU6a7fRvBPC-tPXGQU6Oo0O8,286
|
|
2
|
+
fastapi_extra/cursor.cp312-win_amd64.pyd,sha256=_Lkcm1Mi2PRMXa4M4QO5ydq-5N8Pk0pAjb8hiDLp13A,53760
|
|
3
|
+
fastapi_extra/cursor.pyi,sha256=t1_ub-dRhu3OcXB_dIw5MdBG9r1n7853Vtgzc6bk6dw,115
|
|
3
4
|
fastapi_extra/dependency.py,sha256=LtYnOTMyhOQUFSbNEViw7lxJvAFpPWbyuY4e2goSG-8,2130
|
|
4
5
|
fastapi_extra/form.py,sha256=Fs9uEDOQThjFroDVTrjWnIGJ107BgXCppIVTymwQLzg,1247
|
|
5
6
|
fastapi_extra/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
7
|
fastapi_extra/response.py,sha256=DHvhOSgwot5eBNKuI_jPYxZ5rshZ55Xkg-FNBJlHD1E,9609
|
|
7
|
-
fastapi_extra/routing.cp312-win_amd64.pyd,sha256=
|
|
8
|
+
fastapi_extra/routing.cp312-win_amd64.pyd,sha256=e_t1yZsSSJm-z1ppnXVOch9TGQF2q9ipphYNsY_9Otk,91136
|
|
9
|
+
fastapi_extra/routing.pyi,sha256=QslcOUnVJqFCqt14VJQwjUYQ7Qd3bQBTo34Yx1xS7TA,243
|
|
8
10
|
fastapi_extra/settings.py,sha256=cCcwaper5GiNNoT4gNKqf-iloSOTNnMsiUR0knJx4Mw,1461
|
|
9
11
|
fastapi_extra/types.py,sha256=3z6gUnao6WZL76asZYmex20xfY9mvYA-RbnsxUcui30,819
|
|
10
12
|
fastapi_extra/utils.py,sha256=tsPX3kpF_P5D9Bd3gnlG6rkVsLkv5gbxjml-s6ZL_6I,346
|
|
@@ -12,12 +14,12 @@ fastapi_extra/cache/__init__.py,sha256=kq4b_AYKCSJ0fEp4rqpeaoNJilko4XbtfC81xzUaY
|
|
|
12
14
|
fastapi_extra/cache/redis.py,sha256=-hr2DRkmruzH4cIArdjsytqRiiWWtDJt9GIDy38wmtQ,1600
|
|
13
15
|
fastapi_extra/database/__init__.py,sha256=pCYUoEylTponWqpR0AXJHcRo_cs4fnEXVVV9B5J9rt0,384
|
|
14
16
|
fastapi_extra/database/model.py,sha256=2lDi9PQ5F0PSM7BGZozZf1wSefpXnTWqAVzEyGPaXRI,2453
|
|
15
|
-
fastapi_extra/database/service.py,sha256
|
|
17
|
+
fastapi_extra/database/service.py,sha256=V5ojRpiWs9_B3XVQz-PtyvBePfmByTn8WG2gXwuhpO0,1828
|
|
16
18
|
fastapi_extra/database/session.py,sha256=PALArHhXNS2gCgeMkiKjyatvINV_VW1LjgEIwXDKyfQ,1903
|
|
17
|
-
fastapi_extra/native/cursor.pyx,sha256=
|
|
18
|
-
fastapi_extra/native/routing.pyx,sha256=
|
|
19
|
-
fastapi_extra-0.2.
|
|
20
|
-
fastapi_extra-0.2.
|
|
21
|
-
fastapi_extra-0.2.
|
|
22
|
-
fastapi_extra-0.2.
|
|
23
|
-
fastapi_extra-0.2.
|
|
19
|
+
fastapi_extra/native/cursor.pyx,sha256=GchJIPY6e5scuyl1BbA-Et0CdRcHOI3xgsTvDem0B70,1141
|
|
20
|
+
fastapi_extra/native/routing.pyx,sha256=NisJ9YaxzceDVWJnF3EeVXWT8rv_6WRDuIfLEK0eWbc,6233
|
|
21
|
+
fastapi_extra-0.2.2.dist-info/licenses/LICENSE,sha256=0vTjHDa3VDsxTT-R-sH6SpYcA2F1hKtbX9ZFZQm-EcU,1516
|
|
22
|
+
fastapi_extra-0.2.2.dist-info/METADATA,sha256=buJJyc4jA2ve_5jdhJ0Gm6HXiazZC2rwJm6oGEktH3A,1371
|
|
23
|
+
fastapi_extra-0.2.2.dist-info/WHEEL,sha256=8UP9x9puWI0P1V_d7K2oMTBqfeLNm21CTzZ_Ptr0NXU,101
|
|
24
|
+
fastapi_extra-0.2.2.dist-info/top_level.txt,sha256=B7D80bEftE2E-eSd1be2r9BWkLLMZN21dRTWpb4y4Ig,14
|
|
25
|
+
fastapi_extra-0.2.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|