From 3b59994fc9d45fb334ef80dd4995710798bca467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=BB=D1=8C=D1=8F=20=D0=93=D0=BB=D0=B0=D0=B7=D1=83?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2?= Date: Thu, 4 Dec 2025 03:17:21 +0300 Subject: [PATCH] fixed pyservectl linter errors and formatting --- poetry.lock | 14 +++++++++++++- pyproject.toml | 1 + pyserve/ctl/_daemon.py | 6 ++++-- pyserve/ctl/commands/config.py | 18 +++++++++--------- pyserve/ctl/commands/down.py | 6 +++--- pyserve/ctl/commands/health.py | 4 +++- pyserve/ctl/commands/init.py | 4 ++-- pyserve/ctl/commands/logs.py | 20 ++++++++++---------- pyserve/ctl/commands/scale.py | 5 +++-- pyserve/ctl/commands/service.py | 18 ++++++++++-------- pyserve/ctl/commands/status.py | 8 ++++---- pyserve/ctl/commands/top.py | 12 ++++++------ pyserve/ctl/commands/up.py | 11 ++++++----- pyserve/ctl/main.py | 20 ++++++++++++-------- pyserve/ctl/state/__init__.py | 2 +- 15 files changed, 87 insertions(+), 62 deletions(-) diff --git a/poetry.lock b/poetry.lock index 86efa0c..e3e4c8a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1349,6 +1349,18 @@ files = [ {file = "structlog-25.4.0.tar.gz", hash = "sha256:186cd1b0a8ae762e29417095664adf1d6a31702160a46dacb7796ea82f7409e4"}, ] +[[package]] +name = "types-psutil" +version = "7.1.3.20251202" +description = "Typing stubs for psutil" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "types_psutil-7.1.3.20251202-py3-none-any.whl", hash = "sha256:39bfc44780de7ab686c65169e36a7969db09e7f39d92de643b55789292953400"}, + {file = "types_psutil-7.1.3.20251202.tar.gz", hash = "sha256:5cfecaced7c486fb3995bb290eab45043d697a261718aca01b9b340d1ab7968a"}, +] + [[package]] name = "types-pyyaml" version = "6.0.12.20250822" @@ -1709,4 +1721,4 @@ wsgi = ["a2wsgi"] [metadata] lock-version = "2.1" python-versions = ">=3.12" -content-hash = "359245cc9d83f36b9eff32deaf7a4665b25149c89b4062abab72db1c07607500" +content-hash = "653d7b992e2bb133abde2e8b1c44265e948ed90487ab3f2670429510a8aa0683" diff --git a/pyproject.toml b/pyproject.toml index ced1eff..7823ac5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -101,4 +101,5 @@ flake8 = "^7.3.0" pytest-asyncio = "^1.3.0" cython = "^3.0.0" setuptools = "^80.0.0" +types-psutil = "^7.1.3.20251202" diff --git a/pyserve/ctl/_daemon.py b/pyserve/ctl/_daemon.py index 1967536..326e995 100644 --- a/pyserve/ctl/_daemon.py +++ b/pyserve/ctl/_daemon.py @@ -11,9 +11,11 @@ import os import signal import sys from pathlib import Path +from types import FrameType +from typing import Optional -def main(): +def main() -> None: parser = argparse.ArgumentParser(description="PyServe Daemon") parser.add_argument("--config", required=True, help="Configuration file path") parser.add_argument("--state-dir", required=True, help="State directory path") @@ -63,7 +65,7 @@ def main(): runner = ServiceRunner(config, state_manager) - def signal_handler(signum, frame): + def signal_handler(signum: int, frame: Optional[FrameType]) -> None: logger.info(f"Received signal {signum}, shutting down...") runner.stop() diff --git a/pyserve/ctl/commands/config.py b/pyserve/ctl/commands/config.py index 3b5a381..24a43ac 100644 --- a/pyserve/ctl/commands/config.py +++ b/pyserve/ctl/commands/config.py @@ -11,7 +11,7 @@ import yaml @click.group("config") -def config_cmd(): +def config_cmd() -> None: """ Configuration management commands. @@ -40,7 +40,7 @@ def config_cmd(): help="Enable strict validation (warn on unknown fields)", ) @click.pass_obj -def validate_cmd(ctx, config_file: Optional[str], strict: bool): +def validate_cmd(ctx: Any, config_file: Optional[str], strict: bool) -> None: """ Validate a configuration file. @@ -146,7 +146,7 @@ def validate_cmd(ctx, config_file: Optional[str], strict: bool): help="Show only a specific section (e.g., server, logging)", ) @click.pass_obj -def show_cmd(ctx, config_file: Optional[str], output_format: str, section: Optional[str]): +def show_cmd(ctx: Any, config_file: Optional[str], output_format: str, section: Optional[str]) -> None: """ Display current configuration. @@ -192,7 +192,7 @@ def show_cmd(ctx, config_file: Optional[str], output_format: str, section: Optio elif output_format == "table": from rich.tree import Tree - def build_tree(data, tree): + def build_tree(data: Any, tree: Any) -> None: if isinstance(data, dict): for key, value in data.items(): if isinstance(value, (dict, list)): @@ -227,7 +227,7 @@ def show_cmd(ctx, config_file: Optional[str], output_format: str, section: Optio help="Path to configuration file", ) @click.pass_obj -def get_cmd(ctx, key: str, config_file: Optional[str]): +def get_cmd(ctx: Any, key: str, config_file: Optional[str]) -> None: """ Get a specific configuration value. @@ -291,7 +291,7 @@ def get_cmd(ctx, key: str, config_file: Optional[str]): help="Path to configuration file", ) @click.pass_obj -def set_cmd(ctx, key: str, value: str, config_file: Optional[str]): +def set_cmd(ctx: Any, key: str, value: str, config_file: Optional[str]) -> None: """ Set a configuration value. @@ -357,7 +357,7 @@ def set_cmd(ctx, key: str, value: str, config_file: Optional[str]): @config_cmd.command("diff") @click.argument("file1", type=click.Path(exists=True)) @click.argument("file2", type=click.Path(exists=True)) -def diff_cmd(file1: str, file2: str): +def diff_cmd(file1: str, file2: str) -> None: """ Compare two configuration files. @@ -373,8 +373,8 @@ def diff_cmd(file1: str, file2: str): with open(file2) as f: data2 = yaml.safe_load(f) - def compare_dicts(d1, d2, path=""): - differences = [] + def compare_dicts(d1: Any, d2: Any, path: str = "") -> list[tuple[str, str, Any, Any]]: + differences: list[tuple[str, str, Any, Any]] = [] all_keys = set(d1.keys() if d1 else []) | set(d2.keys() if d2 else []) diff --git a/pyserve/ctl/commands/down.py b/pyserve/ctl/commands/down.py index f5497de..5d43123 100644 --- a/pyserve/ctl/commands/down.py +++ b/pyserve/ctl/commands/down.py @@ -5,7 +5,7 @@ pyserve down - Stop all services import signal import time from pathlib import Path -from typing import cast +from typing import Any, cast import click @@ -31,11 +31,11 @@ import click ) @click.pass_obj def down_cmd( - ctx, + ctx: Any, timeout: int, volumes: bool, remove_orphans: bool, -): +) -> None: """ Stop and remove all services. diff --git a/pyserve/ctl/commands/health.py b/pyserve/ctl/commands/health.py index 1d9a55c..3a25385 100644 --- a/pyserve/ctl/commands/health.py +++ b/pyserve/ctl/commands/health.py @@ -5,6 +5,8 @@ pyserve health - Check health of services import asyncio from pathlib import Path +from typing import Any + import click @@ -25,7 +27,7 @@ import click help="Output format", ) @click.pass_obj -def health_cmd(ctx, services: tuple, timeout: int, output_format: str): +def health_cmd(ctx: Any, services: tuple[str, ...], timeout: int, output_format: str) -> None: """ Check health of services. diff --git a/pyserve/ctl/commands/init.py b/pyserve/ctl/commands/init.py index 90a98c6..830cfa4 100644 --- a/pyserve/ctl/commands/init.py +++ b/pyserve/ctl/commands/init.py @@ -364,12 +364,12 @@ def get_template_content(template: str) -> str: ) @click.pass_context def init_cmd( - ctx, + ctx: click.Context, template: str, output_file: str, force: bool, list_templates: bool, -): +) -> None: """ Initialize a new pyserve project. diff --git a/pyserve/ctl/commands/logs.py b/pyserve/ctl/commands/logs.py index 06015d2..13dda2e 100644 --- a/pyserve/ctl/commands/logs.py +++ b/pyserve/ctl/commands/logs.py @@ -5,7 +5,7 @@ pyserve logs - View service logs import asyncio import time from pathlib import Path -from typing import Optional +from typing import Any, Optional import click @@ -56,8 +56,8 @@ import click ) @click.pass_obj def logs_cmd( - ctx, - services: tuple, + ctx: Any, + services: tuple[str, ...], follow: bool, tail: int, since: Optional[str], @@ -65,7 +65,7 @@ def logs_cmd( timestamps: bool, no_color: bool, filter_pattern: Optional[str], -): +) -> None: """ View service logs. @@ -165,15 +165,15 @@ def _parse_time(time_str: str) -> Optional[float]: def _read_logs( - log_files, - service_colors, + log_files: list[tuple[str, Path]], + service_colors: dict[str, str], tail: int, since_time: Optional[float], until_time: Optional[float], timestamps: bool, no_color: bool, filter_pattern: Optional[str], -): +) -> None: import re from ..output import console @@ -231,12 +231,12 @@ def _read_logs( async def _follow_logs( - log_files, - service_colors, + log_files: list[tuple[str, Path]], + service_colors: dict[str, str], timestamps: bool, no_color: bool, filter_pattern: Optional[str], -): +) -> None: from ..output import console positions = {} diff --git a/pyserve/ctl/commands/scale.py b/pyserve/ctl/commands/scale.py index 01edc9c..d07a2b6 100644 --- a/pyserve/ctl/commands/scale.py +++ b/pyserve/ctl/commands/scale.py @@ -4,6 +4,7 @@ pyserve scale - Scale services import asyncio from pathlib import Path +from typing import Any import click @@ -23,7 +24,7 @@ import click help="Don't wait for services to be ready", ) @click.pass_obj -def scale_cmd(ctx, scales: tuple, timeout: int, no_wait: bool): +def scale_cmd(ctx: Any, scales: tuple[str, ...], timeout: int, no_wait: bool) -> None: """ Scale services to specified number of workers. @@ -66,7 +67,7 @@ def scale_cmd(ctx, scales: tuple, timeout: int, no_wait: bool): console.print("[bold]Scaling services...[/bold]") - async def do_scale(): + async def do_scale() -> None: for service, workers in scale_map.items(): current = all_services[service].workers or 1 print_info(f"Scaling {service}: {current} → {workers} workers") diff --git a/pyserve/ctl/commands/service.py b/pyserve/ctl/commands/service.py index 39e1331..400c690 100644 --- a/pyserve/ctl/commands/service.py +++ b/pyserve/ctl/commands/service.py @@ -5,6 +5,8 @@ pyserve start/stop/restart - Service management commands import asyncio from pathlib import Path +from typing import Any, Dict + import click @@ -18,7 +20,7 @@ import click help="Timeout in seconds for service startup", ) @click.pass_obj -def start_cmd(ctx, services: tuple, timeout: int): +def start_cmd(ctx: Any, services: tuple[str, ...], timeout: int) -> None: """ Start one or more services. @@ -43,8 +45,8 @@ def start_cmd(ctx, services: tuple, timeout: int): console.print(f"[bold]Starting services: {', '.join(services)}[/bold]") - async def do_start(): - results = {} + async def do_start() -> Dict[str, bool]: + results: Dict[str, bool] = {} for service in services: try: success = await runner.start_service(service, timeout=timeout) @@ -83,7 +85,7 @@ def start_cmd(ctx, services: tuple, timeout: int): help="Force stop (SIGKILL)", ) @click.pass_obj -def stop_cmd(ctx, services: tuple, timeout: int, force: bool): +def stop_cmd(ctx: Any, services: tuple[str, ...], timeout: int, force: bool) -> None: """ Stop one or more services. @@ -106,8 +108,8 @@ def stop_cmd(ctx, services: tuple, timeout: int, force: bool): console.print(f"[bold]Stopping services: {', '.join(services)}[/bold]") - async def do_stop(): - results = {} + async def do_stop() -> Dict[str, bool]: + results: Dict[str, bool] = {} for service in services: try: success = await runner.stop_service(service, timeout=timeout, force=force) @@ -140,7 +142,7 @@ def stop_cmd(ctx, services: tuple, timeout: int, force: bool): help="Timeout in seconds for restart", ) @click.pass_obj -def restart_cmd(ctx, services: tuple, timeout: int): +def restart_cmd(ctx: Any, services: tuple[str, ...], timeout: int) -> None: """ Restart one or more services. @@ -165,7 +167,7 @@ def restart_cmd(ctx, services: tuple, timeout: int): console.print(f"[bold]Restarting services: {', '.join(services)}[/bold]") - async def do_restart(): + async def do_restart() -> Dict[str, bool]: results = {} for service in services: try: diff --git a/pyserve/ctl/commands/status.py b/pyserve/ctl/commands/status.py index 15589f5..d922644 100644 --- a/pyserve/ctl/commands/status.py +++ b/pyserve/ctl/commands/status.py @@ -4,7 +4,7 @@ pyserve ps / status - Show service status import json from pathlib import Path -from typing import Optional +from typing import Any, Optional import click @@ -39,13 +39,13 @@ import click ) @click.pass_obj def ps_cmd( - ctx, - services: tuple, + ctx: Any, + services: tuple[str, ...], show_all: bool, quiet: bool, output_format: str, filter_status: Optional[str], -): +) -> None: """ Show status of services. diff --git a/pyserve/ctl/commands/top.py b/pyserve/ctl/commands/top.py index 9a5059c..110ba67 100644 --- a/pyserve/ctl/commands/top.py +++ b/pyserve/ctl/commands/top.py @@ -5,7 +5,7 @@ pyserve top - Live monitoring dashboard import asyncio import time from pathlib import Path -from typing import Optional +from typing import Any, Optional import click @@ -25,7 +25,7 @@ import click help="Disable colored output", ) @click.pass_obj -def top_cmd(ctx, services: tuple, refresh_interval: float, no_color: bool): +def top_cmd(ctx: Any, services: tuple[str, ...], refresh_interval: float, no_color: bool) -> None: """ Live monitoring dashboard for services. @@ -60,11 +60,11 @@ def top_cmd(ctx, services: tuple, refresh_interval: float, no_color: bool): async def _run_dashboard( - state_manager, - filter_services: Optional[list], + state_manager: Any, + filter_services: Optional[list[str]], refresh_interval: float, no_color: bool, -): +) -> None: from rich.layout import Layout from rich.live import Live from rich.panel import Panel @@ -81,7 +81,7 @@ async def _run_dashboard( start_time = time.time() - def make_dashboard(): + def make_dashboard() -> Any: all_services = state_manager.get_all_services() if filter_services: diff --git a/pyserve/ctl/commands/up.py b/pyserve/ctl/commands/up.py index 26b0063..e4c2340 100644 --- a/pyserve/ctl/commands/up.py +++ b/pyserve/ctl/commands/up.py @@ -7,6 +7,7 @@ import signal import sys import time from pathlib import Path +from typing import Any import click @@ -54,16 +55,16 @@ import click ) @click.pass_obj def up_cmd( - ctx, - services: tuple, + ctx: Any, + services: tuple[str, ...], detach: bool, build: bool, force_recreate: bool, - scales: tuple, + scales: tuple[str, ...], timeout: int, wait: bool, remove_orphans: bool, -): +) -> None: """ Start services defined in configuration. @@ -147,7 +148,7 @@ def up_cmd( else: console.print("[bold]Starting PyServe...[/bold]") - def signal_handler(signum, frame): + def signal_handler(signum: int, frame: Any) -> None: console.print("\n[yellow]Received shutdown signal...[/yellow]") runner.stop() sys.exit(0) diff --git a/pyserve/ctl/main.py b/pyserve/ctl/main.py index 9acdf76..fdfecf3 100644 --- a/pyserve/ctl/main.py +++ b/pyserve/ctl/main.py @@ -7,7 +7,7 @@ Usage: import sys from pathlib import Path -from typing import Optional +from typing import TYPE_CHECKING, Optional import click @@ -28,22 +28,26 @@ from .commands import ( from .. import __version__ +if TYPE_CHECKING: + from ..config import Config + from .state import StateManager + DEFAULT_CONFIG = "config.yaml" DEFAULT_STATE_DIR = ".pyserve" class Context: - def __init__(self): + def __init__(self) -> None: self.config_file: str = DEFAULT_CONFIG self.state_dir: Path = Path(DEFAULT_STATE_DIR) self.verbose: bool = False self.debug: bool = False self.project: Optional[str] = None - self._config = None - self._state = None + self._config: Optional["Config"] = None + self._state: Optional["StateManager"] = None @property - def config(self): + def config(self) -> "Config": if self._config is None: from ..config import Config @@ -54,7 +58,7 @@ class Context: return self._config @property - def state(self): + def state(self) -> "StateManager": if self._state is None: from .state import StateManager @@ -96,7 +100,7 @@ pass_context = click.make_pass_decorator(Context, ensure=True) ) @click.version_option(version=__version__, prog_name="pyservectl") @click.pass_context -def cli(ctx, config_file: str, project: Optional[str], verbose: bool, debug: bool): +def cli(ctx: click.Context, config_file: str, project: Optional[str], verbose: bool, debug: bool) -> None: """ PyServeCTL - Service management CLI for PyServe. @@ -145,7 +149,7 @@ cli.add_command(scale_cmd, name="scale") cli.add_command(ps_cmd, name="status") -def main(): +def main() -> None: try: cli(standalone_mode=False) except click.ClickException as e: diff --git a/pyserve/ctl/state/__init__.py b/pyserve/ctl/state/__init__.py index 8a923ea..7300608 100644 --- a/pyserve/ctl/state/__init__.py +++ b/pyserve/ctl/state/__init__.py @@ -148,7 +148,7 @@ class StateManager: def get_state(self) -> ProjectState: return self.load() - def update_service(self, name: str, **kwargs) -> ServiceState: + def update_service(self, name: str, **kwargs: Any) -> ServiceState: state = self.load() if name not in state.services: