All Python code is formatted with Black using default settings:
- Line length: 88 characters
- Target Python version: Python 3.8+
- String normalization: enabled
# Format a file
black path/to/file.py
# Check format without changing files
black --check path/to/file.py
# Format entire project
black .Imports are sorted with isort using the following profile:
- Profile: black (compatible with Black formatter)
from __future__ import annotationsfirst- Standard library imports
- Third-party imports
- First-party (
scratchv.*) imports
# Sort imports
isort path/to/file.py
# Check imports
isort --check-only path/to/file.pyRuff is used for fast linting, replacing flake8:
- All pycodestyle (E, W) rules
- All Pyflakes (F) rules
- isort compatibility (I001)
- Unused variables and imports
# Check for issues
ruff check .
# Auto-fix issues
ruff check --fix .mypy is configured for strict type checking:
- Python 3.8+ target
- Strict optional checked
- Disallow untyped defs
- Warn on return Any
- Follow imports
# Run mypy
mypy scratchv/
# Run on specific module
mypy scratchv/frontend/dsl_parser.pyscratchv/
__init__.py # Version info
frontend/ # DSL and ONNX parsers
ir/ # IR types, builder, printer
optimizer/ # Optimization passes
analysis/ # CFG analysis, IR verification
backend/ # Code generation (RISC-V, LLVM)
verification/ # Runtime verification
simulator/ # RISC-V and TinyFive simulators
codegen/ # Code generation interfaces
utils/ # Logging and utilities
Always use absolute imports with the scratchv.* path:
# Correct
from scratchv.ir.types import Program, Function, OpCode
from scratchv.frontend.dsl_parser import DSLParser
# Incorrect (relative imports)
from .dsl_parser import DSLParser
from ..ir.types import ProgramEvery module should have a docstring describing its purpose:
"""Brief description of the module.
Longer description of the module's purpose, key classes, and usage examples.
"""Use type hints for all public functions and methods:
def parse(self, text: str) -> Program:
"""Parse DSL text into IR Program.
Args:
text: The DSL source code as a string.
Returns:
A Program object containing the generated IR.
"""- Use custom exception classes for domain-specific errors
- Provide clear, actionable error messages
- Include location information (line, column) where applicable
| Element | Convention | Example |
|---|---|---|
| Modules | snake_case | dsl_parser.py |
| Classes | PascalCase | DSLParser |
| Functions/Methods | snake_case | parse_if_block() |
| Variables | snake_case | label_counter |
| Constants | UPPER_SNAKE | MAX_ERRORS |
| Private members | _underscore prefix | _vars, _resolve() |
- Tests go in the
tests/directory - Use pytest with class-based test organization
- Test file names:
test_<module>.py - Test method names:
test_<feature>()
from scratchv.frontend.dsl_parser import DSLParser
class TestDSLParser:
def test_parse_simple_add(self):
dsl = "c = add(a, b)\nreturn c\n"
parser = DSLParser()
program = parser.parse(dsl)
assert len(program.functions[0].blocks[0].instructions) == 2Install hooks before your first commit:
pip install pre-commit
pre-commit installHooks run automatically on git commit. To run manually:
pre-commit run --all-files# Install dev dependencies
pip install black isort ruff mypy pre-commit
# Install pre-commit hooks
pre-commit install
# Format and lint
./scripts/lint_check.sh
# Or manually
black .
isort .
ruff check .
mypy scratchv/The CI pipeline runs:
ruff check .- Lintmypy scratchv/- Type checkblack --check .- Format checkisort --check-only .- Import order checkpytest tests/- Testspython benchmarks/bench_runner.py- Benchmarks