feat: Add CLI for PyServe with configuration options

- Introduced a new CLI module (`cli.py`) to manage server configurations via command line arguments.
- Added script entry point in `pyproject.toml` for easy access to the CLI.
- Enhanced `Config` class to load configurations from a YAML file.
- Updated `__init__.py` to include `__version__` in the module exports.
- Added optional dependencies for development tools in `pyproject.toml`.
- Implemented logging improvements and error handling in various modules.
- Created tests for the CLI functionality to ensure proper behavior.
- Removed the old `run.py` implementation in favor of the new CLI approach.
This commit is contained in:
Илья Глазунов
2025-09-02 00:20:40 +03:00
parent 83cb7d68b0
commit 84cd1c974f
17 changed files with 1016 additions and 232 deletions
+21 -25
View File
@@ -89,8 +89,8 @@ class PyServeServer:
ext_metrics = getattr(extension, 'get_metrics')()
metrics.update(ext_metrics)
except Exception as e:
logger.error(f"Ошибка получения метрик от {type(extension).__name__}: {e}")
logger.error(f"Error getting metrics from {type(extension).__name__}: {e}")
import json
return Response(
json.dumps(metrics, ensure_ascii=False, indent=2),
@@ -105,11 +105,11 @@ class PyServeServer:
return None
if not Path(self.config.ssl.cert_file).exists():
logger.error(f"SSL сертификат не найден: {self.config.ssl.cert_file}")
logger.error(f"SSL certificate not found: {self.config.ssl.cert_file}")
return None
if not Path(self.config.ssl.key_file).exists():
logger.error(f"SSL ключ не найден: {self.config.ssl.key_file}")
logger.error(f"SSL key not found: {self.config.ssl.key_file}")
return None
try:
@@ -118,22 +118,18 @@ class PyServeServer:
self.config.ssl.cert_file,
self.config.ssl.key_file
)
logger.info("SSL контекст создан успешно")
logger.info("SSL context created successfully")
return context
except Exception as e:
logger.error(f"Ошибка создания SSL контекста: {e}")
logger.error(f"Error creating SSL context: {e}")
return None
def run(self) -> None:
"""Запуск сервера"""
if not self.config.validate():
logger.error("Конфигурация невалидна, сервер не может быть запущен")
logger.error("Configuration is invalid, server cannot be started")
return
# Создаем директории если их нет
self._ensure_directories()
# SSL конфигурация
ssl_context = self._create_ssl_context()
uvicorn_config = {
@@ -154,21 +150,21 @@ class PyServeServer:
protocol = "https"
else:
protocol = "http"
logger.info(f"Запуск PyServe сервера на {protocol}://{self.config.server.host}:{self.config.server.port}")
logger.info(f"Starting PyServe server at {protocol}://{self.config.server.host}:{self.config.server.port}")
try:
uvicorn.run(**uvicorn_config)
except KeyboardInterrupt:
logger.info("Получен сигнал остановки")
logger.info("Received shutdown signal")
except Exception as e:
logger.error(f"Ошибка запуска сервера: {e}")
logger.error(f"Error starting server: {e}")
finally:
self.shutdown()
async def run_async(self) -> None:
if not self.config.validate():
logger.error("Конфигурация невалидна, сервер не может быть запущен")
logger.error("Configuration is invalid, server cannot be started")
return
self._ensure_directories()
@@ -201,17 +197,17 @@ class PyServeServer:
for directory in directories:
Path(directory).mkdir(parents=True, exist_ok=True)
logger.debug(f"Создана/проверена директория: {directory}")
logger.debug(f"Created/checked directory: {directory}")
def shutdown(self) -> None:
logger.info("Завершение работы PyServe сервера")
logger.info("Shutting down PyServe server")
self.extension_manager.cleanup()
from .logging_utils import shutdown_logging
shutdown_logging()
logger.info("Сервер остановлен")
logger.info("Server stopped")
def add_extension(self, extension_type: str, config: Dict[str, Any]) -> None:
self.extension_manager.load_extension(extension_type, config)
@@ -224,8 +220,8 @@ class PyServeServer:
ext_metrics = getattr(extension, 'get_metrics')()
metrics.update(ext_metrics)
except Exception as e:
logger.error(f"Ошибка получения метрик от {type(extension).__name__}: {e}")
logger.error(f"Error getting metrics from {type(extension).__name__}: {e}")
return metrics