hypern 0.2.1__cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl → 0.3.0__cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.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.
hypern/application.py CHANGED
@@ -8,8 +8,7 @@ import orjson
8
8
  from typing_extensions import Annotated, Doc
9
9
 
10
10
  from hypern.datastructures import Contact, HTTPMethod, Info, License
11
- from hypern.hypern import FunctionInfo, Router
12
- from hypern.hypern import Route as InternalRoute
11
+ from hypern.hypern import FunctionInfo, Router, Route as InternalRoute, WebsocketRouter
13
12
  from hypern.openapi import SchemaGenerator, SwaggerUI
14
13
  from hypern.processpool import run_processes
15
14
  from hypern.response import HTMLResponse, JSONResponse
@@ -17,6 +16,7 @@ from hypern.routing import Route
17
16
  from hypern.scheduler import Scheduler
18
17
  from hypern.middleware import Middleware
19
18
  from hypern.args_parser import ArgsConfig
19
+ from hypern.ws import WebsocketRoute
20
20
 
21
21
  AppType = TypeVar("AppType", bound="Hypern")
22
22
 
@@ -47,6 +47,15 @@ class Hypern:
47
47
  """
48
48
  ),
49
49
  ] = None,
50
+ websockets: Annotated[
51
+ List[WebsocketRoute] | None,
52
+ Doc(
53
+ """
54
+ A list of routes to serve incoming WebSocket requests.
55
+ You can define routes using the `WebsocketRoute` class from `Hypern
56
+ """
57
+ ),
58
+ ] = None,
50
59
  title: Annotated[
51
60
  str,
52
61
  Doc(
@@ -186,6 +195,7 @@ class Hypern:
186
195
  ) -> None:
187
196
  super().__init__(*args, **kwargs)
188
197
  self.router = Router(path="/")
198
+ self.websocket_router = WebsocketRouter(path="/")
189
199
  self.scheduler = scheduler
190
200
  self.injectables = default_injectables or {}
191
201
  self.middleware_before_request = []
@@ -193,9 +203,12 @@ class Hypern:
193
203
  self.response_headers = {}
194
204
  self.args = ArgsConfig()
195
205
 
196
- for route in routes:
206
+ for route in routes or []:
197
207
  self.router.extend_route(route(app=self).routes)
198
208
 
209
+ for websocket_route in websockets or []:
210
+ self.websocket_router.add_route(websocket_route)
211
+
199
212
  if openapi_url and docs_url:
200
213
  self.__add_openapi(
201
214
  info=Info(
@@ -358,6 +371,7 @@ class Hypern:
358
371
  processes=self.args.processes,
359
372
  max_blocking_threads=self.args.max_blocking_threads,
360
373
  router=self.router,
374
+ websocket_router=self.websocket_router,
361
375
  injectables=self.injectables,
362
376
  before_request=self.middleware_before_request,
363
377
  after_request=self.middleware_after_request,
@@ -379,3 +393,13 @@ class Hypern:
379
393
  func_info = FunctionInfo(handler=handler, is_async=is_async)
380
394
  route = InternalRoute(path=endpoint, function=func_info, method=method.name)
381
395
  self.router.add_route(route=route)
396
+
397
+ def add_websocket(self, ws_route: WebsocketRoute):
398
+ """
399
+ Adds a WebSocket route to the WebSocket router.
400
+
401
+ Args:
402
+ ws_route (WebsocketRoute): The WebSocket route to be added to the router.
403
+ """
404
+ for route in ws_route.routes:
405
+ self.websocket_router.add_route(route=route)
Binary file
hypern/hypern.pyi CHANGED
@@ -183,9 +183,6 @@ class FunctionInfo:
183
183
  handler: Callable
184
184
  is_async: bool
185
185
 
186
- class SocketHeld:
187
- socket: Any
188
-
189
186
  @dataclass
190
187
  class Server:
191
188
  router: Router
@@ -195,6 +192,7 @@ class Server:
195
192
 
196
193
  def add_route(self, route: Route) -> None: ...
197
194
  def set_router(self, router: Router) -> None: ...
195
+ def set_websocket_router(self, websocket_router: WebsocketRouter) -> None: ...
198
196
  def start(self, socket: SocketHeld, worker: int, max_blocking_threads: int) -> None: ...
199
197
  def inject(self, key: str, value: Any) -> None: ...
200
198
  def set_injected(self, injected: Dict[str, Any]) -> None: ...
@@ -227,6 +225,34 @@ class Router:
227
225
  def get_routes_by_method(self, method: str) -> List[Route]: ...
228
226
  def extend_route(self, routes: List[Route]) -> None: ...
229
227
 
228
+ @dataclass
229
+ class SocketHeld:
230
+ socket: Any
231
+
232
+ @dataclass
233
+ class WebSocketSession:
234
+ sender: Callable[[str], None]
235
+ receiver: Callable[[], str]
236
+ is_closed: bool
237
+
238
+ def send(self, message: str) -> None: ...
239
+
240
+ @dataclass
241
+ class WebsocketRoute:
242
+ path: str
243
+ handler: Callable[[WebSocketSession], None]
244
+
245
+ @dataclass
246
+ class WebsocketRouter:
247
+ path: str
248
+ routes: List[WebsocketRoute]
249
+
250
+ def add_route(self, route: WebsocketRoute) -> None: ...
251
+ def remove_route(self, path: str) -> None: ...
252
+ def extend_route(self, route: WebsocketRoute) -> None: ...
253
+ def clear_routes(self) -> None: ...
254
+ def route_count(self) -> int: ...
255
+
230
256
  @dataclass
231
257
  class Header:
232
258
  headers: Dict[str, str]
@@ -264,3 +290,6 @@ class Request:
264
290
  path_params: Dict[str, str]
265
291
  body: BodyData
266
292
  method: str
293
+ remote_addr: str
294
+ timestamp: float
295
+ context_id: str
@@ -147,7 +147,7 @@ class ConcurrentRequestMiddleware(Middleware):
147
147
  self.lock = Lock()
148
148
 
149
149
  def get_request_identifier(self, request):
150
- return request.ip_addr
150
+ return request.remote_addr
151
151
 
152
152
  def before_request(self, request):
153
153
  """
hypern/processpool.py CHANGED
@@ -7,7 +7,7 @@ from typing import Any, Dict, List
7
7
  from multiprocess import Process
8
8
  from watchdog.observers import Observer
9
9
 
10
- from .hypern import FunctionInfo, Router, Server, SocketHeld
10
+ from .hypern import FunctionInfo, Router, Server, SocketHeld, WebsocketRouter
11
11
  from .logging import logger
12
12
  from .reload import EventHandler
13
13
 
@@ -19,6 +19,7 @@ def run_processes(
19
19
  processes: int,
20
20
  max_blocking_threads: int,
21
21
  router: Router,
22
+ websocket_router: WebsocketRouter,
22
23
  injectables: Dict[str, Any],
23
24
  before_request: List[FunctionInfo],
24
25
  after_request: List[FunctionInfo],
@@ -27,7 +28,9 @@ def run_processes(
27
28
  ) -> List[Process]:
28
29
  socket = SocketHeld(host, port)
29
30
 
30
- process_pool = init_processpool(router, socket, workers, processes, max_blocking_threads, injectables, before_request, after_request, response_headers)
31
+ process_pool = init_processpool(
32
+ router, websocket_router, socket, workers, processes, max_blocking_threads, injectables, before_request, after_request, response_headers
33
+ )
31
34
 
32
35
  def terminating_signal_handler(_sig, _frame):
33
36
  logger.info("Terminating server!!")
@@ -67,6 +70,7 @@ def run_processes(
67
70
 
68
71
  def init_processpool(
69
72
  router: Router,
73
+ websocket_router: WebsocketRouter,
70
74
  socket: SocketHeld,
71
75
  workers: int,
72
76
  processes: int,
@@ -82,7 +86,7 @@ def init_processpool(
82
86
  copied_socket = socket.try_clone()
83
87
  process = Process(
84
88
  target=spawn_process,
85
- args=(router, copied_socket, workers, max_blocking_threads, injectables, before_request, after_request, response_headers),
89
+ args=(router, websocket_router, copied_socket, workers, max_blocking_threads, injectables, before_request, after_request, response_headers),
86
90
  )
87
91
  process.start()
88
92
  process_pool.append(process)
@@ -106,6 +110,7 @@ def initialize_event_loop():
106
110
 
107
111
  def spawn_process(
108
112
  router: Router,
113
+ websocket_router: WebsocketRouter,
109
114
  socket: SocketHeld,
110
115
  workers: int,
111
116
  max_blocking_threads: int,
@@ -118,6 +123,7 @@ def spawn_process(
118
123
 
119
124
  server = Server()
120
125
  server.set_router(router=router)
126
+ server.set_websocket_router(websocket_router=websocket_router)
121
127
  server.set_injected(injected=injectables)
122
128
  server.set_before_hooks(hooks=before_request)
123
129
  server.set_after_hooks(hooks=after_request)
hypern/routing/route.py CHANGED
@@ -188,7 +188,7 @@ class Route:
188
188
  docs["responses"] = {
189
189
  "200": {
190
190
  "description": "Successful response",
191
- "content": {"application/json": {"schema": response_type.model_json_schema()}},
191
+ "content": {"application/json": {"schema": pydantic_to_swagger(response_type).get(response_type.__name__)}},
192
192
  }
193
193
  }
194
194
 
hypern/ws.py ADDED
@@ -0,0 +1,16 @@
1
+ from .hypern import WebsocketRoute as WebsocketRouteInternal, WebSocketSession
2
+
3
+
4
+ class WebsocketRoute:
5
+ def __init__(self) -> None:
6
+ self.routes = []
7
+
8
+ def on(self, path):
9
+ def wrapper(func):
10
+ self.routes.append(WebsocketRouteInternal(path, func))
11
+ return func
12
+
13
+ return wrapper
14
+
15
+
16
+ __all__ = ["WebsocketRoute", "WebSocketSession"]
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: hypern
3
- Version: 0.2.1
3
+ Version: 0.3.0
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -1,23 +1,24 @@
1
- hypern-0.2.1.dist-info/METADATA,sha256=XnBEky_cZRe5MMTijuguzD2xMsbXI8Jc0mLvXmlO1Zo,3658
2
- hypern-0.2.1.dist-info/WHEEL,sha256=3dYz42ztAymIiwEQC7LmGpGwjFphClb96av9UKeGuu0,125
3
- hypern-0.2.1.dist-info/licenses/LICENSE,sha256=VdbaK2hSaaD-LUjtDIlEbeZVmvLGK7BEQvltP3mv-cY,1304
4
- hypern/application.py,sha256=DE9tQjkB4Pa6YQmmKJ7QwdaHDnhW3iw99zsyLJ0uFLI,13018
1
+ hypern-0.3.0.dist-info/METADATA,sha256=SINnZRpXUXjLnonzyUZ-STXzjY1JRGPl_nu0vqF0Qkg,3658
2
+ hypern-0.3.0.dist-info/WHEEL,sha256=FoUXvRjrx9srB--PKQ_WTjugQ9iTCsmmZ8FeY4NnMw8,125
3
+ hypern-0.3.0.dist-info/licenses/LICENSE,sha256=VdbaK2hSaaD-LUjtDIlEbeZVmvLGK7BEQvltP3mv-cY,1304
4
+ hypern/application.py,sha256=yXrKhVKwCQDweHoZPFyWr0ws7nmCOPp6H3aLZLbD7sw,13923
5
5
  hypern/middleware/__init__.py,sha256=YpgxL7GQkzZM91VCNxHT2xmTa1R1b_BUS8n3tZ2b1Ys,268
6
6
  hypern/middleware/cors.py,sha256=SfG-3vAS-4MPXqsIsegNwDx9mqC9lvgUc3RuYzN6HNg,1643
7
7
  hypern/middleware/base.py,sha256=Llcg9wglcumvY4BqaTfrX1OOZDqns4wb34wGF55EXcI,523
8
- hypern/middleware/limit.py,sha256=JNlZ2S5xlr3svt_rvr92ofh_zsVpe1uNuGc2jO5y3GY,7972
8
+ hypern/middleware/limit.py,sha256=9EA79q2GgyZkRynMJj8rfgumEhJKbAvyi3jII6A_BX8,7976
9
9
  hypern/middleware/i18n.py,sha256=s82nQo6kKClZ0s3G3jsy87VRfwxpBDbASB_ErjRL3O0,15
10
10
  hypern/routing/dispatcher.py,sha256=aujogCVTz2mYtZRkEtmpdlxXA9l6X4D072qOiIg-a_Q,2301
11
11
  hypern/routing/__init__.py,sha256=MtyPYRHYMWIiCReZsUjJH93PvluotCbPU3RnWFQQmrA,97
12
- hypern/routing/route.py,sha256=ribSMOo0eZ2WUZ1P8PdiXIsyVA3dHrI1gEYDikRDn4o,10090
12
+ hypern/routing/route.py,sha256=AZc4Qo5iy74q0_U8E5X6RIsudznHZYEZR8MdHRoCmB4,10119
13
13
  hypern/routing/endpoint.py,sha256=AWLHLQNlSGR8IGU6xM0RP-1kP06OJQzqpbXKSiZEzEo,996
14
14
  hypern/routing/parser.py,sha256=4BFn8MAmSX1QplwBXEEgbabYiNUAllYf2svPZoPPD5k,3454
15
15
  hypern/response/__init__.py,sha256=9z99BDgASpG404GK8LGkOsXgac0wFwH_cQOTI5Ju-1U,223
16
16
  hypern/response/response.py,sha256=s6KqscjA7jl8RaZh5gZQgVksPtHKzsRrQywDcEjVSR4,4448
17
17
  hypern/i18n/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- hypern/processpool.py,sha256=Wrh_l87-3w4Z9znc6P22hi8kZfBA8cQ1C0Oaq8ysLVs,3657
18
+ hypern/ws.py,sha256=XImBSYW2SM9s8wprnis8c2uRPhYxIXuDhwgRLLLDU38,378
19
+ hypern/processpool.py,sha256=mtP6qYSKTUgHOQEqtw6yhBvZ4JMAPw6uLxuyd-96CYI,3908
19
20
  hypern/security.py,sha256=dOWdNHA8SoUhlbu6Z2MapOwT9tAhlsierrTBBiEV5-A,1729
20
- hypern/hypern.pyi,sha256=eSqxlY7q6KboRjP3bpRlGSn2sEjxrIHFpxXh1o-qQJ4,6649
21
+ hypern/hypern.pyi,sha256=WlE2tNIY3FnJaUorHKfJ7tY-DZf83XK7bRvzrxauyr4,7405
21
22
  hypern/logging/logger.py,sha256=62Qg4YAi_JDGV72Rd6R58jixqZk7anRqHbtnuBlkrwA,3174
22
23
  hypern/logging/__init__.py,sha256=lzYSz0382eIM3CvP0sZ6RbEEwYZwfeJEJh9cxQA6Rws,49
23
24
  hypern/reload.py,sha256=oRwDyxze69ERiVT41eJI_qpg6eJFDbIszGPVAoS5DHs,2233
@@ -64,5 +65,5 @@ hypern/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
65
  hypern/datastructures.py,sha256=7Nb_fOxmfO8CT7_v_-RhmXg54IhioXGZSp405IzJLh4,857
65
66
  hypern/config.py,sha256=v9KLL6snReAETKiVb8x3KOFrXpYd8-Io5tM7eruR85U,4781
66
67
  hypern/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
67
- hypern/hypern.cpython-310-i386-linux-gnu.so,sha256=oIDe8_eR63Ep5hRTsu20T58RMegTkoeOn1WsrdwkzoI,6250364
68
- hypern-0.2.1.dist-info/RECORD,,
68
+ hypern/hypern.cpython-310-i386-linux-gnu.so,sha256=ldctvI0tUTpF_rGKBuEjMrsMNg-6yWwiz0xEQ05WD-M,6496404
69
+ hypern-0.3.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: maturin (1.7.4)
2
+ Generator: maturin (1.7.7)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp310-cp310-manylinux_2_12_i686.manylinux2010_i686