hammad-python 0.0.30__py3-none-any.whl → 0.0.31__py3-none-any.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.
Files changed (137) hide show
  1. ham/__init__.py +10 -0
  2. {hammad_python-0.0.30.dist-info → hammad_python-0.0.31.dist-info}/METADATA +6 -32
  3. hammad_python-0.0.31.dist-info/RECORD +6 -0
  4. hammad/__init__.py +0 -84
  5. hammad/_internal.py +0 -256
  6. hammad/_main.py +0 -226
  7. hammad/cache/__init__.py +0 -40
  8. hammad/cache/base_cache.py +0 -181
  9. hammad/cache/cache.py +0 -169
  10. hammad/cache/decorators.py +0 -261
  11. hammad/cache/file_cache.py +0 -80
  12. hammad/cache/ttl_cache.py +0 -74
  13. hammad/cli/__init__.py +0 -33
  14. hammad/cli/animations.py +0 -573
  15. hammad/cli/plugins.py +0 -867
  16. hammad/cli/styles/__init__.py +0 -55
  17. hammad/cli/styles/settings.py +0 -139
  18. hammad/cli/styles/types.py +0 -358
  19. hammad/cli/styles/utils.py +0 -634
  20. hammad/data/__init__.py +0 -90
  21. hammad/data/collections/__init__.py +0 -49
  22. hammad/data/collections/collection.py +0 -326
  23. hammad/data/collections/indexes/__init__.py +0 -37
  24. hammad/data/collections/indexes/qdrant/__init__.py +0 -1
  25. hammad/data/collections/indexes/qdrant/index.py +0 -723
  26. hammad/data/collections/indexes/qdrant/settings.py +0 -94
  27. hammad/data/collections/indexes/qdrant/utils.py +0 -210
  28. hammad/data/collections/indexes/tantivy/__init__.py +0 -1
  29. hammad/data/collections/indexes/tantivy/index.py +0 -426
  30. hammad/data/collections/indexes/tantivy/settings.py +0 -40
  31. hammad/data/collections/indexes/tantivy/utils.py +0 -176
  32. hammad/data/configurations/__init__.py +0 -35
  33. hammad/data/configurations/configuration.py +0 -564
  34. hammad/data/models/__init__.py +0 -50
  35. hammad/data/models/extensions/__init__.py +0 -4
  36. hammad/data/models/extensions/pydantic/__init__.py +0 -42
  37. hammad/data/models/extensions/pydantic/converters.py +0 -759
  38. hammad/data/models/fields.py +0 -546
  39. hammad/data/models/model.py +0 -1078
  40. hammad/data/models/utils.py +0 -280
  41. hammad/data/sql/__init__.py +0 -24
  42. hammad/data/sql/database.py +0 -576
  43. hammad/data/sql/types.py +0 -127
  44. hammad/data/types/__init__.py +0 -75
  45. hammad/data/types/file.py +0 -431
  46. hammad/data/types/multimodal/__init__.py +0 -36
  47. hammad/data/types/multimodal/audio.py +0 -200
  48. hammad/data/types/multimodal/image.py +0 -182
  49. hammad/data/types/text.py +0 -1308
  50. hammad/formatting/__init__.py +0 -33
  51. hammad/formatting/json/__init__.py +0 -27
  52. hammad/formatting/json/converters.py +0 -158
  53. hammad/formatting/text/__init__.py +0 -63
  54. hammad/formatting/text/converters.py +0 -723
  55. hammad/formatting/text/markdown.py +0 -131
  56. hammad/formatting/yaml/__init__.py +0 -26
  57. hammad/formatting/yaml/converters.py +0 -5
  58. hammad/genai/__init__.py +0 -217
  59. hammad/genai/a2a/__init__.py +0 -32
  60. hammad/genai/a2a/workers.py +0 -552
  61. hammad/genai/agents/__init__.py +0 -59
  62. hammad/genai/agents/agent.py +0 -1973
  63. hammad/genai/agents/run.py +0 -1024
  64. hammad/genai/agents/types/__init__.py +0 -42
  65. hammad/genai/agents/types/agent_context.py +0 -13
  66. hammad/genai/agents/types/agent_event.py +0 -128
  67. hammad/genai/agents/types/agent_hooks.py +0 -220
  68. hammad/genai/agents/types/agent_messages.py +0 -31
  69. hammad/genai/agents/types/agent_response.py +0 -125
  70. hammad/genai/agents/types/agent_stream.py +0 -327
  71. hammad/genai/graphs/__init__.py +0 -125
  72. hammad/genai/graphs/_utils.py +0 -190
  73. hammad/genai/graphs/base.py +0 -1828
  74. hammad/genai/graphs/plugins.py +0 -316
  75. hammad/genai/graphs/types.py +0 -638
  76. hammad/genai/models/__init__.py +0 -1
  77. hammad/genai/models/embeddings/__init__.py +0 -43
  78. hammad/genai/models/embeddings/model.py +0 -226
  79. hammad/genai/models/embeddings/run.py +0 -163
  80. hammad/genai/models/embeddings/types/__init__.py +0 -37
  81. hammad/genai/models/embeddings/types/embedding_model_name.py +0 -75
  82. hammad/genai/models/embeddings/types/embedding_model_response.py +0 -76
  83. hammad/genai/models/embeddings/types/embedding_model_run_params.py +0 -66
  84. hammad/genai/models/embeddings/types/embedding_model_settings.py +0 -47
  85. hammad/genai/models/language/__init__.py +0 -57
  86. hammad/genai/models/language/model.py +0 -1098
  87. hammad/genai/models/language/run.py +0 -878
  88. hammad/genai/models/language/types/__init__.py +0 -40
  89. hammad/genai/models/language/types/language_model_instructor_mode.py +0 -47
  90. hammad/genai/models/language/types/language_model_messages.py +0 -28
  91. hammad/genai/models/language/types/language_model_name.py +0 -239
  92. hammad/genai/models/language/types/language_model_request.py +0 -127
  93. hammad/genai/models/language/types/language_model_response.py +0 -217
  94. hammad/genai/models/language/types/language_model_response_chunk.py +0 -56
  95. hammad/genai/models/language/types/language_model_settings.py +0 -89
  96. hammad/genai/models/language/types/language_model_stream.py +0 -600
  97. hammad/genai/models/language/utils/__init__.py +0 -28
  98. hammad/genai/models/language/utils/requests.py +0 -421
  99. hammad/genai/models/language/utils/structured_outputs.py +0 -135
  100. hammad/genai/models/model_provider.py +0 -4
  101. hammad/genai/models/multimodal.py +0 -47
  102. hammad/genai/models/reranking.py +0 -26
  103. hammad/genai/types/__init__.py +0 -1
  104. hammad/genai/types/base.py +0 -215
  105. hammad/genai/types/history.py +0 -290
  106. hammad/genai/types/tools.py +0 -507
  107. hammad/logging/__init__.py +0 -35
  108. hammad/logging/decorators.py +0 -834
  109. hammad/logging/logger.py +0 -1018
  110. hammad/mcp/__init__.py +0 -53
  111. hammad/mcp/client/__init__.py +0 -35
  112. hammad/mcp/client/client.py +0 -624
  113. hammad/mcp/client/client_service.py +0 -400
  114. hammad/mcp/client/settings.py +0 -178
  115. hammad/mcp/servers/__init__.py +0 -26
  116. hammad/mcp/servers/launcher.py +0 -1161
  117. hammad/runtime/__init__.py +0 -32
  118. hammad/runtime/decorators.py +0 -142
  119. hammad/runtime/run.py +0 -299
  120. hammad/service/__init__.py +0 -49
  121. hammad/service/create.py +0 -527
  122. hammad/service/decorators.py +0 -283
  123. hammad/types.py +0 -288
  124. hammad/typing/__init__.py +0 -435
  125. hammad/web/__init__.py +0 -43
  126. hammad/web/http/__init__.py +0 -1
  127. hammad/web/http/client.py +0 -944
  128. hammad/web/models.py +0 -275
  129. hammad/web/openapi/__init__.py +0 -1
  130. hammad/web/openapi/client.py +0 -740
  131. hammad/web/search/__init__.py +0 -1
  132. hammad/web/search/client.py +0 -1023
  133. hammad/web/utils.py +0 -472
  134. hammad_python-0.0.30.dist-info/RECORD +0 -135
  135. {hammad → ham}/py.typed +0 -0
  136. {hammad_python-0.0.30.dist-info → hammad_python-0.0.31.dist-info}/WHEEL +0 -0
  137. {hammad_python-0.0.30.dist-info → hammad_python-0.0.31.dist-info}/licenses/LICENSE +0 -0
