hypern 0.2.0__cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.whl → 0.3.0__cp312-cp312-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
@@ -2,23 +2,21 @@
2
2
  from __future__ import annotations
3
3
 
4
4
  import asyncio
5
- import socket
6
5
  from typing import Any, Callable, List, TypeVar
7
6
 
8
7
  import orjson
9
8
  from typing_extensions import Annotated, Doc
10
9
 
11
10
  from hypern.datastructures import Contact, HTTPMethod, Info, License
12
- from hypern.exceptions import InvalidPortNumber
13
- from hypern.hypern import FunctionInfo, Router
14
- from hypern.hypern import Route as InternalRoute
15
- from hypern.logging import logger
11
+ from hypern.hypern import FunctionInfo, Router, Route as InternalRoute, WebsocketRouter
16
12
  from hypern.openapi import SchemaGenerator, SwaggerUI
17
13
  from hypern.processpool import run_processes
18
14
  from hypern.response import HTMLResponse, JSONResponse
19
15
  from hypern.routing import Route
20
16
  from hypern.scheduler import Scheduler
21
17
  from hypern.middleware import Middleware
18
+ from hypern.args_parser import ArgsConfig
19
+ from hypern.ws import WebsocketRoute
22
20
 
23
21
  AppType = TypeVar("AppType", bound="Hypern")
24
22
 
@@ -49,6 +47,15 @@ class Hypern:
49
47
  """
50
48
  ),
51
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,
52
59
  title: Annotated[
53
60
  str,
54
61
  Doc(
@@ -188,15 +195,20 @@ class Hypern:
188
195
  ) -> None:
189
196
  super().__init__(*args, **kwargs)
190
197
  self.router = Router(path="/")
198
+ self.websocket_router = WebsocketRouter(path="/")
191
199
  self.scheduler = scheduler
192
200
  self.injectables = default_injectables or {}
193
201
  self.middleware_before_request = []
194
202
  self.middleware_after_request = []
195
203
  self.response_headers = {}
204
+ self.args = ArgsConfig()
196
205
 
197
- for route in routes:
206
+ for route in routes or []:
198
207
  self.router.extend_route(route(app=self).routes)
199
208
 
209
+ for websocket_route in websockets or []:
210
+ self.websocket_router.add_route(websocket_route)
211
+
200
212
  if openapi_url and docs_url:
201
213
  self.__add_openapi(
202
214
  info=Info(
@@ -340,60 +352,31 @@ class Hypern:
340
352
  self.after_request()(after_request)
341
353
  return self
342
354
 
343
- def is_port_in_use(self, port: int) -> bool:
344
- try:
345
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
346
- return s.connect_ex(("localhost", port)) == 0
347
- except Exception:
348
- raise InvalidPortNumber(f"Invalid port number: {port}")
349
-
350
355
  def start(
351
356
  self,
352
- host: Annotated[str, Doc("The host to run the server on. Defaults to `127.0.0.1`")] = "127.0.0.1",
353
- port: Annotated[int, Doc("The port to run the server on. Defaults to `8080`")] = 8080,
354
- workers: Annotated[int, Doc("The number of workers to run. Defaults to `1`")] = 1,
355
- processes: Annotated[int, Doc("The number of processes to run. Defaults to `1`")] = 1,
356
- max_blocking_threads: Annotated[int, Doc("The maximum number of blocking threads. Defaults to `100`")] = 1,
357
- check_port: Annotated[bool, Doc("Check if the port is already in use. Defaults to `True`")] = False,
358
357
  ):
359
358
  """
360
359
  Starts the server with the specified configuration.
361
-
362
- Args:
363
- host (str): The host to run the server on. Defaults to `127.0.0.1`.
364
- port (int): The port to run the server on. Defaults to `8080`.
365
- workers (int): The number of workers to run. Defaults to `1`.
366
- processes (int): The number of processes to run. Defaults to `1`.
367
- max_blocking_threads (int): The maximum number of blocking threads. Defaults to `100`.
368
- check_port (bool): Check if the port is already in use. Defaults to `True`.
369
-
370
360
  Raises:
