Skip to content

chore: add ruff + mypy Python linting with pre-commit and CI - #340

Merged
CatherineSue merged 10 commits into
mainfrom
chang/add-python-precommit
Feb 6, 2026
Merged

CatherineSue merged 10 commits into
mainfrom
chang/add-python-precommit

Conversation

@CatherineSue

@CatherineSue CatherineSue commented Feb 5, 2026 •

Copy link
Copy Markdown
Member

Description

Problem

The Python code in e2e_test/, bindings/python/, and scripts/ had no automated linting or formatting enforcement, leading to inconsistent style, deprecated typing patterns, and unused imports accumulating over time.

Solution

Add ruff (lint + format) as a pre-commit hook and CI check, plus mypy for type checking in CI. Bump minimum Python version from 3.9 (EOL) to 3.12.

Changes

  • ruff.toml — New config: Python 3.12 target, line-length 100 (code) / 120 (comments/docstrings), rules: E, F, I, W, UP
  • mypy.ini — New permissive mypy config for CI
  • .pre-commit-config.yaml — Removed global exclude for Python dirs, added ruff and ruff-format hooks
  • .github/workflows/pr-test-rust.yml — Added python-lint CI job (ruff check, ruff format --check, mypy)
  • e2e_test/pyproject.toml / bindings/python/pyproject.toml — Bumped requires-python to >=3.12, added mypy + ruff dev deps
  • 48 Python files — Applied ruff lint + format fixes:
    • Modernized typing: Optional[X] → X | None, List → list, Dict → dict, Tuple → tuple
    • Fixed import sorting, removed unused imports/variables
    • Fixed all line-length violations
    • Applied consistent black-compatible formatting

Test Plan

  • ruff check e2e_test/ bindings/python/ scripts/ → All checks passed
  • ruff format --check e2e_test/ bindings/python/ scripts/ → 68 files already formatted
  • CI python-lint job validates on every PR going forward
Checklist
  • cargo +nightly fmt passes
  • cargo clippy --all-targets --all-features -- -D warnings passes
  • ruff check passes
  • ruff format --check passes

Summary by CodeRabbit

Release Notes

  • Chores

    • Updated minimum Python version requirement to 3.12.
    • Added automated Python linting and type checking via Ruff and MyPy in CI pipeline.
    • Configured Ruff and MyPy for enhanced code quality.
  • Refactor

    • Modernized Python type annotations to use PEP 604 syntax (| operator instead of Union).
    • Updated type hints across codebase for improved type safety.
  • Bug Fixes

    • Enhanced error handling and validation in argument parsing and server startup logic.
    • Added robustness checks for process management and resource cleanup.

Add pre-commit hooks (ruff check + ruff format) and a CI python-lint
job with ruff and mypy. Bump minimum Python to 3.12.
Modernize typing (Optional[X] -> X | None, List -> list, Dict -> dict),
fix import sorting, remove unused imports/variables, fix line lengths,
and apply consistent formatting to all Python files.
@github-actions github-actions Bot added python-bindings Python bindings changes dependencies Dependency updates ci CI/CD configuration changes tests Test changes labels Feb 5, 2026
@coderabbitai

coderabbitai Bot commented Feb 5, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR modernizes the Python codebase to version 3.12+, adding linting infrastructure (mypy, ruff) via CI/CD and configuration files, updating all type annotations to PEP 604 union syntax and built-in generics (list, dict), and refactoring key modules for improved type safety and error handling.

Changes

