hypern 0.3.7__cp310-cp310-win32.whl → 0.3.8__cp310-cp310-win32.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/__init__.py CHANGED
@@ -1,4 +1,24 @@
1
+ from hypern.logging import logger
2
+ from hypern.routing import HTTPEndpoint, QueuedHTTPEndpoint, Route
3
+ from hypern.ws import WebsocketRoute, WebSocketSession
4
+
1
5
  from .application import Hypern
2
6
  from .hypern import Request, Response
7
+ from .response import FileResponse, HTMLResponse, JSONResponse, PlainTextResponse, RedirectResponse
3
8
 
4
- __all__ = ["Hypern", "Request", "Response"]
9
+ __all__ = [
10
+ "Hypern",
11
+ "Request",
12
+ "Response",
13
+ "Route",
14
+ "HTTPEndpoint",
15
+ "QueuedHTTPEndpoint",
16
+ "WebsocketRoute",
17
+ "WebSocketSession",
18
+ "FileResponse",
19
+ "HTMLResponse",
20
+ "JSONResponse",
21
+ "PlainTextResponse",
22
+ "RedirectResponse",
23
+ "logger",
24
+ ]
hypern/application.py CHANGED
@@ -83,6 +83,14 @@ class Hypern:
83
83
  """
84
84
  ),
85
85
  ] = None,
86
+ dependencies: Annotated[
87
+ dict[str, Any] | None,
88
+ Doc(
89
+ """
90
+ A dictionary of global dependencies that can be accessed by all routes.
91
+ """
92
+ ),
93
+ ] = None,
86
94
  title: Annotated[
87
95
  str,
88
96
  Doc(
@@ -209,22 +217,6 @@ class Hypern:
209
217
  """
210
218
  ),
211
219
  ] = None,
