| name | python |
| description | Python coding standards for Scenescape — imports, indentation, patterns, and conventions. |
Python Coding Standards for Scenescape
Import Organization
Organize imports in this order:
- Standard library imports
- Third-party imports (external packages)
- Local application imports (scene_common, manager, controller, etc.)
import json
import os
from pathlib import Path
import numpy as np
from django.http import HttpResponse
from scene_common import log
from scene_common.geometry import Point
from manager.models import Scene
Naming Conventions
- Classes:
PascalCase (e.g., SceneController, RESTClient)
- Functions/Methods:
snake_case (e.g., get_scene_data, validate_message)
- Constants:
UPPER_SNAKE_CASE (e.g., TOPIC_BASE, CHUNK_SIZE)
- Private members: Prefix with single underscore
_ (e.g., _process_data, _internal_state)
Code Style
Linting & Formatting
Indentation
- Use 2 spaces (never tabs)
- Checked via
make indent-check
Line Length
- Target: 100 characters (soft limit)
- Hard limit: 120 characters
Docstrings
Use docstrings for classes and public methods:
def process_detection(self, detection_data):
"""Process detection data from sensor.
Args:
detection_data: Dictionary containing detection information
Returns:
Processed detection object or None on failure
"""
Django Patterns
Models
- Import from
scene_common for shared geometry/camera classes
- Use
ListField (from manager.fields) for list/array storage - provides database portability (PostgreSQL and non-PostgreSQL) and robust handling of edge cases
- Implement
__str__ for admin interface readability
from django.db import models
from scene_common.geometry import Region as ScenescapeRegion
from manager.fields import ListField
class Scene(models.Model):
name = models.CharField(max_length=255)
map = models.FileField(upload_to='maps/')
coordinates = ListField(default=list)
def __str__(self):
return self.name
Views
- Use class-based views for CRUD operations (
CreateView, UpdateView, DeleteView)
- Use
@login_required decorator for protected views
- Return
JsonResponse for AJAX endpoints
API Endpoints (Django REST Framework)
- Use serializers from
manager.serializers
- Implement custom permissions (e.g.,
IsAdminOrReadOnly)
- Return proper HTTP status codes
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class SceneAPI(APIView):
def get(self, request, scene_id):
return Response(data, status=status.HTTP_200_OK)
Scene Common Library Patterns
MQTT/PubSub
from scene_common.mqtt import PubSub
pubsub = PubSub(mqtt_auth, client_cert, root_cert, mqtt_broker, keepalive=60)
pubsub.onMessage = self.handle_message
pubsub.connect()
Schema Validation
from scene_common.schema import SchemaValidation
schema_val = SchemaValidation(schema_file)
if not schema_val.validateMessage("detector", message_data):
log.error("Validation failed")
REST Client
from scene_common.rest_client import RESTClient
client = RESTClient(rest_url, rest_auth, root_cert)
result = client.getScene(scene_id)
Logging
- Use f-strings for interpolated log messages.
- Do not use printf-style placeholders (for example
%s, %d) in log statements.
from scene_common import log
log.info("Processing started")
log.error(f"Failed to process scene {scene_id}")
log.debug(f"Debug information: {debug_payload}")
Type Hints
Use type hints for function signatures:
from typing import Optional, List, Dict, Union
from pathlib import Path
def process_images(
image_paths: List[Path],
config: Optional[Dict] = None
) -> Union[np.ndarray, None]:
pass
Error Handling
Use specific exceptions and log appropriately:
try:
result = dangerous_operation()
except FileNotFoundError as e:
log.error(f"File not found: {e}")
return None
except Exception as e:
log.error(f"Unexpected error: {e}")
raise
Performance Patterns
Avoid Deep Copies When Possible
data = original_data.copy()
data = copy.deepcopy(original_data)
Use List Comprehensions
results = [process(item) for item in items if item.valid]
results = []
for item in items:
if item.valid:
results.append(process(item))
Common Anti-Patterns to Avoid
❌ Don't use mutable default arguments:
def process(data, cache={}):
pass
def process(data, cache=None):
if cache is None:
cache = {}
❌ Don't catch bare exceptions unless re-raising:
try:
risky_operation()
except:
pass
try:
risky_operation()
except SpecificException as e:
log.error(f"Failed: {e}")
❌ Don't use from module import *:
from scene_common.geometry import *
from scene_common.geometry import Point, Region
Virtual Environment Setup
Development uses .venv in project root:
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements-runtime.txt
VS Code configuration should point to .venv/bin/python.
Dependencies
- Add to
requirements-runtime.txt for runtime dependencies
- Add to
requirements-build.txt for build-time dependencies
- Rebuild Docker image after dependency changes