fastapi-extra 0.2.0__cp312-cp312-win_amd64.whl → 0.2.1__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 CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "0.2.0"
1
+ __version__ = "0.2.1"
2
2
 
3
3
 
4
4
  from fastapi import FastAPI
Binary file
@@ -0,0 +1,8 @@
1
+ __author__ = "ziyan.yin"
2
+ __describe__ = ""
3
+
4
+
5
+ class Cursor:
6
+
7
+ def next_val(self) -> int:
8
+ ...
@@ -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) -> str:
40
+ def next_val(self) -> int:
41
41
  index = self.fetch()
42
42
  while index == 0:
43
43
  index = self.fetch()
44
- return str(index)
44
+ return index
@@ -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.routes = []
23
- self.leaves = {}
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
- def add_leaf(self, node):
29
- if node.prefix in self.leaves:
30
- raise KeyError(node.prefix)
31
- else:
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
- cdef list change_path_to_ranks(unicode path):
36
- ranks = path.lstrip('/').split('/')
37
- return ranks
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 add_route(unicode path, RouteNode root, object route):
41
- current_node = root
42
- ranks = change_path_to_ranks(path)
43
- for r in ranks:
44
- if r.find('{') >= 0 and r.find('}') > 0:
45
- break
46
- if not r:
47
- continue
48
- if r in current_node.leaves:
49
- current_node = current_node.leaves[r]
50
- else:
51
- next_node = RouteNode.__new__(RouteNode, r)
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
- async def handle(router, scope, receive, send):
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:
@@ -90,46 +123,70 @@ async def handle(router, scope, receive, send):
90
123
 
91
124
  scope["path"] = route_path = starlette_utils.get_route_path(scope)
92
125
  scope["root_path"] = ""
93
- matched_routes = find_routes(route_path, root_node)
94
- n = len(matched_routes)
95
-
96
- for i in range(n):
97
- route = matched_routes[n - i - 1]
98
- match, child_scope = route.matches(scope)
99
- if match.value == 2:
100
- scope.update(child_scope)
101
- await route.handle(scope, receive, send)
102
- return
103
- elif match.value == 1 and partial is None:
104
- partial = route
105
- partial_scope = child_scope
126
+ leaf_node = search_node(route_path)
127
+
128
+ if leaf_node.prefix == route_path:
129
+ for route in leaf_node.static_routes:
130
+ match, child_scope = route.matches(scope)
131
+ if match.value == 2:
132
+ scope.update(child_scope)
133
+ await route.handle(scope, receive, send)
134
+ return
135
+ elif match.value == 1 and partial is None:
136
+ partial = route
137
+ partial_scope = child_scope
138
+ else:
139
+ current_node = leaf_node
140
+ routes = current_node.params_routes
141
+ while current_node.parent:
142
+ for route in routes:
143
+ match, child_scope = route.matches(scope)
144
+ if match.value == 2:
145
+ scope.update(child_scope)
146
+ await route.handle(scope, receive, send)
147
+ return
148
+ elif match.value == 1 and partial is None:
149
+ partial = route
150
+ partial_scope = child_scope
151
+ current_node = current_node.parent
106
152
 
107
153
  if partial is not None:
108
154
  scope.update(partial_scope)
109
155
  await partial.handle(scope, receive, send)
110
156
  return
111
157
 
112
-
113
158
  if scope["type"] == "http" and router.redirect_slashes and route_path != "/":
114
159
  redirect_scope = dict(scope)
115
160
  if route_path.endswith("/"):
116
161
  redirect_scope["path"] = redirect_scope["path"].rstrip("/")
117
162
  else:
118
163
  redirect_scope["path"] = redirect_scope["path"] + "/"
119
-
120
- for i in range(n):
121
- route = matched_routes[n - i - 1]
122
- match, child_scope = route.matches(redirect_scope)
123
- if match.value != 0:
124
- redirect_url = URL(scope=redirect_scope)
125
- response = RedirectResponse(url=str(redirect_url))
126
- await response(scope, receive, send)
127
- return
164
+
165
+ if leaf_node.prefix == redirect_scope["path"]:
166
+ for route in leaf_node.static_routes:
167
+ match, child_scope = route.matches(redirect_scope)
168
+ if match.value != 0:
169
+ redirect_url = URL(scope=redirect_scope)
170
+ response = RedirectResponse(url=str(redirect_url))
171
+ await response(scope, receive, send)
172
+ return
173
+ else:
174
+ current_node = leaf_node
175
+ routes = current_node.params_routes
176
+ while current_node.parent:
177
+ for route in routes:
178
+ if match.value != 0:
179
+ redirect_url = URL(scope=redirect_scope)
180
+ response = RedirectResponse(url=str(redirect_url))
181
+ await response(scope, receive, send)
182
+ return
183
+ current_node = current_node.parent
128
184
 
129
185
  await router.default(scope, receive, send)
130
186
 
131
187
 
132
188
  def install(app):
133
189
  for route in app.routes:
