Files
archived-MoviePilot/docs/rules/06-code-styles.md

5.1 KiB

06 — Code Standards and Style

General Principles

  • Preserve the style of the surrounding file. When in doubt, read neighboring code first.
  • Prefer the smallest correct change. Do not introduce a new abstraction layer without a clear payoff.
  • Do not add features, refactors, or abstractions beyond what the task requires.
  • Do not add error handling or validation for scenarios that cannot happen. Trust internal code and framework guarantees; only validate at system boundaries (user input, external API responses).

Python Version and Typing

  • Target: Python 3.11+. CI runs Python 3.12.
  • Type annotations are required on all public methods and function signatures.
  • Use Optional[X] for nullable types (do not use X | None — keep consistency with the existing codebase style).
  • Use Union[X, Y] for multi-type parameters.
  • Prefer list[X], dict[K, V], tuple[X, Y] built-in generics in new code (Python 3.9+); match the style of the surrounding file.
  • Use pathlib.Path for all file path operations. Never use raw string concatenation for paths.

Pydantic Models

  • All request body and response models must be defined as Pydantic BaseModel subclasses in app/schemas/.
  • Use Field(...) for required fields; use Field(default=...) or Field(None) for optional fields.
  • Do not define ad-hoc dict return types for API responses — define a schema class.
  • Settings and deployment configuration live in ConfigModel / Settings in app/core/config.py using pydantic-settings.
  • Use model_validator for cross-field validation logic.

Async and Concurrency

  • Prefer async def for I/O-bound operations (network requests, database queries, file operations).
  • Use await consistently; do not mix sync and async code paths in the same function without using run_in_threadpool from FastAPI or asyncio.to_thread.
  • For CPU-bound work that must not block the event loop, submit to ThreadHelper (see app/helper/thread.py).
  • Do not use bare threading.Thread in new code; use ThreadHelper.submit().

Imports

Order imports as follows, separated by blank lines:

  1. Standard library (import os, import json, etc.)
  2. Third-party packages (from fastapi import ..., from pydantic import ...)
  3. Local application packages (from app.chain import ..., from app.schemas import ...)

Within each group, sort alphabetically. Do not use wildcard imports (from module import *) in application code.


String Formatting

  • Use f-strings for all string interpolation. Do not use % formatting or .format().
  • For log messages, use logger.info(f"...") — do not use lazy %s format in logger calls (the project does not rely on lazy evaluation here).

Error Handling

  • In chain and module layers: do not raise HTTP exceptions. Catch exceptions, log them, and return None or a domain-level error object so the caller can decide how to proceed.
  • In endpoint layer: use FastAPI's HTTPException or the project's standard response schemas for errors.
  • Never swallow exceptions silently. At minimum log the error with logger.error(f"...: {str(err)}").
  • Do not use bare except: — always catch a specific exception type or at minimum Exception.
# Correct
try:
    result = self.do_work()
except Exception as err:
    logger.error(f"Failed to do work: {str(err)}")
    return None

# Wrong — swallowing silently
try:
    result = self.do_work()
except:
    pass

Logging

  • Use logger from app/log.py. Do not import the standard library logging directly in application code.
  • Log levels:
    • logger.debug(...) — detailed diagnostic information, disabled by default.
    • logger.info(...) — normal operational events.
    • logger.warning(...) — unexpected but recoverable situations.
    • logger.error(...) — failures that affect functionality.
  • Keep log messages in Chinese unless the surrounding file consistently uses English.

Constants and Magic Values

  • Do not scatter raw string keys for SystemConfig. Add a SystemConfigKey enum entry and reference it.
  • Do not use magic numbers or magic strings inline. Define a named constant or enum value.

File Organization

  • One primary class per file is the norm for chains, modules, and helpers.
  • Private helper functions in the same file are preferable to extracting a new helper for single-use logic.
  • Keep files focused on one domain concern.

What Not To Do

  • Do not introduce new third-party libraries without updating requirements.in and running pip-compile.
  • Do not use requests or httpx directly for external HTTP calls — use RequestUtils from app/utils/http.py.
  • Do not issue raw SQLAlchemy queries from chains, modules, or endpoints — use the *_oper.py classes.
  • Do not add TODO or FIXME without context. Only keep one if it is genuinely deferred and cannot be addressed in the current task.
  • Do not add noisy markers like # change starts here, # important, or # this is a fix.
  • Do not write comments that restate what the code already clearly says.

Last Updated: 2026-05-25