refactor: Add typing stubs for PyYAML and improve type hints in logging utilities and extensions

This commit is contained in:
Илья Глазунов 2025-09-02 14:33:34 +03:00
parent 6b157d7626
commit 72418f6bdb
6 changed files with 31 additions and 22 deletions

1
.gitignore vendored
View File

@ -9,3 +9,4 @@ logs/*
static/*
.DS_Store

14
poetry.lock generated
View File

@ -653,6 +653,18 @@ typing-extensions = {version = ">=4.10.0", markers = "python_version < \"3.13\""
[package.extras]
full = ["httpx (>=0.27.0,<0.29.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"]
[[package]]
name = "types-pyyaml"
version = "6.0.12.20250822"
description = "Typing stubs for PyYAML"
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "types_pyyaml-6.0.12.20250822-py3-none-any.whl", hash = "sha256:1fe1a5e146aa315483592d292b72a172b65b946a6d98aa6ddd8e4aa838ab7098"},
{file = "types_pyyaml-6.0.12.20250822.tar.gz", hash = "sha256:259f1d93079d335730a9db7cff2bcaf65d7e04b4a56b5927d49a612199b59413"},
]
[[package]]
name = "typing-extensions"
version = "4.15.0"
@ -948,4 +960,4 @@ dev = ["black", "flake8", "isort", "mypy", "pytest", "pytest-cov"]
[metadata]
lock-version = "2.1"
python-versions = ">=3.12"
content-hash = "a69856492efdf3ed2272517f43842f06b7199519b2da459c6aadc863e2429c45"
content-hash = "e145aef2574fcda0c0d45b8620988baf25f386a1b6ccf199c56210cbc0e3aa76"

View File

@ -11,7 +11,8 @@ requires-python = ">=3.12"
dependencies = [
"starlette (>=0.47.3,<0.48.0)",
"uvicorn[standard] (>=0.35.0,<0.36.0)",
"pyyaml (>=6.0,<7.0)"
"pyyaml (>=6.0,<7.0)",
"types-pyyaml (>=6.0.12.20250822,<7.0.0.0)",
]
[project.scripts]

View File

@ -5,7 +5,7 @@ from pathlib import Path
from . import PyServeServer, Config, __version__
def main():
def main() -> None:
parser = argparse.ArgumentParser(
description="PyServe - HTTP web server",
prog="pyserve"

View File

@ -1,5 +1,5 @@
from abc import ABC, abstractmethod
from typing import Dict, Any, List, Optional
from typing import Dict, Any, List, Optional, Type
from starlette.requests import Request
from starlette.responses import Response
from .logging_utils import get_logger
@ -101,7 +101,7 @@ class MonitoringExtension(Extension):
super().__init__(config)
self.request_count = 0
self.error_count = 0
self.response_times = []
self.response_times: list[float] = []
self.enable_metrics = config.get("enable_metrics", True)
async def process_request(self, request: Request) -> Optional[Response]:
@ -138,16 +138,16 @@ class MonitoringExtension(Extension):
class ExtensionManager:
def __init__(self):
def __init__(self) -> None:
self.extensions: List[Extension] = []
self.extension_registry = {
self.extension_registry: Dict[str, Type[Extension]] = {
"routing": RoutingExtension,
"security": SecurityExtension,
"caching": CachingExtension,
"monitoring": MonitoringExtension
}
def register_extension_type(self, name: str, extension_class: type) -> None:
def register_extension_type(self, name: str, extension_class: Type[Extension]) -> None:
self.extension_registry[name] = extension_class
def load_extension(self, extension_type: str, config: Dict[str, Any]) -> None:

View File

@ -1,8 +1,3 @@
"""
Кастомная система логирования для PyServe
Управляет логгерами всех пакетов и модулей, включая uvicorn и starlette
"""
import logging
import logging.handlers
import sys
@ -14,7 +9,7 @@ from . import __version__
class UvicornLogFilter(logging.Filter):
def filter(self, record):
def filter(self, record: logging.LogRecord) -> bool:
if hasattr(record, 'name') and 'uvicorn.access' in record.name:
if hasattr(record, 'getMessage'):
msg = record.getMessage()
@ -41,12 +36,12 @@ class PyServeFormatter(logging.Formatter):
'RESET': '\033[0m' # Reset
}
def __init__(self, use_colors: bool = True, show_module: bool = True, *args, **kwargs):
def __init__(self, use_colors: bool = True, show_module: bool = True, *args: Any, **kwargs: Any):
super().__init__(*args, **kwargs)
self.use_colors = use_colors and hasattr(sys.stderr, 'isatty') and sys.stderr.isatty()
self.show_module = show_module
def format(self, record):
def format(self, record: logging.LogRecord) -> str:
if self.use_colors:
levelname = record.levelname
if levelname in self.COLORS:
@ -69,12 +64,12 @@ class AccessLogHandler(logging.Handler):
super().__init__()
self.access_logger = logging.getLogger(logger_name)
def emit(self, record):
def emit(self, record: logging.LogRecord) -> None:
self.access_logger.handle(record)
class PyServeLogManager:
def __init__(self):
def __init__(self) -> None:
self.configured = False
self.handlers: Dict[str, logging.Handler] = {}
self.loggers: Dict[str, logging.Logger] = {}
@ -138,10 +133,10 @@ class PyServeLogManager:
pyserve_logger.setLevel(getattr(logging, level))
self.loggers['pyserve'] = pyserve_logger
pyserve_logger.info(f"PyServe v{__version__} - Система логирования инициализирована")
pyserve_logger.info(f"Уровень логирования: {level}")
pyserve_logger.info(f"Консольный вывод: {'включен' if console_output else 'отключен'}")
pyserve_logger.info(f"Файл логов: {log_file if log_file else 'отключен'}")
pyserve_logger.info(f"PyServe v{__version__} - Logger initialized")
pyserve_logger.info(f"Logging level: {level}")
pyserve_logger.info(f"Console output: {'enabled' if console_output else 'disabled'}")
pyserve_logger.info(f"Log file: {log_file if log_file else 'disabled'}")
self.configured = True