General Principles
- Readability: Code should be clear and self-documenting.
- Consistency: Follow established patterns throughout the codebase.
- Type Safety: Use comprehensive type annotations.
- Modularity: Keep functions and classes focused on single responsibilities.
- Performance: Consider efficiency in compiler-related code.
File Structure and Organization
This section covers how to structure Python files, organize imports, and arrange code within modules to maintain clarity and consistency.File Headers
File Headers
All Python files must start with the standard copyright header:
Import Organization
Import Organization
Imports should be organized in the following order:
Module Structure
Module Structure
Prefer structuring modules sequentially:
Imports
We use specific imports rather than wildcards, always includefrom __future__ import annotations
when needed, and organize imports in four distinct groups with alphabetical ordering within each group. Related imports are grouped together, and we prefer absolute imports for clarity.
Import Style
Import Style
- Use
from __future__ import annotations
at the top of files that use forward references - Prefer specific imports over wildcard imports
- Group related imports together
- Use absolute imports for clarity
Naming Conventions
We usesnake_case
for variables and functions, PascalCase
for classes, UPPER_SNAKE_CASE
for constants, and single leading underscores for private members. Names should be descriptive and avoid abbreviations unless they’re well-known in the domain.
Variables and Functions
Variables and Functions
- Use
snake_case
for variables, functions, and module names - Use descriptive names that clearly indicate purpose
- Avoid abbreviations unless they’re well-known
Classes
Classes
- Use
PascalCase
for class names - Use descriptive names that indicate the class purpose
Constants
Constants
- Use
UPPER_SNAKE_CASE
for module-level constants - Group related constants together
Private Members
Private Members
- Use single leading underscore for internal functions/methods
- Use double leading underscore for name mangling when necessary
Function and Class Definitions
We requrie comprehensive type annotations on functions and classes. We use keyword-only arguments for optional parameters, and group logically.Function Signatures
Function Signatures
- Always include type annotations for parameters and return values
- Use keyword-only arguments for optional parameters when appropriate
- Group related parameters together
Class Definitions
Class Definitions
- Inherit from appropriate base classes (
ABC
,BaseModel
, etc.) - Use abstract methods when defining interfaces
- Include type annotations for class attributes
Type Annotations
We use comprehensive type annotations throughout the codebase. All function parameters, return types, and class attributes must be annotated.Basic Types
Basic Types
Use built-in types and typing module for annotations:
Union Types
Union Types
Use the pipe
|
syntax for union types (Python 3.10+):Generic Types
Generic Types
Make sure to specify type arguments for generic types:
Forward References
Forward References
Prefer using
from __future__ import annotations
for forward references over string annotations:Comments and Docstrings
We encourage the use of comments and docstrings to provide context around code.Docstrings
Docstrings
Use triple-quoted strings for docstrings. Follow Google-style format:
Inline Comments
Inline Comments
- Use comments sparingly for complex logic
- Prefer self-documenting code over comments
- Use
# CHECK
for areas that need review - Use
# INCOMPLETE
for unfinished functionality
Code Formatting
We write highly ergonomic code that is easy to both look at and reason about:Line Length
Line Length
- Maximum line length: 120 characters
- Break long lines using parentheses for natural grouping
Spacing
Spacing
- Use 4 spaces for indentation
- No trailing whitespace
- Single blank line between function and class definitions
- No spaces around
=
in keyword arguments
Block Comments
Block Comments
- Use comments to separate logical blocks within functions or methods instead of empty lines:
String Formatting
String Formatting
- Use f-strings for string interpolation
- Use double quotes for strings consistently
- Use triple double quotes for multiline strings
Error Handling
We encourage defining a small set of custom exception types that can be explicitly handled:Exception Classes
Exception Classes
- Create specific exception classes for different error types:
Error Messages
Error Messages
- Provide clear, actionable error messages
- Include context about what failed and why
Exception Handling
Exception Handling
- Catch specific errors when it makes sense to do so.
- When propagating errors from an exception handler, chain exceptions with
raise ... from ex
to preserve context.
Testing
Tests follow the Arrange-Act-Assert pattern with comments, and are organized in atest/
directory that mirrors the source code structure.
Test Structure
Test Structure
- Use descriptive test function names with
test_
prefix - Group related tests in classes
- Use clear assertions
Test Files
Test Files
- Test files should end with
_test.py
- Place tests in a
test/
directory - Mirror the source code structure in test organization
Dependencies
We prefer well-maintained packages with pinned versions for critical dependencies, use optional import patterns with try/except blocks for non-critical features, and favor relative imports for internal modules.External Dependencies
External Dependencies
- Prefer well-maintained, widely-used packages
- Pin versions for critical dependencies
- Use optional imports for non-critical features
Internal Dependencies
Internal Dependencies
- Use relative imports for internal modules
- Keep dependencies between modules minimal
- Avoid circular imports