212
- default_injectables: Annotated[
213
- dict[str, Any] | None,
214
- Doc(
215
- """
216
- A dictionary of default injectables to be passed to all routes.
217
- """
218
- ),
219
- ] = None,
220
- auto_compression: Annotated[
221
- bool,
222
- Doc(
223
- """
224
- Enable automatic compression of responses.
225
- """
226
- ),
227
- ] = False,
228
220
  database_config: Annotated[
229
221
  DatabaseConfig | None,
230
222
  Doc(
@@ -239,15 +231,14 @@ class Hypern:
239
231
  super().__init__(*args, **kwargs)
240
232
  self.router = Router(path="/")
241
233
  self.websocket_router = WebsocketRouter(path="/")
234
+ self.dependencies = dependencies or {}
242
235
  self.scheduler = scheduler
243
- self.injectables = default_injectables or {}
244
236
  self.middleware_before_request = []
245
237
  self.middleware_after_request = []
246
238
  self.response_headers = {}
247
239
  self.args = ArgsConfig()
248
240
  self.start_up_handler = None
249
241
  self.shutdown_handler = None
250
- self.auto_compression = auto_compression
251
242
  self.database_config = database_config
252
243
  self.thread_config = ThreadConfigurator().get_config()
253
244
 
@@ -255,7 +246,8 @@ class Hypern:
255
246
  self.router.extend_route(route(app=self).routes)
256
247
 
257
248
  for websocket_route in websockets or []:
258
- self.websocket_router.add_route(websocket_route)
249
+ for route in websocket_route.routes:
250
+ self.websocket_router.add_route(route)
259
251
 
260
252
  if openapi_url and docs_url:
261
253
  self.__add_openapi(
@@ -313,6 +305,20 @@ class Hypern:
313
305
  self.add_route(HTTPMethod.GET, openapi_url, schema)
314
306
  self.add_route(HTTPMethod.GET, docs_url, template_render)
315
307
 
308
+ def inject(self, key: str, value: Any):
309
+ """
310
+ Injects a key-value pair into the injectables dictionary.
311
+
312
+ Args:
313
+ key (str): The key to be added to the injectables dictionary.
314
+ value (Any): The value to be associated with the key.
315
+
316
+ Returns:
317
+ self: Returns the instance of the class to allow method chaining.
318
+ """
319
+ self.dependencies[key] = value
320
+ return self
321
+
316
322
  def add_response_header(self, key: str, value: str):
317
323
  """
318
324
  Adds a response header to the response headers dictionary.
@@ -366,20 +372,6 @@ class Hypern:
366
372
 
367
373
  return decorator
368
374
 
369
- def inject(self, key: str, value: Any):
370
- """
371
- Injects a key-value pair into the injectables dictionary.
372
-
373
- Args:
374
- key (str): The key to be added to the injectables dictionary.
375
- value (Any): The value to be associated with the key.
376
-
377
- Returns:
378
- self: Returns the instance of the class to allow method chaining.
379
- """
380
- self.injectables[key] = value
381
- return self
382
-
383
375
  def add_middleware(self, middleware: Middleware):
384
376
  """
385
377
  Adds middleware to the application.
@@ -429,12 +421,10 @@ class Hypern:
429
421
  server = Server()
430
422
  server.set_router(router=self.router)
431
423
  server.set_websocket_router(websocket_router=self.websocket_router)
432
- server.set_injected(injected=self.injectables)
424
+ server.set_dependencies(dependencies=self.dependencies)
433
425
  server.set_before_hooks(hooks=self.middleware_before_request)
434
426
  server.set_after_hooks(hooks=self.middleware_after_request)
435
427
  server.set_response_headers(headers=self.response_headers)
436
- server.set_auto_compression(enabled=self.auto_compression)
437
- server.set_mem_pool_capacity(min_capacity=self.args.min_capacity, max_capacity=self.args.max_capacity)
438
428
 
439
429
  if self.database_config:
440
430
  server.set_database_config(config=self.database_config)
hypern/args_parser.py CHANGED
@@ -49,35 +49,12 @@ class ArgsConfig:
49
49
  action="store_true",
50
50
  help="It restarts the server based on file changes.",
51
51
  )
52
-
53
- parser.add_argument(
54
- "--auto-compression",
55
- action="store_true",
56
- help="It compresses the response automatically.",
57
- )
58
-
59
52
  parser.add_argument(
60
53
  "--auto-workers",
61
54
  action="store_true",
62
55
  help="It sets the number of workers and max-blocking-threads automatically.",
63
56
  )
64
57
 
65
- parser.add_argument(
66
- "--min-capacity",
67
- type=int,
68
- default=1,
69
- required=False,
70
- help="Choose the minimum memory pool capacity. [Default: 1]",
71
- )
72
-
73
- parser.add_argument(
74
- "--max-capacity",
75
- type=int,
76
- default=100,
77
- required=False,
78
- help="Choose the maximum memory pool capacity. [Default: 100]",
79
- )
80
-
81
58
  args, _ = parser.parse_known_args()
82
59
 
83
60
  self.host = args.host or "127.0.0.1"
@@ -86,7 +63,4 @@ class ArgsConfig:
86
63
  self.processes = args.processes or 1
87
64
  self.workers = args.workers or 1
88
65
  self.reload = args.reload or False
89
- self.auto_compression = args.auto_compression
90
66
  self.auto_workers = args.auto_workers
91
- self.min_capacity = args.min_capacity
92
- self.max_capacity = args.max_capacity
hypern/datastructures.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from typing import Optional
2
2
  from enum import Enum
3
- from pydantic import BaseModel, AnyUrl, EmailStr
3
+ from pydantic import BaseModel, AnyUrl
4
4
 
5
5
 
6
6
  class BaseModelWithConfig(BaseModel):
@@ -10,7 +10,7 @@ class BaseModelWithConfig(BaseModel):
10
10
  class Contact(BaseModelWithConfig):
11
11
  name: Optional[str] = None
12
12
  url: Optional[AnyUrl] = None
13
- email: Optional[EmailStr] = None
13
+ email: Optional[str] = None
14
14
 
15
15
 
16
16
  class License(BaseModelWithConfig):
Binary file
hypern/hypern.pyi CHANGED
@@ -181,16 +181,13 @@ class Server:
181
181
  def set_router(self, router: Router) -> None: ...
182
182
  def set_websocket_router(self, websocket_router: WebsocketRouter) -> None: ...
183
183
  def start(self, socket: SocketHeld, worker: int, max_blocking_threads: int) -> None: ...
184
- def inject(self, key: str, value: Any) -> None: ...
185
- def set_injected(self, injected: Dict[str, Any]) -> None: ...
186
184
  def set_before_hooks(self, hooks: List[FunctionInfo]) -> None: ...
187
185
  def set_after_hooks(self, hooks: List[FunctionInfo]) -> None: ...
188
186
  def set_response_headers(self, headers: Dict[str, str]) -> None: ...
189
187
  def set_startup_handler(self, on_startup: FunctionInfo) -> None: ...
190
188
  def set_shutdown_handler(self, on_shutdown: FunctionInfo) -> None: ...
191
- def set_auto_compression(self, enabled: bool) -> None: ...
192
189
  def set_database_config(self, config: DatabaseConfig) -> None: ...
193
- def set_mem_pool_capacity(self, min_capacity: int, max_capacity: int) -> None: ...
190
+ def set_dependencies(self, dependencies: Dict[str, Any]) -> None: ...
194
191
 
195
192
  class Route:
196
193
  path: str
@@ -278,7 +275,7 @@ class UploadedFile:
278
275
  path: str
279
276
  size: int
280
277
  content: bytes
281
- filename: str
278
+ file_name: str
282
279
 
283
280
  @dataclass
284
281
  class BodyData:
hypern/worker.py CHANGED
@@ -1,30 +1,274 @@
1
- # -*- coding: utf-8 -*-
2
- from typing import Any
1
+ import asyncio
2
+ import logging
3
+ import os
4
+ import time
5
+ import traceback
6
+ from concurrent.futures import ThreadPoolExecutor
7
+ from functools import partial, wraps
8
+ from typing import Callable, Dict, List
9
+
3
10
  from celery import Celery
4
- from asgiref.sync import async_to_sync
11
+ from celery.result import AsyncResult
12
+ from celery.signals import (
13
+ after_setup_logger,
14
+ after_setup_task_logger,
15
+ task_failure,
16
+ task_postrun,
17
+ task_prerun,
18
+ worker_ready,
19
+ worker_shutdown,
20
+ )
21
+ from kombu import Exchange, Queue
22
+
23
+
24
+ class Worker(Celery):
25
+ def __init__(
26
+ self,
27
+ main: str = None,
28
+ broker_url: str = None,
29
+ result_backend: str = "rpc://",
30
+ queues: Dict[str, Dict] = None,
31
+ task_routes: Dict[str, str] = None,
32
+ imports: List[str] = None,
33
+ **kwargs,
34
+ ):
35
+ super().__init__(main, **kwargs)
36
+
37
+ self._executor = ThreadPoolExecutor()
38
+ self._task_timings = {}
39
+
40
+ self.default_exchange = Exchange("default", type="direct")
41
+ self.priority_exchange = Exchange("priority", type="direct")
42
+
43
+ default_queues = {
44
+ "default": {"exchange": self.default_exchange, "routing_key": "default"},
45
+ "high_priority": {"exchange": self.priority_exchange, "routing_key": "high"},
46
+ "low_priority": {"exchange": self.priority_exchange, "routing_key": "low"},
47
+ }
48
+ if queues:
49
+ default_queues.update(queues)
50
+
51
+ self._queues = {
52
+ name: Queue(
53
+ name,
54
+ exchange=config.get("exchange", self.default_exchange),
55
+ routing_key=config.get("routing_key", name),
56
+ queue_arguments=config.get("arguments", {}),
57
+ )
58
+ for name, config in default_queues.items()
59
+ }
60
+
61
+ self.conf.update(
62
+ broker_url=broker_url,
63
+ result_backend=result_backend,
64
+ # Worker Pool Configuration
65
+ worker_pool="solo",
66
+ worker_pool_restarts=True,
67
+ broker_connection_retry_on_startup=True,
68
+ # Worker Configuration
69
+ worker_prefetch_multiplier=1,
70
+ worker_max_tasks_per_child=1000,
71
+ worker_concurrency=os.cpu_count(),
72
+ # Task Settings
73
+ task_acks_late=True,
74
+ task_reject_on_worker_lost=True,
75
+ task_time_limit=3600,
76
+ task_soft_time_limit=3000,
77
+ task_default_retry_delay=300,
78
+ task_max_retries=3,
79
+ # Memory Management
80
+ worker_max_memory_per_child=200000, # 200MB
81
+ # Task Routing
82
+ task_routes=task_routes,
83
+ task_queues=list(self._queues.values()),
84
+ # Performance Settings
85
+ task_compression="gzip",
86
+ result_compression="gzip",
87
+ task_serializer="json",
88
+ result_serializer="json",
89
+ accept_content=["json"],
90
+ imports=imports,
91
+ task_default_exchange=self.default_exchange.name,
92
+ task_default_routing_key="default",
93
+ )
94
+
95
+ self._setup_signals()
96
+
97
+ def _setup_signals(self):
98
+ @worker_ready.connect
99
+ def on_worker_ready(sender, **kwargs):
100
+ self.logger.info(f"Worker {sender.hostname} is ready")
101
+
102
+ @worker_shutdown.connect
103
+ def on_worker_shutdown(sender, **kwargs):
104
+ self.logger.info(f"Worker {sender.hostname} is shutting down")
105
+ self._executor.shutdown(wait=True)
106
+
107
+ @task_prerun.connect
108
+ def task_prerun_handler(task_id, task, *args, **kwargs):
109
+ self._task_timings[task_id] = {"start": time.time()}
110
+ self.logger.info(f"Task {task.name}[{task_id}] started")
111
+
112
+ @task_postrun.connect
113
+ def task_postrun_handler(task_id, task, *args, retval=None, **kwargs):
114
+ if task_id in self._task_timings:
115
+ start_time = self._task_timings[task_id]["start"]
116
+ duration = time.time() - start_time
117
+ self.logger.info(f"Task {task.name}[{task_id}] completed in {duration:.2f}s")
118
+ del self._task_timings[task_id]
119
+
120
+ @task_failure.connect
121
+ def task_failure_handler(task_id, exc, task, *args, **kwargs):
122
+ self.logger.error(f"Task {task.name}[{task_id}] failed: {exc}\n{traceback.format_exc()}")
123
+
124
+ @after_setup_logger.connect
125
+ def setup_celery_logger(logger, *args, **kwargs):
126
+ existing_logger = logging.getLogger("hypern")
127
+ logger.handlers = existing_logger.handlers
128
+ logger.filters = existing_logger.filters
129
+ logger.level = existing_logger.level
130
+
131
+ @after_setup_task_logger.connect
132
+ def setup_task_logger(logger, *args, **kwargs):
133
+ existing_logger = logging.getLogger("hypern")
134
+ logger.handlers = existing_logger.handlers
135
+ logger.filters = existing_logger.filters
136
+ logger.level = existing_logger.level
137
+
138
+ def add_task_routes(self, routes: Dict[str, str]) -> None:
139
+ """
140
+ Example:
141
+ app.add_task_routes({
142
+ 'tasks.email.*': 'email_queue',
143
+ 'tasks.payment.process': 'payment_queue',
144
+ 'tasks.high_priority.*': 'high_priority'
145
+ })
146
+ """
147
+ for task_pattern, queue in routes.items():
148
+ self.add_task_route(task_pattern, queue)
149
+
150
+ def add_task_route(self, task_pattern: str, queue: str) -> None:
151
+ """
152
+ Add a task route to the Celery app
153
+
154
+ Example:
155
+ app.add_task_route('tasks.email.send', 'email_queue')
156
+ app.add_task_route('tasks.payment.*', 'payment_queue')
157
+ """
158
+ if queue not in self._queues:
159
+ raise ValueError(f"Queue '{queue}' does not exist. Create it first using create_queue()")
160
+
161
+ self._task_route_mapping[task_pattern] = queue
162
+
163
+ # Update Celery task routes
164
+ routes = self.conf.task_routes or {}
165
+ routes[task_pattern] = {"queue": queue}
166
+ self.conf.task_routes = routes
167
+
168
+ self.logger.info(f"Added route: {task_pattern} -> {queue}")
169
+
170
+ def task(self, *args, **opts):
171
+ """
172
+ Decorator modified to support sync and async functions
173
+ """
174
+ base_task = Celery.task.__get__(self)
175
+
176
+ def decorator(func):
177
+ is_async = asyncio.iscoroutinefunction(func)
178
+
179
+ if is_async:
180
+
181
+ @wraps(func)
182
+ async def async_wrapper(*fargs, **fkwargs):
183
+ return await func(*fargs, **fkwargs)
184
+
185
+ @base_task(*args, **opts)
186
+ def wrapped(*fargs, **fkwargs):
187
+ loop = asyncio.new_event_loop()
188
+ asyncio.set_event_loop(loop)
189
+ try:
190
+ return loop.run_until_complete(async_wrapper(*fargs, **fkwargs))
191
+ finally:
192
+ loop.close()
193
+
194
+ return wrapped
195
+ else:
196
+ return base_task(*args, **opts)(func)
197
+
198
+ return decorator
199
+
200
+ async def async_send_task(self, task_name: str, *args, **kwargs) -> AsyncResult:
201
+ """
202
+ Version of send_task() that is async
203
+ """
204
+ loop = asyncio.get_event_loop()
205
+ return await loop.run_in_executor(self._executor, partial(self.send_task, task_name, args=args, kwargs=kwargs))
206
+
207
+ async def async_result(self, task_id: str) -> Dict:
208
+ """
209
+ Get the result of a task asynchronously
210
+ """
211
+ async_result = self.AsyncResult(task_id)
212
+ loop = asyncio.get_event_loop()
213
+
214
+ result = await loop.run_in_executor(
215
+ self._executor,
216
+ lambda: {
217
+ "task_id": task_id,
218
+ "status": async_result.status,
219
+ "result": async_result.result,
220
+ "traceback": async_result.traceback,
221
+ "date_done": async_result.date_done,
222
+ },
223
+ )
224
+ return result
225
+
226
+ def get_queue_length(self, queue_name: str) -> int:
227
+ """
228
+ Get the number of messages in a queue
229
+ """
230
+ with self.connection_or_acquire() as conn:
231
+ channel = conn.channel()
232
+ queue = Queue(queue_name, channel=channel)
233
+ return queue.queue_declare(passive=True).message_count
5
234
 
235
+ async def chain_tasks(self, tasks: list) -> AsyncResult:
236
+ """
237
+ Function to chain multiple tasks together
238
+ """
239
+ chain = tasks[0]
240
+ for task in tasks[1:]:
241
+ chain = chain | task
242
+ return await self.adelay_task(chain)
6
243
 
7
- class AsyncCelery(Celery):
8
- def __new__(cls, *args, **kwargs) -> Any:
9
- if not hasattr(cls, "instance") or not cls.instance: # type: ignore
10
- cls.instance = super().__new__(cls)
11
- return cls.instance
244
+ def register_task_middleware(self, middleware: Callable):
245
+ """
246
+ Register a middleware function to be called before each task
247
+ """
12
248
 
13
- def __init__(self, *args, **kwargs) -> None:
14
- super().__init__(*args, **kwargs)
15
- self.patch_task()
249
+ def task_middleware(task):
250
+ @wraps(task)
251
+ def _wrapped(*args, **kwargs):
252
+ return middleware(task, *args, **kwargs)
16
253
 
17
- def patch_task(self) -> None:
18
- TaskBase = self.Task
254
+ return _wrapped
19
255
 
20
- class ContextTask(TaskBase): # type: ignore
21
- abstract = True
256
+ self.task = task_middleware(self.task)
22
257
 
23
- def _run(self, *args, **kwargs):
24
- result = async_to_sync(TaskBase.__call__)(self, *args, **kwargs)
25
- return result
258
+ def monitor_task(self, task_id: str) -> dict:
259
+ """
260
+ Get monitoring data for a task
261
+ """
262
+ result = self.AsyncResult(task_id)
263
+ timing_info = self._task_timings.get(task_id, {})
26
264
 
27
- def __call__(self, *args, **kwargs):
28
- return self._run(*args, **kwargs)
265
+ monitoring_data = {
266
+ "task_id": task_id,
267
+ "status": result.status,
268
+ "start_time": timing_info.get("start"),
269
+ "duration": time.time() - timing_info["start"] if timing_info.get("start") else None,
270
+ "result": result.result if result.ready() else None,
271
+ "traceback": result.traceback,
272
+ }
29
273
 
30
- self.Task = ContextTask
274
+ return monitoring_data
@@ -1,11 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hypern
3
- Version: 0.3.7
3
+ Version: 0.3.8
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
7
7
  Requires-Dist: sqlalchemy[asyncio] ==2.0.31
8
- Requires-Dist: pydantic[email] ==2.8.2
9
8
  Requires-Dist: passlib ==1.7.4
10
9
  Requires-Dist: pyjwt ==2.8.0
11
10
  Requires-Dist: pydash ==8.0.3
@@ -38,7 +37,7 @@ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
38
37
 
39
38
  Hypern: A Versatile Python and Rust Framework
40
39
 
41
- Hypern is a flexible, open-source framework built on the [Axum](https://github.com/tokio-rs/axum), designed to jumpstart your high-performance web development endeavors. By providing a pre-configured structure and essential components, Hypern empowers you to rapidly develop custom web applications that leverage the combined power of Python and Rust.
40
+ Hypern is a flexible, open-source framework built on the [Rust](https://github.com/rust-lang/rust), designed to jumpstart your high-performance web development endeavors. By providing a pre-configured structure and essential components, Hypern empowers you to rapidly develop custom web applications that leverage the combined power of Python and Rust.
42
41
 
43
42
  With Hypern, you can seamlessly integrate asynchronous features and build scalable solutions for RESTful APIs and dynamic web applications. Its intuitive design and robust tooling allow developers to focus on creating high-quality code while maximizing performance. Embrace the synergy of Python and Rust to elevate your web development experience.
44
43
 
@@ -92,7 +91,7 @@ routing = [
92
91
  app = Hypern(routing)
93
92
 
94
93
  if __name__ == "__main__":
95
- app.start(host='localhost', port=5005)
94
+ app.start()
96
95
  ```
97
96
 
98
97
  ```
@@ -100,6 +99,16 @@ $ python3 main.py
100
99
  ```
101
100
  You can open swagger UI at path `/docs`
102
101
 
102
+ ## CLI
103
+
104
+ - host (str): The host address to bind to. Defaults to '127.0.0.1'.
105
+ - port (int): The port number to bind to. Defaults to 5000.
106
+ - processes (int): The number of processes to use. Defaults to 1.
107
+ - workers (int): The number of worker threads to use. Defaults to 1.
108
+ - max_blocking_threads (int): The maximum number of blocking threads. Defaults to 32.
109
+ - reload (bool): If True, the server will restart on file changes.
110
+ - auto_workers (bool): If True, sets the number of workers and max-blocking-threads automatically.
111
+
103
112
 
104
113
  ## 💡 Features
105
114
 
@@ -107,7 +116,7 @@ You can open swagger UI at path `/docs`
107
116
  - Rust-powered core with Python flexibility
108
117
  - Multi-process architecture for optimal CPU utilization
109
118
  - Async/await support for non-blocking operations
110
- - Built on top of production-ready Axum web framework
119
+ - Built on top of production-ready Rust language
111
120
 
112
121
  ### 🛠 Development Experience
113
122
  - Type hints and IDE support
@@ -118,7 +127,7 @@ You can open swagger UI at path `/docs`
118
127
  ### 🔌 Integration & Extensions
119
128
  - Easy dependency injection
120
129
  - Middleware support (before/after request hooks)
121
- - WebSocket support (Comming soon)
130
+ - WebSocket support
122
131
  - Background task scheduling
123
132
  - File upload handling
124
133
 
@@ -1,8 +1,8 @@
1
- hypern-0.3.7.dist-info/METADATA,sha256=Sxz9aJX0DPkYH0LaD6PqhN6FWpAd2nVrrm1Iu848bp8,3879
2
- hypern-0.3.7.dist-info/WHEEL,sha256=HVA0wOUnIw3WSu8DET4aOHFt1dH_siSsnV6db_YgIxE,92
3
- hypern-0.3.7.dist-info/licenses/LICENSE,sha256=qbYKAIJLS6jYg5hYncKE7OtWmqOtpVTvKNkwOa0Iwwg,1328
4
- hypern/application.py,sha256=DCYFtU8e8NhQtmfaXbUfOxR2_Y3fEn-pzce9OOs6S4U,18396
5
- hypern/args_parser.py,sha256=zTfLfBoKBvYWxdPjabTfZsCtYF3La3PT0TD8dfLMeM4,2815
1
+ hypern-0.3.8.dist-info/METADATA,sha256=0bMLw-pA0VeoGBbQxXr4cqCO8dS6esga5NjluEeV5MY,4356
2
+ hypern-0.3.8.dist-info/WHEEL,sha256=XP_v6cPyiD7wlS03U072x6RNAGBEEICE5-GLPV2ppFI,92
3
+ hypern-0.3.8.dist-info/licenses/LICENSE,sha256=qbYKAIJLS6jYg5hYncKE7OtWmqOtpVTvKNkwOa0Iwwg,1328
4
+ hypern/application.py,sha256=07QGDd3w7tQRL8njfbNVinG6l8W7O0V-rN_SkO5O3B4,18002
5
+ hypern/args_parser.py,sha256=BjGCooHdZjOpyN-AGL9PCKCKdzROVThE3dzQgC97rng,2035
6
6
  hypern/auth/authorization.py,sha256=-NprZsI0np889ZN1fp-MiVFrPoMNzUtatBJaCMtkllM,32
7
7
  hypern/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  hypern/background.py,sha256=xy38nQZSJsYFRXr3-uFJeNW9E1GiXXOC7lSe5pC0eyE,124
@@ -37,7 +37,7 @@ hypern/database/sql/model.py,sha256=C8_rJA1Adw1yPWthjmAGh26hjTBuwwlEdtH45ADxvL0,
37
37
  hypern/database/sql/query.py,sha256=En19t27zt6iUDQbFgO_wLEWPQCkPeBuH3s37fzlhMVc,33345
38
38
  hypern/database/sql/__init__.py,sha256=dbSAz2nP0DPKK4Bb_jJdObSaSYQfgZ8D4U1TJdc4e7c,645
39
39
  hypern/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
- hypern/datastructures.py,sha256=zZGGSP07kPc9KJDf11hX5uYhAyRE-Ck5wezW5QtOVXw,897
40
+ hypern/datastructures.py,sha256=Pxr9KsZZTFfp0KC1-A4v5AkQfmrUyvVwxKuToQUOLoE,882
41
41
  hypern/enum.py,sha256=KcVziJj7vWvyie0r2rtxhrLzdtkZAsf0DY58oJ4tQl4,360
42
42
  hypern/exceptions/base.py,sha256=5AgfyEea79JjKk5MeAIJ-wy44FG5XEU0Jn3KXKScPiI,2017
43
43
  hypern/exceptions/common.py,sha256=0E8wHRRTWjYOmtOCkTDvZ5NMwL6vRW6aiDD9X1eYA30,227
@@ -50,7 +50,7 @@ hypern/gateway/gateway.py,sha256=26K2qvJUR-0JnN4IlhwvSSt7EYcpYrBVDuzZ1ivQQ34,147
50
50
  hypern/gateway/proxy.py,sha256=w1wcTplDnVrfjn7hb0M0yBVth5TGl88irF-MUYHysQQ,2463
51
51
  hypern/gateway/service.py,sha256=PkRaM08olqM_j_4wRjEJCR8X8ZysAF2WOcfhWjaX2eo,1701
52
52
  hypern/gateway/__init__.py,sha256=TpFWtqnJerW1-jCWq5fjypJcw9Y6ytyrkvkzby1Eg0E,235
53
- hypern/hypern.pyi,sha256=f0kHWHI4creyAezdPlr-HOX87xqpCyYpu6cFGpbFCe4,9210
53
+ hypern/hypern.pyi,sha256=Urc3uHhPupsN-RRYluyWiw8B_xYWzE91Og3Zft40NgU,9010
54
54
  hypern/i18n/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
55
  hypern/logging/logger.py,sha256=WACam_IJiCMXX0hGVKMGSxUQpY4DgAXy7M1dD3q-Z9s,3256
56
56
  hypern/logging/__init__.py,sha256=6eVriyncsJ4J73fGYhoejv9MX7aGTkRezTpPxO4DX1I,52
@@ -78,13 +78,12 @@ hypern/routing/route.py,sha256=kan47-UeL-OPwcpp0rEhmBaaum6hN7FUj13Y8pZDEYA,10256
78
78
  hypern/routing/__init__.py,sha256=U4xW5fDRsn03z4cVLT4dJHHGGU6SVxyv2DL86LXodeE,162
79
79
  hypern/scheduler.py,sha256=-k3tW2AGCnHYSthKXk-FOs_SCtWp3yIxQzwzUJMJsbo,67
80
80
  hypern/security.py,sha256=3E86Yp_eOSVa1emUvBrDgoF0Sn6eNX0CfLnt87w5CPI,1773
81
- hypern/worker.py,sha256=WQrhY_awR6zjMwY4Q7izXi4E4fFrDqt7jIblUW8Bzcg,924
81
+ hypern/worker.py,sha256=ksJW8jWQg3HbIYnIZ5qdAmO-yh5hLpwvTT3dKkHR4Eo,9761
82
82
  hypern/ws/channel.py,sha256=0ns2qmeoFJOpGLXS_hqldhywDQm_DxHwj6KloQx4Q3I,3183
83
83
  hypern/ws/heartbeat.py,sha256=sWMXzQm6cbDHHA2NHc-gFjv7G_E56XtxswHQ93_BueM,2861
84
84
  hypern/ws/room.py,sha256=0_L6Nun0n007F0rfNY8yX5x_A8EuXuI67JqpMkJ4RNI,2598
85
85
  hypern/ws/route.py,sha256=fGQ2RC708MPOiiIHPUo8aZ-oK379TTAyQYm4htNA5jM,803
86
86
  hypern/ws/__init__.py,sha256=dhRoRY683_rfPfSPM5qUczfTuyYDeuLOCFxY4hIdKt8,131
87
- hypern/ws.py,sha256=F6SA2Z1KVnqTEX8ssvOXqCtudUS4eo30JsiIsvfbHnE,394
88
- hypern/__init__.py,sha256=9Ww_aUQ0vJls0tOq7Yw1_TVOCRsa5bHJ-RtnSeComwk,119
89
- hypern/hypern.cp310-win32.pyd,sha256=wT6oVemqaafBCSwbuTmh-lBTrPH1Hqk89MCgPDFTogw,9790976
90
- hypern-0.3.7.dist-info/RECORD,,
87
+ hypern/__init__.py,sha256=p3AtJQbsPs1RYEiN1thxH-k5UP8FfLeiJSoP0Vt3MDg,639
88
+ hypern/hypern.cp310-win32.pyd,sha256=kqmyHdU5z2fDpxju2DwEyb_JEp7Wvz3o6e4XS_3QzvA,7576064
89
+ hypern-0.3.8.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: maturin (1.7.8)
2
+ Generator: maturin (1.8.1)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp310-cp310-win32
hypern/ws.py DELETED
@@ -1,16 +0,0 @@
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"]