371
361
  ValueError: If an invalid port number is entered when prompted.
372
362
 
373
363
  """
374
- if check_port:
375
- while self.is_port_in_use(port):
376
- logger.error("Port %s is already in use. Please use a different port.", port)
377
- try:
378
- port = int(input("Enter a different port: "))
379
- except Exception:
380
- logger.error("Invalid port number. Please enter a valid port number.")
381
- continue
382
-
383
364
  if self.scheduler:
384
365
  self.scheduler.start()
385
366
 
386
367
  run_processes(
387
- host=host,
388
- port=port,
389
- workers=workers,
390
- processes=processes,
391
- max_blocking_threads=max_blocking_threads,
368
+ host=self.args.host,
369
+ port=self.args.port,
370
+ workers=self.args.workers,
371
+ processes=self.args.processes,
372
+ max_blocking_threads=self.args.max_blocking_threads,
392
373
  router=self.router,
374
+ websocket_router=self.websocket_router,
393
375
  injectables=self.injectables,
394
376
  before_request=self.middleware_before_request,
395
377
  after_request=self.middleware_after_request,
396
378
  response_headers=self.response_headers,
379
+ reload=self.args.reload,
397
380
  )
398
381
 
399
382
  def add_route(self, method: HTTPMethod, endpoint: str, handler: Callable[..., Any]):
@@ -410,3 +393,13 @@ class Hypern:
410
393
  func_info = FunctionInfo(handler=handler, is_async=is_async)
411
394
  route = InternalRoute(path=endpoint, function=func_info, method=method.name)
412
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)
hypern/args_parser.py ADDED
@@ -0,0 +1,59 @@
1
+ import argparse
2
+
3
+
4
+ class ArgsConfig:
5
+ def __init__(self) -> None:
6
+ parser = argparse.ArgumentParser(description="Hypern: A Versatile Python and Rust Framework")
7
+ self.parser = parser
8
+ parser.add_argument(
9
+ "--host",
10
+ type=str,
11
+ default=None,
12
+ required=False,
13
+ help="Choose the host. [Defaults to `127.0.0.1`]",
14
+ )
15
+
16
+ parser.add_argument(
17
+ "--port",
18
+ type=int,
19
+ default=None,
20
+ required=False,
21
+ help="Choose the port. [Defaults to `5000`]",
22
+ )
23
+
24
+ parser.add_argument(
25
+ "--processes",
26
+ type=int,
27
+ default=None,
28
+ required=False,
29
+ help="Choose the number of processes. [Default: 1]",
30
+ )
31
+ parser.add_argument(
32
+ "--workers",
33
+ type=int,
34
+ default=None,
35
+ required=False,
36
+ help="Choose the number of workers. [Default: 1]",
37
+ )
38
+
39
+ parser.add_argument(
40
+ "--max-blocking-threads",
41
+ type=int,
42
+ default=None,
43
+ required=False,
44
+ help="Choose the maximum number of blocking threads. [Default: 100]",
45
+ )
46
+
47
+ parser.add_argument(
48
+ "--reload",
49
+ action="store_true",
50
+ help="It restarts the server based on file changes.",
51
+ )
52
+ args, _ = parser.parse_known_args()
53
+
54
+ self.host = args.host or "127.0.0.1"
55
+ self.port = args.port or 5000
56
+ self.max_blocking_threads = args.max_blocking_threads or 100
57
+ self.processes = args.processes or 1
58
+ self.workers = args.workers or 1
59
+ self.reload = args.reload or False
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
hypern/logging/logger.py CHANGED
@@ -59,7 +59,7 @@ class ColourizedFormatter(logging.Formatter):
59
59
  recordcopy.__dict__["message"] = recordcopy.getMessage()
60
60
  recordcopy.__dict__["levelprefix"] = levelname + separator
61
61
  recordcopy.__dict__["process"] = click.style(str(process), fg="blue")
62
- recordcopy.__dict__["asctime"] = click.style(datetime.fromtimestamp(created, tz=timezone.utc).strftime("%Y-%m-%d %H:%M:%S.%fZ"), fg=(101, 111, 104))
62
+ recordcopy.__dict__["asctime"] = click.style(datetime.fromtimestamp(created, tz=timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%fZ"), fg=(101, 111, 104))
63
63
  recordcopy.__dict__["filename"] = click.style(f"{module}/{filename}:{lineno}:", fg=(101, 111, 104))
64
64
  return super().formatMessage(recordcopy)
65
65
 
@@ -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
@@ -1,12 +1,15 @@
1
1
  import asyncio
2
+ import os
2
3
  import signal
3
4
  import sys
4
5
  from typing import Any, Dict, List
5
6
 
6
7
  from multiprocess import Process
8
+ from watchdog.observers import Observer
7
9
 
8
- from .hypern import FunctionInfo, Router, Server, SocketHeld
10
+ from .hypern import FunctionInfo, Router, Server, SocketHeld, WebsocketRouter
9
11
  from .logging import logger
12
+ from .reload import EventHandler
10
13
 
11
14
 
12
15
  def run_processes(
@@ -16,14 +19,18 @@ def run_processes(
16
19
  processes: int,
17
20
  max_blocking_threads: int,
18
21
  router: Router,
22
+ websocket_router: WebsocketRouter,
19
23
  injectables: Dict[str, Any],
20
24
  before_request: List[FunctionInfo],
21
25
  after_request: List[FunctionInfo],
22
26
  response_headers: Dict[str, str],
27
+ reload: bool = True,
23
28
  ) -> List[Process]:
24
29
  socket = SocketHeld(host, port)
25
30
 
26
- 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
+ )
27
34
 
28
35
  def terminating_signal_handler(_sig, _frame):
29
36
  logger.info("Terminating server!!")
@@ -33,15 +40,37 @@ def run_processes(
33
40
  signal.signal(signal.SIGINT, terminating_signal_handler)
34
41
  signal.signal(signal.SIGTERM, terminating_signal_handler)
35
42
 
36
- logger.info("Press Ctrl + C to stop \n")
37
- for process in process_pool:
38
- process.join()
43
+ if reload:
44
+ # Set up file system watcher for auto-reload
45
+ watch_dirs = [os.getcwd()]
46
+ observer = Observer()
47
+ reload_handler = EventHandler(file_path=sys.argv[0], directory_path=os.getcwd())
48
+
49
+ for directory in watch_dirs:
50
+ observer.schedule(reload_handler, directory, recursive=True)
51
+
52
+ observer.start()
53
+
54
+ logger.info(f"Server started at http://{host}:{port}")
55
+ logger.info("Press Ctrl + C to stop")
56
+
57
+ try:
58
+ for process in process_pool:
59
+ logger.debug(f"Process {process.pid} started")
60
+ process.join()
61
+ except KeyboardInterrupt:
62
+ pass
63
+ finally:
64
+ if reload:
65
+ observer.stop()
66
+ observer.join()
39
67
 
40
68
  return process_pool
41
69
 
42
70
 
43
71
  def init_processpool(
44
72
  router: Router,
73
+ websocket_router: WebsocketRouter,
45
74
  socket: SocketHeld,
46
75
  workers: int,
47
76
  processes: int,
@@ -57,7 +86,7 @@ def init_processpool(
57
86
  copied_socket = socket.try_clone()
58
87
  process = Process(
59
88
  target=spawn_process,
60
- 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),
61
90
  )
62
91
  process.start()
63
92
  process_pool.append(process)
@@ -81,6 +110,7 @@ def initialize_event_loop():
81
110
 
82
111
  def spawn_process(
83
112
  router: Router,
113
+ websocket_router: WebsocketRouter,
84
114
  socket: SocketHeld,
85
115
  workers: int,
86
116
  max_blocking_threads: int,
@@ -93,6 +123,7 @@ def spawn_process(
93
123
 
94
124
  server = Server()
95
125
  server.set_router(router=router)
126
+ server.set_websocket_router(websocket_router=websocket_router)
96
127
  server.set_injected(injected=injectables)
97
128
  server.set_before_hooks(hooks=before_request)
98
129
  server.set_after_hooks(hooks=after_request)
hypern/reload.py ADDED
@@ -0,0 +1,60 @@
1
+ import sys
2
+ import time
3
+ import subprocess
4
+ from watchdog.events import FileSystemEventHandler
5
+
6
+ from .logging import logger
7
+
8
+
9
+ class EventHandler(FileSystemEventHandler):
10
+ def __init__(self, file_path: str, directory_path: str) -> None:
11
+ self.file_path = file_path
12
+ self.directory_path = directory_path
13
+ self.process = None # Keep track of the subprocess
14
+ self.last_reload = time.time() # Keep track of the last reload. EventHandler is initialized with the process.
15
+
16
+ def stop_server(self):
17
+ if self.process:
18
+ try:
19
+ # Check if the process is still alive
20
+ if self.process.poll() is None: # None means the process is still running
21
+ self.process.terminate() # Gracefully terminate the process
22
+ self.process.wait(timeout=5) # Wait for the process to exit
23
+ else:
24
+ logger.error("Process is not running.")
25
+ except subprocess.TimeoutExpired:
26
+ logger.error("Process did not terminate in time. Forcing termination.")
27
+ self.process.kill() # Forcefully kill the process if it doesn't stop
28
+ except ProcessLookupError:
29
+ logger.error("Process does not exist.")
30
+ except Exception as e:
31
+ logger.error(f"An error occurred while stopping the server: {e}")
32
+ else:
33
+ logger.debug("No process to stop.")
34
+
35
+ def reload(self):
36
+ self.stop_server()
37
+ logger.debug("Reloading the server")
38
+ prev_process = self.process
39
+ if prev_process:
40
+ prev_process.kill()
41
+
42
+ self.process = subprocess.Popen(
43
+ [sys.executable, *sys.argv],
44
+ )
45
+
46
+ self.last_reload = time.time()
47
+
48
+ def on_modified(self, event) -> None:
49
+ """
50
+ This function is a callback that will start a new server on every even change
51
+
52
+ :param event FSEvent: a data structure with info about the events
53
+ """
54
+
55
+ # Avoid reloading multiple times when watchdog detects multiple events
56
+ if time.time() - self.last_reload < 0.5:
57
+ return
58
+
59
+ time.sleep(0.2) # Wait for the file to be fully written
60
+ self.reload()
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.0
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
@@ -22,6 +22,7 @@ Requires-Dist: orjson ==3.10.11
22
22
  Requires-Dist: multiprocess ==0.70.17
23
23
  Requires-Dist: uvloop ==0.21.0 ; sys_platform != 'win32' and platform_python_implementation == 'CPython' and platform_machine != 'armv7l'
24
24
  Requires-Dist: cryptography ==43.0.3
25
+ Requires-Dist: watchdog ==6.0.0
25
26
  License-File: LICENSE
26
27
  Summary: A Fast Async Python backend with a Rust runtime.
27
28
  Author-email: Martin Dang <vannghiem848@gmail.com>
@@ -1,25 +1,27 @@
1
- hypern-0.2.0.dist-info/METADATA,sha256=vr_oCiPq5bDdIyTt0w6S_phtY8IvEX-oRW407K-Wd-o,3626
2
- hypern-0.2.0.dist-info/WHEEL,sha256=o8sInZVN8vcuWYVPD-pUpJuGZk9YuD70jVvxGoQg6-0,125
3
- hypern-0.2.0.dist-info/licenses/LICENSE,sha256=VdbaK2hSaaD-LUjtDIlEbeZVmvLGK7BEQvltP3mv-cY,1304
4
- hypern/application.py,sha256=fZ4pXSLHuJO7hyIq3THFnNDfpXJt3p5IxYYYgmOBNXU,14771
1
+ hypern-0.3.0.dist-info/METADATA,sha256=SINnZRpXUXjLnonzyUZ-STXzjY1JRGPl_nu0vqF0Qkg,3658
2
+ hypern-0.3.0.dist-info/WHEEL,sha256=IVSFWXFWSEs2jwzqcaXi10esovSNujWh380jSRKxYz0,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=q985ILIzI7CSiusRL614PwOAT4RCczon7e-CAn1U5Vc,2925
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/logging/logger.py,sha256=hYOLjx_UVdnaDLFnmCZMANx3rgs4TIGsvtBFJ-YlYxg,3174
21
+ hypern/hypern.pyi,sha256=WlE2tNIY3FnJaUorHKfJ7tY-DZf83XK7bRvzrxauyr4,7405
22
+ hypern/logging/logger.py,sha256=62Qg4YAi_JDGV72Rd6R58jixqZk7anRqHbtnuBlkrwA,3174
22
23
  hypern/logging/__init__.py,sha256=lzYSz0382eIM3CvP0sZ6RbEEwYZwfeJEJh9cxQA6Rws,49
24
+ hypern/reload.py,sha256=oRwDyxze69ERiVT41eJI_qpg6eJFDbIszGPVAoS5DHs,2233
23
25
  hypern/exceptions.py,sha256=wpTSTzw32Sb6bY9YxCDM7W_-Ww6u6pB1GKNbFf-1oj0,2331
24
26
  hypern/openapi/schemas.py,sha256=nmcmNYvKmjNkwFqi_3qpXVi1ukanNxMVay68bOLTrx8,1624
25
27
  hypern/openapi/__init__.py,sha256=oJ0HM9yAgSN00mBC_fRgV2irlGugrhvIpiveuDMv8PM,136
@@ -39,6 +41,7 @@ hypern/caching/redis_backend.py,sha256=3FYzKCW0_OvoIMl-e9pARRGOUvRYGG7hGlaXEB18v
39
41
  hypern/caching/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
42
  hypern/caching/custom_key_maker.py,sha256=DxJv1RV--5IdFCCFYawVExwMQ097hZ5V6_nHDYIQIZI,383
41
43
  hypern/caching/cache_manager.py,sha256=EBx89xNj38bYpQ9jf4MoQ3zNkfoCGYInxvvPtzsW5Xo,1997
44
+ hypern/args_parser.py,sha256=kJQtzw2xZrumDBzLQaZyEejAT02rUetPYCrmOpjzxWY,1731
42
45
  hypern/enum.py,sha256=-StRU0cWboP-y5fNuhB4Q7yMk8Zm_h1Eua9KzOtIyI8,347
43
46
  hypern/worker.py,sha256=kN93QGx4bst0inHRO_fsTzMmhDA0N3pdzaqNXwyu3N0,894
44
47
  hypern/db/nosql/__init__.py,sha256=LCVBhcJCQmFt5dCLiSf7C_TsjsEILeZe8JqiFEKuD2s,619
@@ -62,5 +65,5 @@ hypern/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
65
  hypern/datastructures.py,sha256=7Nb_fOxmfO8CT7_v_-RhmXg54IhioXGZSp405IzJLh4,857
63
66
  hypern/config.py,sha256=v9KLL6snReAETKiVb8x3KOFrXpYd8-Io5tM7eruR85U,4781
64
67
  hypern/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
65
- hypern/hypern.cpython-312-i386-linux-gnu.so,sha256=g5_ahAIXUIFfyFOMu72jvU__BrPnMBRqlyy6wqCEft8,6258556
66
- hypern-0.2.0.dist-info/RECORD,,
68
+ hypern/hypern.cpython-312-i386-linux-gnu.so,sha256=q6UBGw9RKhwgvnPcD-hRHsPGvrhbv2FDio_k74iZ-oo,6504596
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: cp312-cp312-manylinux_2_12_i686.manylinux2010_i686