Cohort / File(s) Summary
CI/CD and Linting Configuration
.github/workflows/pr-test-rust.yml, .pre-commit-config.yaml, ruff.toml, mypy.ini
Added Python linting job (ruff, mypy) to CI pipeline, configured pre-commit hooks for ruff, and created configuration files for mypy and ruff with Python 3.12 targeting, line-length 100, and selective lint rules.
Python Version and Dependencies
bindings/python/pyproject.toml, e2e_test/pyproject.toml
Bumped minimum Python requirement from 3.9 to 3.12 across bindings and e2e_test, added mypy and ruff as dev dependencies.
Type Annotation Modernization - Bindings
bindings/python/src/smg/router_args.py, bindings/python/src/smg/router.py, bindings/python/src/smg/serve.py
Migrated ~80 field and method type annotations from Optional[T]/List[T]/Dict[K,V] to modern T | None/list[T]/dict[K,V] syntax across RouterArgs dataclass and router/serve modules.
Type Annotation Modernization - E2E Tests
e2e_test/fixtures/hooks.py, e2e_test/fixtures/pool.py, e2e_test/fixtures/setup_backend.py, e2e_test/infra/constants.py, e2e_test/infra/gateway.py, e2e_test/infra/model_pool.py, e2e_test/infra/simple_eval_common.py
Updated type hints to use Generator from collections.abc, converted forward-referenced types to concrete types (e.g., "ModelPool" → ModelPool), replaced Enum with StrEnum for ConnectionMode/WorkerType/Runtime, and expanded Runtime enum with new members (VLLM, TRTLLM, OPENAI, XAI, GEMINI).
CLI and Server Module Refactoring
bindings/python/src/smg/cli.py, bindings/python/src/smg/launch_router.py, bindings/python/src/smg/launch_server.py
Refactored cli.py main function with pre-parse version flag handling, lazy imports per subcommand, and empty command validation; updated launch_router to accept RouterArgs or Namespace with exception-based error handling; consolidated launch_server signal handling and added try/except around router startup with cleanup on failure.
Python Script Modernization
bindings/python/setup.py, scripts/run_benchmarks.py, e2e_test/infra/run_eval.py, e2e_test/infra/model_specs.py
Modernized type annotations from typing module to built-ins, refactored variable assignments, added exception handling in run_benchmarks (CalledProcessError), and converted forward reference type annotations to concrete types.
Comprehensive Test Formatting
bindings/python/tests/*.py, e2e_test/chat_completions/*.py, e2e_test/responses/*.py, e2e_test/router/*.py, e2e_test/benchmarks/*.py
Consolidated multi-line constructs to single-line equivalents across 20+ test files (RouterArgs instantiations, assertions, decorators, list/dict literals) with no functional logic changes; minor exception handling updates for TimeoutError ordering.
Infrastructure and Utility Updates
e2e_test/infra/__init__.py, e2e_test/infra/gpu_allocator.py, e2e_test/infra/gpu_monitor.py, e2e_test/infra/simple_eval_mmlu.py, e2e_test/benchmarks/nightly_summarize.py, e2e_test/benchmarks/results.py, e2e_test/benchmarks/summarize.py
Removed unused imports, consolidated formatting in logging/assertions, added None-safety checks, updated type annotations, and converted string format literals for consistency.
Miscellaneous Configuration
bindings/python/tests/conftest.py, e2e_test/bindings_go/conftest.py, e2e_test/benchmarks/conftest.py
Minor formatting adjustments, updated fixture type hints to use collections.abc.Generator, removed quotes around type annotations, and added mypy-facing assertions for None-safety.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • key4ng

Poem

🐰 Hops through the types so bright,
From Optional's old height,
To | None and list[str] delight,
Ruff and mypy linting tight,
Python 3.12—pure type-checked flight! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and directly describes the main objective of the changeset: adding ruff and mypy Python linting with pre-commit and CI integration.
Docstring Coverage ✅ Passed Docstring coverage is 85.09% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chang/add-python-precommit

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @CatherineSue, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the quality and consistency of the Python codebase by integrating modern linting, formatting, and static type-checking tools. By adopting Ruff and Mypy, and updating the Python version to 3.12, the project benefits from automated code quality enforcement, improved readability, and early detection of potential issues, streamlining development and maintenance workflows.

Highlights

  • New Python Linting and Formatting: Introduced 'ruff' for both linting and formatting Python code, ensuring consistent style and catching common issues. This is integrated as a pre-commit hook and a CI check.
  • Static Type Checking with Mypy: Added 'mypy' for static type checking of Python code, which runs as part of the CI pipeline to improve code reliability and maintainability.
  • Python Version Update: The minimum required Python version has been bumped from 3.9 (which is End-of-Life) to 3.12 across the relevant Python projects.
  • Code Modernization and Cleanup: Applied extensive fixes across 48 Python files, including modernizing typing patterns (e.g., Optional[X] to X | None), fixing import sorting, removing unused imports/variables, and enforcing consistent formatting.
Changelog
  • .pre-commit-config.yaml
    • Removed global exclude for Python directories, allowing pre-commit hooks to run on Python files.
    • Added ruff and ruff-format hooks to automate linting and formatting.
  • bindings/python/pyproject.toml
    • Updated requires-python to >=3.12.
    • Added mypy and ruff as development dependencies.
    • Removed older Python versions (3.9, 3.10, 3.11) from project classifiers.
  • bindings/python/setup.py
    • Minor formatting adjustment in a warnings.warn call.
  • bindings/python/src/smg/cli.py
    • Removed typing.List and typing.Optional imports, adopting native Python type hints (list[str] | None).
    • Removed explicit assignment of subparsers.add_parser return values to variables when those variables were not subsequently used.
  • bindings/python/src/smg/launch_router.py
    • Removed typing.List and typing.Optional imports, adopting native Python type hints.
  • bindings/python/src/smg/launch_server.py
    • Removed typing.List import, adopting native Python type hints.
    • Reordered imports for consistency.
    • Applied minor formatting changes to multi-line strings and function signatures for improved readability.
  • bindings/python/src/smg/router.py
    • Removed typing.Optional import, adopting native Python type hints.
  • bindings/python/src/smg/router_args.py
    • Removed typing.Dict, typing.List, and typing.Optional imports, adopting native Python type hints.
    • Adjusted help text formatting for CLI arguments to fit within line length limits.
  • bindings/python/src/smg/serve.py
    • Removed typing.List, typing.Optional, and typing.Tuple imports, adopting native Python type hints.
    • Applied minor formatting changes to function signatures and multi-line strings.
  • bindings/python/tests/conftest.py
    • Removed redundant import pytest statement.
    • Minor formatting adjustment for config.addinivalue_line call.
  • bindings/python/tests/test_arg_parser.py
    • Minor formatting adjustments in function calls.
  • bindings/python/tests/test_router_config.py
    • Minor formatting adjustments in function calls.
  • bindings/python/tests/test_serve.py
    • Minor formatting adjustments in function calls and multi-line argument lists.
  • bindings/python/tests/test_startup_sequence.py
    • Minor formatting adjustments in function calls and multi-line strings.
  • bindings/python/tests/test_validation.py
    • Minor formatting adjustments in function calls.
  • e2e_test/benchmarks/nightly_summarize.py
    • Removed unused re import.
    • Minor formatting adjustments in f-strings and multi-line strings.
    • Replaced unicode warning sign with its escape sequence for consistency.
  • e2e_test/benchmarks/results.py
    • Removed redundant cls type hint from from_json method signature.
    • Minor formatting adjustments in multi-line function calls.
  • e2e_test/benchmarks/summarize.py
    • Minor formatting adjustments in multi-line strings and function calls.
  • e2e_test/benchmarks/test_nightly_perf.py
    • Minor formatting adjustments in multi-line lists and function calls.
    • Removed unused import.
  • e2e_test/bindings_go/conftest.py
    • Updated typing.Generator to collections.abc.Generator for improved type hint compatibility.
    • Replaced socket.timeout with TimeoutError in exception handling.
    • Minor formatting adjustments in f-strings.
  • e2e_test/bindings_go/test_go_oai_server.py
    • Minor formatting adjustments in multi-line lists and f-strings.
  • e2e_test/chat_completions/test_enable_thinking.py
    • Minor formatting adjustments in multi-line strings.
  • e2e_test/chat_completions/test_function_calling.py
    • Minor formatting adjustments in multi-line strings, comments, and function calls.
  • e2e_test/chat_completions/test_openai_server.py
    • Minor formatting adjustments in multi-line strings and function calls.
  • e2e_test/chat_completions/test_reasoning_content.py
    • Minor formatting adjustments in multi-line strings and function calls.
  • e2e_test/chat_completions/test_validation.py
    • Minor formatting adjustments in multi-line strings and function calls.
  • e2e_test/embeddings/test_correctness.py
    • Minor formatting adjustments in multi-line strings and function calls.
  • e2e_test/fixtures/hooks.py
    • Updated type hints for _worker_counts and _first_seen_order to use direct class references instead of string literals (e.g., ConnectionMode instead of "ConnectionMode").
    • Minor formatting adjustments in function calls.
    • Removed unused import of LOG_SEPARATOR_WIDTH.
  • e2e_test/fixtures/pool.py
    • Updated type hints for _model_pool and fixture return types to use direct class references instead of string literals (e.g., ModelPool instead of "ModelPool").
    • Minor formatting adjustments in multi-line lists.
  • e2e_test/fixtures/setup_backend.py
    • Updated type hints for model_pool parameter to use direct class references instead of string literals.
    • Minor formatting adjustments in multi-line function calls.
  • e2e_test/infra/init.py
    • Reordered imports for consistency.
  • e2e_test/infra/constants.py
    • Minor formatting adjustments.
  • e2e_test/infra/gateway.py
    • Updated type hint for __enter__ method to use direct class reference Gateway instead of string literal "Gateway".
    • Minor formatting adjustments in multi-line strings.
  • e2e_test/infra/gpu_allocator.py
    • Minor formatting adjustments in list comprehensions.
  • e2e_test/infra/gpu_monitor.py
    • Minor formatting adjustments in multi-line function calls and f-strings.
  • e2e_test/infra/model_pool.py
    • Minor formatting adjustments in f-strings and multi-line function calls.
    • Updated type hint for get_client method to use direct class reference openai.OpenAI instead of string literal "openai.OpenAI".
  • e2e_test/infra/model_specs.py
    • Minor formatting adjustments in multi-line lists and f-strings.
  • e2e_test/infra/run_eval.py
    • Updated type hint for _get_eval function to use direct class reference Eval instead of string literal "Eval".
  • e2e_test/infra/simple_eval_common.py
    • Minor formatting adjustments in multi-line strings and function calls.
  • e2e_test/infra/simple_eval_mmlu.py
    • Updated type hint for sampler parameter to use direct class reference SamplerBase instead of string literal "SamplerBase".
    • Minor formatting adjustments in function calls.
  • e2e_test/pyproject.toml
    • Updated requires-python to >=3.12.
    • Added mypy to development dependencies.
  • e2e_test/responses/test_basic_crud.py
    • Minor formatting adjustments in multi-line strings.
  • e2e_test/responses/test_builtin_tools.py
    • Replaced socket.timeout with TimeoutError in exception handling.
    • Minor formatting adjustments in multi-line strings.
  • e2e_test/responses/test_state_management.py
    • Minor formatting adjustments in multi-line strings.
  • e2e_test/responses/test_streaming_events.py
    • Minor formatting adjustments in multi-line strings.
  • e2e_test/responses/test_structured_output.py
    • Minor formatting adjustments in multi-line strings.
  • e2e_test/responses/test_tools_call.py
    • Minor formatting adjustments in multi-line strings.
  • e2e_test/router/test_mmlu.py
    • Minor formatting adjustments in f-strings.
  • e2e_test/router/test_pd_mmlu.py
    • Minor formatting adjustments in f-strings.
  • e2e_test/router/test_worker_api.py
    • Minor formatting adjustments in multi-line strings.
  • mypy.ini
    • New configuration file for Mypy.
    • Sets python_version = 3.12.
    • Configures ignore_missing_imports = True.
    • Disables warn_return_any and check_untyped_defs.
    • Enables warn_unused_configs.
  • ruff.toml
    • New configuration file for Ruff.
    • Sets target-version = "py312" and line-length = 100.
    • Selects lint rules E, F, I, W, UP.
    • Configures lint.pycodestyle.max-line-length = 120 for comments/docstrings.
    • Adds per-file-ignores for e2e_test/** and bindings/python/tests/** to ignore F841 (unused variables) and E402 (module level import not at top of file).
  • scripts/run_benchmarks.py
    • Removed unused os import.
    • Removed typing.Dict, typing.List, and typing.Optional imports, adopting native Python type hints.
    • Minor formatting adjustments in function calls.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/pr-test-rust.yml
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
bindings/python/tests/test_startup_sequence.py (1)

839-854: ⚠️ Potential issue | 🟠 Major

Nested function will not be executed by pytest.

test_validation_error_handling is defined inside test_launch_server_process_and_cleanup at line 839, making it a nested function rather than a test method. It also uses self without being part of a class. This test will never be discovered or executed by pytest.

This appears to be an indentation error—the function should likely be a method of a test class (e.g., TestStartupErrorHandling) or moved to module level as a standalone test function.

Proposed fix: Move to class or module level

If it belongs in TestStartupErrorHandling, move it there:

 class TestStartupErrorHandling:
     """Test startup error handling logic."""

+    def test_validation_error_handling(self):
+        """Test error handling when validation fails."""
+        args = RouterArgs(
+            pd_disaggregation=True,
+            prefill_urls=[],
+            decode_urls=[],
+            service_discovery=False,
+        )
+
+        with patch("smg.launch_router.logger") as mock_logger:
+            with pytest.raises(ValueError, match="PD disaggregation mode requires --prefill"):
+                launch_router(args)
+
+            # Should log error for validation failures
+            mock_logger.error.assert_called_once()
+
     def test_router_creation_error_handling(self):

And remove it from inside test_launch_server_process_and_cleanup.

bindings/python/src/smg/launch_router.py (1)

18-46: ⚠️ Potential issue | 🟡 Minor

Return type and docstring are inconsistent with actual behavior.

The function signature declares -> Router | None and the docstring states "Returns: Router instance if successful, None if failed". However, the function:

  • Returns None implicitly on success (no return statement after router.start())
  • Raises an exception on failure (re-raises after logging)

The function never returns a Router instance. Consider either:

  1. Returning the router instance after starting it, or
  2. Updating the return type to -> None and fixing the docstring
Option 1: Return the router instance
         router = Router.from_args(router_args)
         router.start()
+        return router

     except Exception as e:
         logger.error(f"Error starting router: {e}")
         raise e
Option 2: Fix return type and docstring
-def launch_router(args: argparse.Namespace) -> Router | None:
+def launch_router(args: argparse.Namespace) -> None:
     """
     Launch the SMG router with the configuration from parsed arguments.

     Args:
         args: Namespace object containing router configuration
             Can be either raw argparse.Namespace or converted RouterArgs

-    Returns:
-        Router instance if successful, None if failed
+    Raises:
+        RuntimeError: If Rust Router is not installed
+        Exception: If router initialization or startup fails
     """
bindings/python/src/smg/router.py (1)

17-31: ⚠️ Potential issue | 🟡 Minor

Return type annotation is incorrect.

The function returns None when policy_str is None (lines 19-20), but the return type is declared as -> PolicyType without allowing None. This is a type error that mypy should catch.

Proposed fix
-def policy_from_str(policy_str: str | None) -> PolicyType:
+def policy_from_str(policy_str: str | None) -> PolicyType | None:
🤖 Fix all issues with AI agents
In `@bindings/python/src/smg/router_args.py`:
- Around line 619-638: The CLI help string for the disable-circuit-breaker arg
in RouterArgs currently uses Rust-specific wording ("u32::MAX"); update the help
text in the add_argument call for f"--{prefix}disable-circuit-breaker" to a
language-agnostic phrasing such as "Disable circuit breaker (equivalent to
setting cb_failure_threshold to the maximum 32-bit unsigned value)" or "Disable
circuit breaker by setting cb_failure_threshold to a very large value", so users
of the Python CLI aren’t exposed to Rust-specific notation; locate the change
near the RouterArgs code where health_group and the disable-circuit-breaker
argument are defined.

In `@e2e_test/fixtures/hooks.py`:
- Line 27: The type annotation for _worker_counts is incorrect: it currently
uses tuple[ConnectionMode, WorkerType] but the code uses 3-tuples including a
model_id string; update the annotation to dict[tuple[ConnectionMode, WorkerType,
str], int] (referencing the _worker_counts variable and the ConnectionMode and
WorkerType types and the model_id key used across the file) so the declared type
matches actual usage.
🧹 Nitpick comments (3)
e2e_test/bindings_go/conftest.py (1)

142-163: Consider adding type parameter for consistency.

Line 142's return type is properly parameterized, but line 163 uses an unparameterized list. For consistency with the PR's type modernization goal and better static analysis:

-    instances: list = []
+    instances: list[ModelInstance] = []
mypy.ini (1)

1-6: Permissive mypy configuration suitable for initial adoption.

The configuration is intentionally lenient (check_untyped_defs = False, warn_return_any = False) which is reasonable for introducing mypy to an existing codebase. Consider adding a comment noting the intent to gradually tighten these settings as type coverage improves.

📝 Suggested documentation comment
 [mypy]
+# NOTE: Permissive configuration for initial adoption.
+# TODO: Tighten settings as type coverage improves:
+#   - check_untyped_defs = True
+#   - warn_return_any = True
 python_version = 3.12
 ignore_missing_imports = True
 warn_return_any = False
 warn_unused_configs = True
 check_untyped_defs = False
.github/workflows/pr-test-rust.yml (1)

57-57: Consider pinning ruff and mypy versions for CI stability.

Installing unpinned ruff and mypy means CI behavior may change unexpectedly when new versions are released (e.g., new lint rules, stricter checks). Consider pinning to specific versions that match what's in pyproject.toml dev dependencies:

🔧 Suggested fix
      - name: Install linting tools
-        run: pip install ruff mypy
+        run: pip install ruff==0.8.6 mypy==1.14.1

Alternatively, install from the project's dev dependencies to ensure consistency with local development.

Comment thread bindings/python/src/smg/router_args.py
Comment thread e2e_test/fixtures/hooks.py Outdated

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request is a great initiative to improve Python code quality by introducing ruff for linting/formatting and mypy for type checking. The update of the minimum Python version to 3.12 and the application of automated fixes across the codebase are valuable changes. The configurations for the new tools are sensible starting points. I have one suggestion regarding the pre-commit configuration to ensure it works as expected for all developers.

Comment thread .pre-commit-config.yaml
- Migrate str+Enum to StrEnum (ruff UP042)
- Fix _worker_counts type annotation to match 3-tuple usage
- Replace Rust-specific u32::MAX in CLI help with generic wording
Comment thread bindings/python/pyproject.toml

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
bindings/python/tests/test_startup_sequence.py (1)

839-854: ⚠️ Potential issue | 🟡 Minor

Move test_validation_error_handling to the TestStartupErrorHandling class.

This test is currently nested inside the top-level function test_launch_server_process_and_cleanup (line 777), making it undiscoverable by pytest. As a nested function taking self as a parameter, it cannot execute. Move it to the TestStartupErrorHandling class (which exists at line 585) where it belongs as a proper test method.

🐛 Proposed fix: Move to TestStartupErrorHandling class

Move this function to be a method of the TestStartupErrorHandling class (after line 605):

 class TestStartupErrorHandling:
     """Test startup error handling logic."""
 
     def test_router_creation_error_handling(self):
         ...
 
     def test_router_start_error_handling(self):
         ...
 
+    def test_validation_error_handling(self):
+        """Test error handling when validation fails."""
+        args = RouterArgs(
+            pd_disaggregation=True,
+            prefill_urls=[],
+            decode_urls=[],
+            service_discovery=False,
+        )
+
+        with patch("smg.launch_router.logger") as mock_logger:
+            with pytest.raises(ValueError, match="PD disaggregation mode requires --prefill"):
+                launch_router(args)
+
+            # Should log error for validation failures
+            mock_logger.error.assert_called_once()
+

Remove it from inside test_launch_server_process_and_cleanup.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
bindings/python/src/smg/launch_router.py (1)

18-28: ⚠️ Potential issue | 🟡 Minor

Update the docstring to match the no‑return behavior.

launch_router now returns None, but the docstring still describes a Router return value.

Suggested fix
-    Returns:
-        Router instance if successful, None if failed
+    Returns:
+        None. Raises on failure.
e2e_test/infra/model_pool.py (1)

76-84: ⚠️ Potential issue | 🟠 Major

Clarify and unify PD worker key construction in ModelPool.

WorkerIdentity.key for non-REGULAR workers includes the index (e.g., llama-8b:http:prefill_0), but ModelPool._get_unlocked and _launch_model construct lookup keys without the index (llama-8b:http:prefill). While the codebase avoids calling get() with PREFILL/DECODE types (using get_workers_by_type() instead), this inconsistency is a design hazard: if future code calls get(model_id, mode, WorkerType.PREFILL), it will silently return only the first matching worker, hiding the existence of others. Either include the index in all PD worker keys or explicitly document that get() is not intended for PREFILL/DECODE workers.

🤖 Fix all issues with AI agents
In `@bindings/python/src/smg/launch_server.py`:
- Around line 183-186: The signal handlers currently call
cleanup_processes(server_processes) but do not terminate the main process;
change the handlers registered via signal.signal for SIGINT, SIGTERM and SIGQUIT
to invoke cleanup_processes(server_processes) and then exit the process (e.g.,
call sys.exit with an appropriate exit code) so the main process does not
continue running without workers; update the lambdas or replace them with a
small helper function (referencing cleanup_processes and the signal registration
sites) to ensure cleanup is performed followed by an immediate exit.

In `@e2e_test/infra/gateway.py`:
- Around line 272-276: The current regular-mode validation only checks for None
and allows an empty list; update the guard around worker_urls in the same block
that raises for model_path to ensure worker_urls is a non-empty sequence (e.g.,
if not worker_urls or len(worker_urls) == 0: raise ValueError("worker_urls must
be a non-empty list for regular mode")). Locate the check that references
worker_urls and model_path in gateway.py and replace or augment the existing "if
worker_urls is None" check with a truthiness/length check (optionally also
validate element types/strings) so an empty [] is rejected.
🧹 Nitpick comments (1)
e2e_test/infra/run_eval.py (1)

127-136: Consider logging a warning when score is None.

Silently defaulting result.score from None to 0.0 masks the distinction between "evaluation produced a zero score" and "evaluation failed to compute a score." In CI/CD environments, this could hide evaluation failures.

Consider adding a warning when the fallback occurs:

     # Build metrics
     metrics = result.metrics.copy() if result.metrics else {}
+    if result.score is None:
+        logger.warning("%s eval returned no score, defaulting to 0.0", eval_name)
     metrics["score"] = result.score if result.score is not None else 0.0

Comment thread bindings/python/src/smg/launch_server.py Outdated
Comment thread e2e_test/infra/gateway.py Outdated
- Update launch_router docstring to match None return type
- Fix signal handlers to exit after cleanup in launch_server
- Guard against empty worker_urls in gateway
- Log warning when eval score is None
- Move test_validation_error_handling to TestStartupErrorHandling class
The test was previously dead code (nested function inside another test,
undiscoverable by pytest). Moving it to TestStartupErrorHandling made it
run for the first time, but it only patched logger — not Router. If
validation didn't raise, Router.from_args().start() would block forever.
This test was originally dead code (nested function, never run by pytest).
_validate_router_args() only checks policy warnings — it does not validate
that prefill/decode URLs are non-empty, so the expected ValueError was
never raised.
@CatherineSue
CatherineSue force-pushed the chang/add-python-precommit branch 2 times, most recently from 5ba08ad to 79c153f Compare February 6, 2026 01:33
Cover the pid-is-None guard, SIGTERM ProcessLookupError, and SIGKILL
ProcessLookupError paths to bring coverage back above 80%.
@CatherineSue
CatherineSue force-pushed the chang/add-python-precommit branch from 79c153f to 37b0785 Compare February 6, 2026 01:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci CI/CD configuration changes dependencies Dependency updates python-bindings Python bindings changes tests Test changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants