Skip to main content
This document outlines the Python coding standards and conventions used across Muna.

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.
All Python files must start with the standard copyright header:
Imports should be organized in the following order:
Prefer structuring modules sequentially:

Imports

We use specific imports rather than wildcards, always include from __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.
  • 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
Example:

Naming Conventions

We use snake_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.
  • Use snake_case for variables, functions, and module names
  • Use descriptive names that clearly indicate purpose
  • Avoid abbreviations unless they’re well-known
  • Use PascalCase for class names
  • Use descriptive names that indicate the class purpose
  • Use UPPER_SNAKE_CASE for module-level constants
  • Group related constants together
  • 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.
  • Always include type annotations for parameters and return values
  • Use keyword-only arguments for optional parameters when appropriate
  • Group related parameters together
  • 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.
Use built-in types and typing module for annotations:
Use the pipe | syntax for union types (Python 3.10+):
Make sure to specify type arguments for generic types:
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.
Use triple-quoted strings for docstrings. Follow Google-style format:
  • 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:
  • Maximum line length: 120 characters
  • Break long lines using parentheses for natural grouping
  • Use 4 spaces for indentation
  • No trailing whitespace
  • Single blank line between function and class definitions
  • No spaces around = in keyword arguments
  • Use comments to separate logical blocks within functions or methods instead of empty lines:
  • 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:
  • Create specific exception classes for different error types:
  • Provide clear, actionable error messages
  • Include context about what failed and why
  • 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 a test/ directory that mirrors the source code structure.
  • Use descriptive test function names with test_ prefix
  • Group related tests in classes
  • Use clear assertions
  • 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.
  • Prefer well-maintained, widely-used packages
  • Pin versions for critical dependencies
  • Use optional imports for non-critical features
  • Use relative imports for internal modules
  • Keep dependencies between modules minimal
  • Avoid circular imports