hammad/service/create.py DELETED
@@ -1,527 +0,0 @@
1
- """hammad.service.create
2
-
3
- Service creation utilities for launching FastAPI servers from various Python objects.
4
- """
5
-
6
- import inspect
7
- import signal
8
- import atexit
9
- from typing import (
10
- Any,
11
- Callable,
12
- Dict,
13
- List,
14
- Literal,
15
- Optional,
16
- Type,
17
- Union,
18
- get_type_hints,
19
- )
20
- from dataclasses import dataclass, fields, is_dataclass, MISSING
21
- from enum import Enum
22
-
23
- try:
24
- from fastapi import FastAPI, HTTPException
25
- from pydantic import BaseModel, create_model
26
- from uvicorn import Config, Server
27
- except ImportError as e:
28
- raise ImportError(
29
- "Service dependencies not installed. Install with: pip install hammad-python[serve]"
30
- ) from e
31
-
32
- import logging
33
-
34
- logger = logging.getLogger(__name__)
35
-
36
-
37
- class ServiceStatus(str, Enum):
38
- """Service status enumeration."""
39
-
40
- STARTING = "starting"
41
- RUNNING = "running"
42
- STOPPING = "stopping"
43
- STOPPED = "stopped"
44
- ERROR = "error"
45
-
46
-
47
- @dataclass
48
- class ServiceConfig:
49
- """Configuration for service creation."""
50
-
51
- host: str = "0.0.0.0"
52
- port: int = 8000
53
- log_level: str = "info"
54
- reload: bool = False
55
- workers: int = 1
56
- timeout_keep_alive: int = 5
57
- timeout_graceful_shutdown: int = 30
58
- access_log: bool = True
59
- use_colors: bool = True
60
- loop: str = "asyncio"
61
-
62
-
63
- class ServiceManager:
64
- """Manages service lifecycle including graceful shutdown."""
65
-
66
- def __init__(self):
67
- self.servers: List[Server] = []
68
- self.status = ServiceStatus.STOPPED
69
- self._shutdown_handlers_registered = False
70
-
71
- def register_shutdown_handlers(self):
72
- """Register signal handlers for graceful shutdown."""
73
- if self._shutdown_handlers_registered:
74
- return
75
-
76
- def signal_handler(signum, _):
77
- logger.info(f"Received signal {signum}. Shutting down services...")
78
- self.shutdown_all()
79
-
80
- signal.signal(signal.SIGTERM, signal_handler)
81
- signal.signal(signal.SIGINT, signal_handler)
82
- atexit.register(self.shutdown_all)
83
- self._shutdown_handlers_registered = True
84
-
85
- def add_server(self, server: Server):
86
- """Add a server to be managed."""
87
- self.servers.append(server)
88
- self.register_shutdown_handlers()
89
-
90
- def shutdown_all(self):
91
- """Shutdown all managed servers."""
92
- if self.status == ServiceStatus.STOPPING:
93
- return
94
-
95
- self.status = ServiceStatus.STOPPING
96
- logger.info(f"Shutting down {len(self.servers)} service(s)...")
97
-
98
- for server in self.servers:
99
- try:
100
- if server.should_exit:
101
- continue
102
- server.should_exit = True
103
- logger.info("Service shutdown initiated")
104
- except Exception as e:
105
- logger.error(f"Error shutting down server: {e}")
106
-
107
- self.status = ServiceStatus.STOPPED
108
- logger.info("All services shut down")
109
-
110
-
111
- # Global service manager
112
- _service_manager = ServiceManager()
113
-
114
-
115
- def _python_type_to_openapi_type(python_type: Type) -> str:
116
- """Convert Python type to OpenAPI type string."""
117
- type_mapping = {
118
- str: "string",
119
- int: "integer",
120
- float: "number",
121
- bool: "boolean",
122
- list: "array",
123
- dict: "object",
124
- }
125
-
126
- # Handle Union types (Optional)
127
- if hasattr(python_type, "__origin__"):
128
- if python_type.__origin__ is Union:
129
- # For Optional[T], use the non-None type
130
- non_none_types = [t for t in python_type.__args__ if t != type(None)]
131
- if non_none_types:
132
- return _python_type_to_openapi_type(non_none_types[0])
133
- elif python_type.__origin__ is list:
134
- return "array"
135
- elif python_type.__origin__ is dict:
136
- return "object"
137
-
138
- return type_mapping.get(python_type, "string")
139
-
140
-
141
- def _create_pydantic_model_from_function(func: Callable) -> Type[BaseModel]:
142
- """Create a Pydantic model from function signature."""
143
- sig = inspect.signature(func)
144
- type_hints = get_type_hints(func)
145
-
146
- fields_dict = {}
147
- for param_name, param in sig.parameters.items():
148
- if param_name == "self":
149
- continue
150
-
151
- param_type = type_hints.get(param_name, str)
152
- default_value = (
153
- ... if param.default == inspect.Parameter.empty else param.default
154
- )
155
-
156
- fields_dict[param_name] = (param_type, default_value)
157
-
158
- return create_model(f"{func.__name__}Model", **fields_dict)
159
-
160
-
161
- def _create_fastapi_from_function(
162
- func: Callable,
163
- *,
164
- name: Optional[str] = None,
165
- method: Literal[
166
- "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"
167
- ] = "POST",
168
- path: str = "/",
169
- include_in_schema: bool = True,
170
- dependencies: Optional[List[Callable[..., Any]]] = None,
171
- tags: Optional[List[str]] = None,
172
- description: Optional[str] = None,
173
- ) -> FastAPI:
174
- """Create a FastAPI app from a function."""
175
- app_name = name or func.__name__
176
- app = FastAPI(
177
- title=app_name,
178
- description=description or f"Auto-generated API for {func.__name__}",
179
- )
180
-
181
- # Create request model for POST/PUT/PATCH methods
182
- if method in ["POST", "PUT", "PATCH"]:
183
- request_model = _create_pydantic_model_from_function(func)
184
-
185
- async def endpoint(request: request_model): # type: ignore
186
- try:
187
- # Convert request to dict and call function
188
- kwargs = request.model_dump()
189
- result = func(**kwargs)
190
- return {"result": result}
191
- except Exception as e:
192
- logger.error(f"Error in {func.__name__}: {e}")
193
- raise HTTPException(status_code=500, detail=str(e))
194
-
195
- app.add_api_route(
196
- path,
197
- endpoint,
198
- methods=[method],
199
- include_in_schema=include_in_schema,
200
- dependencies=dependencies,
201
- tags=tags,
202
- )
203
- else:
204
- # For GET and other methods, use query parameters
205
- sig = inspect.signature(func)
206
-
207
- async def endpoint(**kwargs):
208
- try:
209
- # Filter kwargs to only include function parameters
210
- func_kwargs = {
211
- key: value for key, value in kwargs.items() if key in sig.parameters
212
- }
213
- result = func(**func_kwargs)
214
- return {"result": result}
215
- except Exception as e:
216
- logger.error(f"Error in {func.__name__}: {e}")
217
- raise HTTPException(status_code=500, detail=str(e))
218
-
219
- # Dynamically set the endpoint signature to match the function
220
- endpoint.__signature__ = sig
221
-
222
- app.add_api_route(
223
- path,
224
- endpoint,
225
- methods=[method],
226
- include_in_schema=include_in_schema,
227
- dependencies=dependencies,
228
- tags=tags,
229
- )
230
-
231
- return app
232
-
233
-
234
- def _create_fastapi_from_model(
235
- model: Union[Type[BaseModel], Type, Any],
236
- *,
237
- name: Optional[str] = None,
238
- methods: List[Literal["GET", "POST", "PUT", "DELETE"]] = None,
239
- path: str = "/",
240
- include_in_schema: bool = True,
241
- dependencies: Optional[List[Callable[..., Any]]] = None,
242
- tags: Optional[List[str]] = None,
243
- description: Optional[str] = None,
244
- ) -> FastAPI:
245
- """Create a FastAPI app from a model (Pydantic, dataclass, etc.)."""
246
- if methods is None:
247
- methods = ["GET", "POST"]
248
-
249
- app_name = name or getattr(model, "__name__", "ModelService")
250
- app = FastAPI(
251
- title=app_name,
252
- description=description or f"Auto-generated API for {app_name}",
253
- )
254
-
255
- # Convert model to Pydantic if needed
256
- if is_dataclass(model) and not issubclass(model, BaseModel):
257
- # Convert dataclass to Pydantic model
258
- field_definitions = {}
259
- for field in fields(model):
260
- field_definitions[field.name] = (
261
- field.type,
262
- field.default if field.default != MISSING else ...,
263
- )
264
- pydantic_model = create_model(f"{model.__name__}Model", **field_definitions)
265
- elif inspect.isclass(model) and issubclass(model, BaseModel):
266
- pydantic_model = model
267
- else:
268
- # For other types, create a simple wrapper
269
- pydantic_model = create_model(f"{app_name}Model", value=(str, ...))
270
-
271
- # Store for the service
272
- items: Dict[str, Any] = {}
273
-
274
- if "GET" in methods:
275
-
276
- @app.get(path, response_model=Dict[str, Any])
277
- async def get_items():
278
- return {"items": list(items.values())}
279
-
280
- @app.get(f"{path}/{{item_id}}", response_model=pydantic_model)
281
- async def get_item(item_id: str):
282
- if item_id not in items:
283
- raise HTTPException(status_code=404, detail="Item not found")
284
- return items[item_id]
285
-
286
- if "POST" in methods:
287
-
288
- @app.post(path, response_model=Dict[str, Any])
289
- async def create_item(item: pydantic_model): # type: ignore
290
- item_id = str(len(items))
291
- items[item_id] = item
292
- return {"id": item_id, "item": item}
293
-
294
- if "PUT" in methods:
295
-
296
- @app.put(f"{path}/{{item_id}}", response_model=pydantic_model)
297
- async def update_item(item_id: str, item: pydantic_model): # type: ignore
298
- if item_id not in items:
299
- raise HTTPException(status_code=404, detail="Item not found")
300
- items[item_id] = item
301
- return item
302
-
303
- if "DELETE" in methods:
304
-
305
- @app.delete(f"{path}/{{item_id}}")
306
- async def delete_item(item_id: str):
307
- if item_id not in items:
308
- raise HTTPException(status_code=404, detail="Item not found")
309
- del items[item_id]
310
- return {"message": "Item deleted"}
311
-
312
- return app
313
-
314
-
315
- def create_service(
316
- target: Union[Callable, Type[BaseModel], Type, Any],
317
- *,
318
- # Service configuration
319
- config: Optional[ServiceConfig] = None,
320
- host: str = "0.0.0.0",
321
- port: int = 8000,
322
- # Function-specific parameters
323
- name: Optional[str] = None,
324
- method: Literal[
325
- "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"
326
- ] = "POST",
327
- path: str = "/",
328
- # Model-specific parameters
329
- methods: List[Literal["GET", "POST", "PUT", "DELETE"]] = None,
330
- # FastAPI parameters
331
- include_in_schema: bool = True,
332
- dependencies: Optional[List[Callable[..., Any]]] = None,
333
- tags: Optional[List[str]] = None,
334
- description: Optional[str] = None,
335
- # Server parameters
336
- log_level: str = "info",
337
- reload: bool = False,
338
- workers: int = 1,
339
- timeout_keep_alive: int = 5,
340
- access_log: bool = True,
341
- use_colors: bool = True,
342
- auto_start: bool = True,
343
- ) -> Union[FastAPI, Server]:
344
- """
345
- Create a service from a function, Pydantic model, dataclass, or other object.
346
-
347
- Args:
348
- target: The function or model to create a service from
349
- config: ServiceConfig object (overrides individual parameters)
350
- host: Host to bind to
351
- port: Port to bind to
352
- name: Service name (defaults to function/class name)
353
- method: HTTP method for functions (GET, POST, etc.)
354
- path: API path
355
- methods: HTTP methods for models (list of methods)
356
- include_in_schema: Include in OpenAPI schema
357
- dependencies: FastAPI dependencies
358
- tags: API tags
359
- description: API description
360
- log_level: Uvicorn log level
361
- reload: Enable auto-reload
362
- workers: Number of worker processes
363
- timeout_keep_alive: Keep-alive timeout
364
- access_log: Enable access logging
365
- use_colors: Use colored logs
366
- auto_start: Automatically start the server
367
-
368
- Returns:
369
- FastAPI app if auto_start=False, Server instance if auto_start=True
370
- """
371
- # Use config if provided, otherwise use individual parameters
372
- if config:
373
- host = config.host
374
- port = config.port
375
- log_level = config.log_level
376
- reload = config.reload
377
- workers = config.workers
378
- timeout_keep_alive = config.timeout_keep_alive
379
- access_log = config.access_log
380
- use_colors = config.use_colors
381
-
382
- # Determine if target is a function or model-like object
383
- if callable(target) and not inspect.isclass(target):
384
- # It's a function
385
- app = _create_fastapi_from_function(
386
- target,
387
- name=name,
388
- method=method,
389
- path=path,
390
- include_in_schema=include_in_schema,
391
- dependencies=dependencies,
392
- tags=tags,
393
- description=description,
394
- )
395
- else:
396
- # It's a model-like object (class, Pydantic model, dataclass, etc.)
397
- app = _create_fastapi_from_model(
398
- target,
399
- name=name,
400
- methods=methods,
401
- path=path,
402
- include_in_schema=include_in_schema,
403
- dependencies=dependencies,
404
- tags=tags,
405
- description=description,
406
- )
407
-
408
- if not auto_start:
409
- return app
410
-
411
- # Create and configure server
412
- config_obj = Config(
413
- app=app,
414
- host=host,
415
- port=port,
416
- log_level=log_level,
417
- reload=reload,
418
- workers=workers,
419
- timeout_keep_alive=timeout_keep_alive,
420
- access_log=access_log,
421
- use_colors=use_colors,
422
- loop="asyncio",
423
- )
424
-
425
- server = Server(config_obj)
426
- _service_manager.add_server(server)
427
-
428
- logger.info(f"Starting service on {host}:{port}")
429
- _service_manager.status = ServiceStatus.STARTING
430
-
431
- try:
432
- server.run()
433
- _service_manager.status = ServiceStatus.RUNNING
434
- except Exception as e:
435
- _service_manager.status = ServiceStatus.ERROR
436
- logger.error(f"Service failed to start: {e}")
437
- raise
438
-
439
- return server
440
-
441
-
442
- async def async_create_service(
443
- target: Union[Callable, Type[BaseModel], Type, Any],
444
- *,
445
- config: Optional[ServiceConfig] = None,
446
- **kwargs,
447
- ) -> Union[FastAPI, Server]:
448
- """
449
- Async version of create_service.
450
-
451
- Args:
452
- target: The function or model to create a service from
453
- config: ServiceConfig object
454
- **kwargs: Same as create_service
455
-
456
- Returns:
457
- FastAPI app if auto_start=False, Server instance if auto_start=True
458
- """
459
- # Check if auto_start is provided and respect it
460
- auto_start = kwargs.get("auto_start", True)
461
-
462
- # Force auto_start=False to get the app first
463
- kwargs["auto_start"] = False
464
- app = create_service(target, config=config, **kwargs)
465
-
466
- # If auto_start was False, just return the app
467
- if not auto_start:
468
- return app
469
-
470
- # Use config if provided
471
- if config:
472
- host = config.host
473
- port = config.port
474
- log_level = config.log_level
475
- reload = config.reload
476
- workers = config.workers
477
- timeout_keep_alive = config.timeout_keep_alive
478
- access_log = config.access_log
479
- use_colors = config.use_colors
480
- else:
481
- host = kwargs.get("host", "0.0.0.0")
482
- port = kwargs.get("port", 8000)
483
- log_level = kwargs.get("log_level", "info")
484
- reload = kwargs.get("reload", False)
485
- workers = kwargs.get("workers", 1)
486
- timeout_keep_alive = kwargs.get("timeout_keep_alive", 5)
487
- access_log = kwargs.get("access_log", True)
488
- use_colors = kwargs.get("use_colors", True)
489
-
490
- config_obj = Config(
491
- app=app,
492
- host=host,
493
- port=port,
494
- log_level=log_level,
495
- reload=reload,
496
- workers=workers,
497
- timeout_keep_alive=timeout_keep_alive,
498
- access_log=access_log,
499
- use_colors=use_colors,
500
- loop="asyncio",
501
- )
502
-
503
- server = Server(config_obj)
504
- _service_manager.add_server(server)
505
-
506
- logger.info(f"Starting async service on {host}:{port}")
507
- _service_manager.status = ServiceStatus.STARTING
508
-
509
- try:
510
- await server.serve()
511
- _service_manager.status = ServiceStatus.RUNNING
512
- except Exception as e:
513
- _service_manager.status = ServiceStatus.ERROR
514
- logger.error(f"Async service failed to start: {e}")
515
- raise
516
-
517
- return server
518
-
519
-
520
- def shutdown_all_services():
521
- """Shutdown all managed services."""
522
- _service_manager.shutdown_all()
523
-
524
-
525
- def get_service_status() -> ServiceStatus:
526
- """Get the current service status."""
527
- return _service_manager.status