This document describes the coding standards and style guidelines for the Hornet Nest Locator project.
We use Ruff as our primary linting and formatting tool. Ruff is an extremely fast Python linter that combines the functionality of Flake8, isort, pyupgrade, and many other tools.
Configuration: See pyproject.toml for the complete Ruff configuration.
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"F", # Pyflakes
"W", # pycodestyle warnings
"I", # isort
"N", # pep8-naming
"UP", # pyupgrade
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"T20", # flake8-print
"PYI", # flake8-pyi
"PT", # flake8-pytest-style
"Q", # flake8-quotes
"RUF", # Ruff-specific rules
"SIM", # flake8-simplify
"TID", # flake8-tidy-imports
"ARG", # flake8-unused-arguments
"PLC", # pylint-convention
"PLE", # pylint-error
"PLW", # pylint-warning
]- Maximum: 100 characters
- Rationale: Balances readability with modern screen sizes
- Style: 4 spaces (no tabs)
- Consistency: Enforced by Ruff formatter
- Strings: Double quotes (
"") preferred - Docstrings: Double quotes (
"""""") - Multiline: Double quotes
- Organization: Automatic sorting by isort
- Grouping: Standard library → Third-party → First-party → Local
- Combining: Related imports combined when possible
# Variables and functions
snake_case = "use_snake_case"
# Constants
CONSTANT_NAME = "UPPER_SNAKE_CASE"
# Classes
class ClassName:
pass
# Methods
class MyClass:
def method_name(self):
pass
# Modules
module_name.py- Single Responsibility: Each function should do one thing
- Length: Keep functions focused and concise
- Documentation: Use docstrings for public functions
- Type Hints: Use Python type hints where appropriate
# Good: Specific exception handling
def safe_divide(a: float, b: float) -> float:
try:
return a / b
except ZeroDivisionError:
logger.error("Division by zero attempted")
return float('inf')
# Avoid: Bare except clauses
def bad_example():
try:
risky_operation()
except: # Too broad!
pass| Rule | Description | Example |
|---|---|---|
F401 |
Unused import | import unused_module |
E501 |
Line too long | very_long_line = "..." * 200 |
F841 |
Unused variable | x = 42 (never used) |
B008 |
Function call in default | def func(arg=expensive_call()): |
C901 |
Complex function | Functions with high cyclomatic complexity |
# ✅ Good: Use context managers
with open("file.txt") as f:
content = f.read()
# ❌ Bad: Manual resource management
f = open("file.txt")
content = f.read()
f.close()
# ✅ Good: List comprehensions
squares = [x**2 for x in range(10)]
# ❌ Bad: Unnecessary loops
squares = []
for x in range(10):
squares.append(x**2)
# ✅ Good: f-strings (Python 3.6+)
message = f"Value: {value}"
# ❌ Bad: Old-style formatting
message = "Value: %s" % value# Good test structure
class TestCalculator:
def test_empirical_method(self):
"""Test empirical distance calculation."""
observation = Observation(latitude=48.8584, longitude=2.2945,
bearing=45.0, round_trip_time=390)
assert observation.estimated_distance_empirical == 650.0
def test_theoretical_method(self):
"""Test theoretical distance calculation."""
observation = Observation(latitude=48.8584, longitude=2.2945,
bearing=45.0, round_trip_time=300, speed=7.0)
assert observation.estimated_distance_theoretical == 1050.0- Test classes:
Test*prefix (e.g.,TestCalculator) - Test methods:
test_*prefix (e.g.,test_empirical_method) - Descriptive names: Clearly indicate what's being tested
"""
Calculate hive location from hornet observations.
Uses the professional empirical method from Vespawatchers:
100 meters = 1 minute round trip time
Args:
observation: Single hornet observation with all required data
method: "empirical" (recommended) or "theoretical"
Returns:
HiveLocation with estimated coordinates and confidence
Raises:
ValueError: If method is unknown or speed is missing for theoretical method
""""""
Geographic calculation utilities using haversine formula.
This module provides functions for:
- Calculating destination points given bearing and distance
- Computing great circle distances between coordinates
- Formatting geographic coordinates for display
- Converting between different coordinate representations
"""# Check formatting
ruff format --check .
# Run linter
ruff check .
# Fix formatting issues automatically
ruff format .
# Run tests
pytest tests/ -vThe project uses GitHub Actions for continuous integration:
- Format Check: Ensures code follows formatting rules
- Linting: Catches code quality issues
- Testing: Runs all unit tests
- Type Checking: Optional mypy type checking
VS Code:
{
"python.linting.enabled": true,
"python.linting.lintOnSave": true,
"python.linting.provider": "ruff",
"python.formatting.provider": "ruff",
"editor.formatOnSave": true
}PyCharm:
- Install Ruff plugin
- Set as default linter and formatter
- Enable "Reformat on Save"
To maintain code quality:
- Run Ruff before committing:
ruff check . && ruff format . - Write tests: For new features and bug fixes
- Follow conventions: Use existing code as reference
- Document changes: Update docstrings and comments
- Keep it simple: Prefer readability over cleverness
"Code is read more often than it is written. Write for readability first."
This style guide helps maintain consistency across the codebase, making it easier for conservation workers and developers to understand, maintain, and extend the Hornet Nest Locator application.