mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-10-29 03:18:14 +08:00
Define multiline reStructuredText docstrings and item-level documentation for dataclasses, Pydantic models, and Protocols. Align agent instructions, review guidance, and development documentation. Validation: document links, Python example syntax, docstring format, and diff checks passed. The unchanged text-only architecture documentation test passed under isolated pytest with temporary CONFIG_DIR and no application bootstrap. Normal bootstrap remains unverified because the local environment lacks moviepilot_rust; installed uv also predates the project configuration format. No product code changed.
8.3 KiB
8.3 KiB
06 — Code Standards and Style
General Principles
- Preserve the surrounding implementation style. Comments and docstrings always follow 08 — Comments and Documentation Style, even when neighboring code uses an older style.
- 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.14+. Python 3.14 is the primary CI version; dependency CI also verifies supported platforms and both Linux runtime profiles.
- Type annotations are required on all public methods and function signatures.
- Use
Optional[X]for nullable types (do not useX | 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.Pathfor all file path operations. Never use raw string concatenation for paths.
Pydantic Models
- All request body and response models must be defined as Pydantic
BaseModelsubclasses inapp/schemas/. - Use
Field(...)for required fields; useField(default=...)orField(None)for optional fields. - Do not define ad-hoc
dictreturn types for API responses — define a schema class. - Settings and deployment configuration live in
ConfigModel/Settingsinapp/runtime/config.pyusingpydantic-settings. - Use
model_validatorfor cross-field validation logic. - Every Pydantic model requires a Chinese multiline class docstring, every declared model field requires a Chinese
Field(description=...), and validators and explicit methods require Chinese multiline docstrings. Ordinary#comments and class-level:param:entries do not replace Schema field descriptions. Comment migration must preserve defaults, constraints, aliases, and serialization behavior.
Comments and Structured Contracts
- All comment prose must be Chinese. Every docstring uses multiline triple double quotes with opening and closing delimiters on separate lines.
- Use
:param name:,:return:, and:raises ExceptionType:for parameters, results, and exceptions, not Google-styleArgs:/Returns:sections. - Every dataclass requires class and per-field documentation:
:param:for initialization inputs,:ivar:for non-initialization instance attributes, and:cvar:for class variables. Explicitly defined methods also require documentation. - Every Protocol requires documentation for its class, members, methods, and properties. Methods explain parameters, results, and applicable exceptions, side effects, and implementation constraints. Private types and test scaffolding are not exempt.
- Module headers, ordinary classes and functions, special Pydantic members, ordinary comments, and review requirements follow 08 — Comments and Documentation Style; do not introduce local formats.
Async and Concurrency
- Prefer
async deffor I/O-bound operations (network requests, database queries, file operations). - Use
awaitconsistently; do not mix sync and async code paths in the same function without usingrun_in_threadpoolfrom FastAPI orasyncio.to_thread. - For CPU-bound work that must not block the event loop, submit to
ThreadHelper(seeapp/runtime/thread.py). - Use
ThreadHelper.submit()for finite background work. A long-lived protocol loop may use a dedicatedthreading.Threadonly when its existing lifecycle owner signals and joins that child, while the external caller bounded-waits and retains the parent owner on non-convergence; do not create a dedicated thread pool for that exception.
Imports
Order imports as follows, separated by blank lines:
- Standard library (
import os,import json, etc.) - Third-party packages (
from fastapi import ...,from pydantic import ...) - 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%sformat 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
Noneor a domain-level error object so the caller can decide how to proceed. - In endpoint layer: use FastAPI's
HTTPExceptionor the project's standard response schemas for errors. - Application and adapter layers must not swallow operational failures silently. Log or re-raise them according to the owning contract. Foundation primitives do not log; they return their documented fallback value or raise, leaving operational reporting to the caller.
- Do not use bare
except:— always catch a specific exception type or at minimumException. logger.exception(...)records at ERROR level and includes the current traceback in console output by default. File and resource logs receive the formatted ERROR message through the usual routing. An explicitexc_infovalue follows standard-library logging semantics.
# 保留失败原因,便于定位外部调用问题
try:
result = self.do_work()
except Exception as err:
logger.error(f"Failed to do work: {str(err)}")
return None
# 错误示例:直接吞掉异常会掩盖失败原因
try:
result = self.do_work()
except:
pass
Logging
- Host code uses
loggerfromapp.runtime.log; new plugins useapp.sdk.logging. The historicalapp.logpath is compatibility-only. Do not import the standard libraryloggingdirectly 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 aSystemConfigKeyenum 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, services, and adapters.
- Private functions in the same file are preferable to extracting a new module for single-use logic.
- Add code to the canonical capability package that owns it, and extend an existing domain file whenever that domain already exists.
- Do not recreate generic
core,helper, orutilsbuckets; see05-architecture.mdfor placement rules. - New files use one focused lowercase noun. When the capability already names the package, put the role in a single-word child such as
plugin/manager.py; do not flatten it back intoplugin_manager.py. - Keep files focused on one domain concern.
What Not To Do
- Do not introduce new third-party libraries without placing them in the correct
pyproject.tomldependency group and updatinguv.lock: runtime packages belong in[project].dependencies, test/lint/build tooling in[dependency-groups].dev. - Do not use
requestsorhttpxdirectly for external HTTP calls - host code usesRequestUtilsfromapp/adapters/network/http.py; plugins useapp.sdk.network. - Do not issue raw SQLAlchemy queries or import Oper classes from chains, modules,
or endpoints. Define/consume an Application persistence Port; its concrete
implementation under
app/db/adapters/may use Oper classes fromapp/db/oper/. - 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-10-17