Python Standards
Python Standards
Section titled “Python Standards”1. Package Management
Section titled “1. Package Management”- Tool:
poetryoruvfor dependency management. Lock files committed. - Virtual Environments: Always use isolated environments. Never install globally.
- Requirements:
pyproject.tomlfor modern projects.requirements.txtonly for legacy compatibility.
2. Code Style
Section titled “2. Code Style”- Formatter:
blackwith line length 100. Run viamake fmt. - Linter:
rufffor fast linting.pylintfor comprehensive analysis. - Type Checker:
mypyorpyrightin strict mode with zero errors. See Section 4 for full typing requirements.
Configuration
Section titled “Configuration”[tool.black]line-length = 100target-version = ['py311']
[tool.ruff]line-length = 100select = ["E", "F", "I", "N", "W", "UP"]
[tool.mypy]strict = truewarn_return_any = truewarn_unused_configs = true3. Naming Conventions
Section titled “3. Naming Conventions”- Modules:
snake_case.py - Classes:
PascalCase - Functions/Variables:
snake_case - Constants:
UPPER_SNAKE_CASE - Private:
_single_leading_underscore(module-level) - Name Mangling:
__double_leading_underscore(class-level, avoid unless necessary)
4. Type Hints — All Code Must Be Strongly Typed
Section titled “4. Type Hints — All Code Must Be Strongly Typed”Python code MUST be strongly typed throughout. This is not limited to public APIs — every function, method, variable declaration, class attribute, and return type requires explicit type annotations.
Requirements
Section titled “Requirements”-
All functions and methods: Parameter types and return types are mandatory — no exceptions. This includes private/internal functions.
-
Variables: Annotate variables when the type is not obvious from assignment. Always annotate empty collections,
None-initialized variables, and class attributes. -
mypy strict mode: Must pass with zero errors. The following
pyproject.tomlconfiguration is mandatory:[tool.mypy]strict = truewarn_return_any = truewarn_unused_configs = truedisallow_untyped_defs = truedisallow_incomplete_defs = truecheck_untyped_defs = truedisallow_any_generics = trueno_implicit_optional = truewarn_redundant_casts = truewarn_unused_ignores = true -
No
# type: ignorewithout an accompanying comment explaining why and a linked issue for resolution. -
No
Anywithout explicit justification in a comment. PreferobjectorUnknownpatterns. -
Style: Prefer
list[str]overList[str](Python 3.9+). Use|union syntax overUnion(Python 3.10+). -
Protocols: Use
Protocolfor structural subtyping instead of ABCs when appropriate. -
Generics: Use
TypeVarandGenericfor reusable type parameters.
Example
Section titled “Example”from typing import Protocol, TypeVar
T = TypeVar("T")
class Repository(Protocol[T]): def find_by_id(self, id: str) -> T | None: ... def save(self, entity: T) -> None: ...
# All functions — including private ones — must be fully typeddef _validate_email(email: str) -> bool: return "@" in email
class UserService: _cache: dict[str, User] # Class attributes must be typed
def __init__(self, repo: Repository[User]) -> None: self._cache = {}5. Project Structure
Section titled “5. Project Structure”package_name/├── __init__.py├── domain/│ ├── __init__.py│ ├── entities.py│ └── value_objects.py├── application/│ ├── __init__.py│ ├── use_cases.py│ └── interfaces.py└── infrastructure/ ├── __init__.py └── repositories.py6. Testing
Section titled “6. Testing”- Methodology: Test-Driven Development (TDD) is mandatory. Write failing tests before implementation code.
- Framework:
pytest. Use fixtures for test dependencies. - Coverage:
pytest-cov. 95% is the absolute minimum for any module. Target 100% for domain, 95%+ for application and infrastructure. - Regression: Every bug fix must include a regression test.
- Mocking:
unittest.mockorpytest-mock. Mock external dependencies only. - Local full-stack: Tests must be runnable locally without external dependencies. Use
testcontainersor in-memory substitutes.
Test Structure
Section titled “Test Structure”import pytestfrom domain.entities import User
def test_should_create_user_with_valid_email(): user = User(email="test@example.com", name="Test User") assert user.email == "test@example.com"7. Error Handling
Section titled “7. Error Handling”- Custom Exceptions: Define in domain layer. Inherit from domain base exception.
- Type: Use typed exceptions. No bare
except:clauses. - Context: Use
raise ... fromfor exception chaining.
class DomainError(Exception): """Base exception for domain layer.""" pass
class InvalidEmailError(DomainError): """Raised when email validation fails.""" pass8. Async/Await
Section titled “8. Async/Await”- Use When: I/O-bound operations (database, HTTP, file operations).
- Framework:
asynciofor core,aiohttp/httpxfor HTTP,asyncpg/aiomysqlfor databases. - Type Hints: Use
Coroutine,Awaitablefor return types.
9. Dependencies
Section titled “9. Dependencies”Common Libraries
Section titled “Common Libraries”- HTTP:
httpx(async),requests(sync) - Database:
sqlalchemy(ORM),asyncpg(async PostgreSQL) - Validation:
pydanticfor data validation and settings - Logging:
structlogfor structured logging
10. Documentation
Section titled “10. Documentation”- Docstrings: Google or NumPy style. Required for all public classes and functions.
- Type Info: Type hints preferred over docstring type annotations.
- Examples: Include usage examples in docstrings for complex functions.
def create_user(email: str, name: str) -> User: """Create a new user with validated email.
Args: email: Valid email address. name: User's full name.
Returns: User entity instance.
Raises: InvalidEmailError: If email format is invalid.
Example: >>> user = create_user("test@example.com", "John Doe") >>> user.email 'test@example.com' """ # Implementation