134
- add_route(route.path, root_node, route)
135
- app.router.app = handle
190
+ root_node.add_route(route.path, route)
191
+
192
+ app.router.middleware_stack = handle
Binary file
@@ -0,0 +1,16 @@
1
+ __author__ = "ziyan.yin"
2
+ __describe__ = ""
3
+
4
+
5
+ from typing import Any
6
+ from fastapi import FastAPI
7
+
8
+
9
+ class RouteNode:
10
+
11
+ def add_route(self, fullpath: str, handler: Any):
12
+ ...
13
+
14
+
15
+ def install(app: FastAPI) -> None:
16
+ ...
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-extra
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: extra package for fastapi.
5
5
  Author-email: Ziyan Yin <408856732@qq.com>
6
6
  License: BSD-3-Clause
@@ -1,10 +1,12 @@
1
- fastapi_extra/__init__.py,sha256=MXf66njTRTUqUMbjSkWGF6HxU-1Dm8UVgfC5qh-uehM,286
2
- fastapi_extra/cursor.cp312-win_amd64.pyd,sha256=0HTvLo9ZEY-GwvATHIVeaU5x-B1nxhdA8EvCZ6WhOu8,53760
1
+ fastapi_extra/__init__.py,sha256=nZY4R9s4b2NNPoO6UZnpGbs_Vm2cXhT_Infu-VyNvWM,286
2
+ fastapi_extra/cursor.cp312-win_amd64.pyd,sha256=nKZAYOxCrwr51-YZnXjKFTvpL6RKBMeQd55elvgiqhk,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=XlIyK5YoFeGcNGb_Mv27BYdjEEYJh2qlJagu7dZIJHk,87552
8
+ fastapi_extra/routing.cp312-win_amd64.pyd,sha256=kOfgWarbRkQDTYZAh4LYvyEB5d6DoxnpfzOYbRl6qJk,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
@@ -14,10 +16,10 @@ fastapi_extra/database/__init__.py,sha256=pCYUoEylTponWqpR0AXJHcRo_cs4fnEXVVV9B5
14
16
  fastapi_extra/database/model.py,sha256=2lDi9PQ5F0PSM7BGZozZf1wSefpXnTWqAVzEyGPaXRI,2453
15
17
  fastapi_extra/database/service.py,sha256=-tBC17jEbGZhnxdtWyftP2BUXfCwcOtxzNZ53qLp518,1798
16
18
  fastapi_extra/database/session.py,sha256=PALArHhXNS2gCgeMkiKjyatvINV_VW1LjgEIwXDKyfQ,1903
17
- fastapi_extra/native/cursor.pyx,sha256=bESprFDgk9gGjyPQ4YCSg51dov2WB6s60XrOs3r5-r0,1146
18
- fastapi_extra/native/routing.pyx,sha256=GrdGAoBospwCpxMHBon5cuRYcz9ifAFSSYa2Ytf49lg,3841
19
- fastapi_extra-0.2.0.dist-info/licenses/LICENSE,sha256=0vTjHDa3VDsxTT-R-sH6SpYcA2F1hKtbX9ZFZQm-EcU,1516
20
- fastapi_extra-0.2.0.dist-info/METADATA,sha256=CRLVgSMLpfE9MQ-pj1aEAdC_c_7wCtGG9pCA2ARn-ts,1371
21
- fastapi_extra-0.2.0.dist-info/WHEEL,sha256=RYNUKzg4pggqpqERKe4OLbPF4ZPP-Ng-rmq_sekLDXg,101
22
- fastapi_extra-0.2.0.dist-info/top_level.txt,sha256=B7D80bEftE2E-eSd1be2r9BWkLLMZN21dRTWpb4y4Ig,14
23
- fastapi_extra-0.2.0.dist-info/RECORD,,
19
+ fastapi_extra/native/cursor.pyx,sha256=GchJIPY6e5scuyl1BbA-Et0CdRcHOI3xgsTvDem0B70,1141
20
+ fastapi_extra/native/routing.pyx,sha256=DfK83nSwI2l8KATZ9YXLXjMXSy42YxjxZvwhQEpa0fI,6262
21
+ fastapi_extra-0.2.1.dist-info/licenses/LICENSE,sha256=0vTjHDa3VDsxTT-R-sH6SpYcA2F1hKtbX9ZFZQm-EcU,1516
22
+ fastapi_extra-0.2.1.dist-info/METADATA,sha256=ii3OEMR1gHqVOIQzzDTQiGNVXQXqmT_NtRthARtu_is,1371
23
+ fastapi_extra-0.2.1.dist-info/WHEEL,sha256=8UP9x9puWI0P1V_d7K2oMTBqfeLNm21CTzZ_Ptr0NXU,101
24
+ fastapi_extra-0.2.1.dist-info/top_level.txt,sha256=B7D80bEftE2E-eSd1be2r9BWkLLMZN21dRTWpb4y4Ig,14
25
+ fastapi_extra-0.2.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.8.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp312-cp312-win_amd64
5
5