hypern 0.2.1__cp310-cp310-macosx_10_12_x86_64.whl → 0.3.0__cp310-cp310-macosx_10_12_x86_64.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,10 +1,10 @@
1
- hypern-0.2.1.dist-info/METADATA,sha256=XnBEky_cZRe5MMTijuguzD2xMsbXI8Jc0mLvXmlO1Zo,3658
2
- hypern-0.2.1.dist-info/WHEEL,sha256=LVI1AVbYRTYC5adM2lSivmcJtOl9s941xFznjYMT5P8,106
3
- hypern-0.2.1.dist-info/licenses/LICENSE,sha256=VdbaK2hSaaD-LUjtDIlEbeZVmvLGK7BEQvltP3mv-cY,1304
1
+ hypern-0.3.0.dist-info/METADATA,sha256=SINnZRpXUXjLnonzyUZ-STXzjY1JRGPl_nu0vqF0Qkg,3658
2
+ hypern-0.3.0.dist-info/WHEEL,sha256=O32IZb5kJ6AxRW6nAcwAPHOSGL43bSvKBHNU0JKSSaQ,106
3
+ hypern-0.3.0.dist-info/licenses/LICENSE,sha256=VdbaK2hSaaD-LUjtDIlEbeZVmvLGK7BEQvltP3mv-cY,1304
4
4
  hypern/worker.py,sha256=kN93QGx4bst0inHRO_fsTzMmhDA0N3pdzaqNXwyu3N0,894
5
5
  hypern/middleware/cors.py,sha256=SfG-3vAS-4MPXqsIsegNwDx9mqC9lvgUc3RuYzN6HNg,1643
6
6
  hypern/middleware/__init__.py,sha256=YpgxL7GQkzZM91VCNxHT2xmTa1R1b_BUS8n3tZ2b1Ys,268
7
- hypern/middleware/limit.py,sha256=JNlZ2S5xlr3svt_rvr92ofh_zsVpe1uNuGc2jO5y3GY,7972
7
+ hypern/middleware/limit.py,sha256=9EA79q2GgyZkRynMJj8rfgumEhJKbAvyi3jII6A_BX8,7976
8
8
  hypern/middleware/i18n.py,sha256=s82nQo6kKClZ0s3G3jsy87VRfwxpBDbASB_ErjRL3O0,15
9
9
  hypern/middleware/base.py,sha256=Llcg9wglcumvY4BqaTfrX1OOZDqns4wb34wGF55EXcI,523
10
10
  hypern/config.py,sha256=v9KLL6snReAETKiVb8x3KOFrXpYd8-Io5tM7eruR85U,4781
@@ -21,9 +21,10 @@ hypern/cli/commands.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  hypern/openapi/swagger.py,sha256=E5fHYUfFa77zQsCyQGf_vnqJVpl4_KI5qsKFHdgJEdw,61
22
22
  hypern/openapi/__init__.py,sha256=oJ0HM9yAgSN00mBC_fRgV2irlGugrhvIpiveuDMv8PM,136
23
23
  hypern/openapi/schemas.py,sha256=nmcmNYvKmjNkwFqi_3qpXVi1ukanNxMVay68bOLTrx8,1624
24
- hypern/application.py,sha256=DE9tQjkB4Pa6YQmmKJ7QwdaHDnhW3iw99zsyLJ0uFLI,13018
25
- hypern/hypern.pyi,sha256=eSqxlY7q6KboRjP3bpRlGSn2sEjxrIHFpxXh1o-qQJ4,6649
26
- hypern/processpool.py,sha256=Wrh_l87-3w4Z9znc6P22hi8kZfBA8cQ1C0Oaq8ysLVs,3657
24
+ hypern/ws.py,sha256=XImBSYW2SM9s8wprnis8c2uRPhYxIXuDhwgRLLLDU38,378
25
+ hypern/application.py,sha256=yXrKhVKwCQDweHoZPFyWr0ws7nmCOPp6H3aLZLbD7sw,13923
26
+ hypern/hypern.pyi,sha256=WlE2tNIY3FnJaUorHKfJ7tY-DZf83XK7bRvzrxauyr4,7405
27
+ hypern/processpool.py,sha256=mtP6qYSKTUgHOQEqtw6yhBvZ4JMAPw6uLxuyd-96CYI,3908
27
28
  hypern/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
29
  hypern/db/nosql/addons/color.py,sha256=8zUBFjR19J1zy_WaOCXlS14GjgdOaHAcuSb__zFp_II,430
29
30
  hypern/db/nosql/addons/unicode.py,sha256=vKyqfzrS9SKFo4eKlvu6klST0FrjM0wTx5N3ocvSSO8,258
@@ -47,7 +48,7 @@ hypern/exceptions.py,sha256=wpTSTzw32Sb6bY9YxCDM7W_-Ww6u6pB1GKNbFf-1oj0,2331
47
48
  hypern/scheduler.py,sha256=nQoWIYMRmKd30g4XwdB072hWTNHvJlLd9S6rLlTFKS0,62
48
49
  hypern/args_parser.py,sha256=kJQtzw2xZrumDBzLQaZyEejAT02rUetPYCrmOpjzxWY,1731
49
50
  hypern/routing/dispatcher.py,sha256=aujogCVTz2mYtZRkEtmpdlxXA9l6X4D072qOiIg-a_Q,2301
50
- hypern/routing/route.py,sha256=ribSMOo0eZ2WUZ1P8PdiXIsyVA3dHrI1gEYDikRDn4o,10090
51
+ hypern/routing/route.py,sha256=AZc4Qo5iy74q0_U8E5X6RIsudznHZYEZR8MdHRoCmB4,10119
51
52
  hypern/routing/__init__.py,sha256=MtyPYRHYMWIiCReZsUjJH93PvluotCbPU3RnWFQQmrA,97
52
53
  hypern/routing/parser.py,sha256=4BFn8MAmSX1QplwBXEEgbabYiNUAllYf2svPZoPPD5k,3454
53
54
  hypern/routing/endpoint.py,sha256=AWLHLQNlSGR8IGU6xM0RP-1kP06OJQzqpbXKSiZEzEo,996
@@ -64,5 +65,5 @@ hypern/caching/base/key_maker.py,sha256=FPW9L-N8NSPPgRngqMUCOdLurm1qmqe-KTe4Ucto
64
65
  hypern/caching/redis_backend.py,sha256=3FYzKCW0_OvoIMl-e9pARRGOUvRYGG7hGlaXEB18vnY,67
65
66
  hypern/logging/__init__.py,sha256=lzYSz0382eIM3CvP0sZ6RbEEwYZwfeJEJh9cxQA6Rws,49
66
67
  hypern/logging/logger.py,sha256=62Qg4YAi_JDGV72Rd6R58jixqZk7anRqHbtnuBlkrwA,3174
67
- hypern/hypern.cpython-310-darwin.so,sha256=1zAixAEVaZryZP5wgZ1jfK7VihvPeKZmCkDbGjtoTC4,6077672
68
- hypern-0.2.1.dist-info/RECORD,,
68
+ hypern/hypern.cpython-310-darwin.so,sha256=2W8Aco4VpPEnqvswUUiVmOSNbYZ1mO43q8CKEB0G3kI,6288880
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-macosx_10_12_x86_64