Developer Guide
Tool Script Standards

Tool Script Standards

Dexter tool scripts follow PEP 8 (opens in a new tab) and are linted with Ruff (opens in a new tab).

Layout

tool_scripts/
  common.py              # shared I/O, config, validation helpers (+ JSON schema CLI)
  <name>.py                # one entrypoint per pipeline step
  blender_<name>.py        # scripts run inside Blender (import bpy)
  • Put reusable logic in common.py; keep entrypoint scripts thin.
  • Blender scripts must not import non-Blender dependencies beyond common.py.

Naming

KindStyleExample
Modulessnake_caseinitialize_placement.py
Functionssnake_case, verb-firstload_json_file, validate_schema
Variablessnake_case, descriptiveparent_world_size, not pW
ConstantsUPPER_SNAKE_CASEREPO_ROOT, DEFAULT_CONFIG_PATH
Private helpersleading __rotate_scaled_center
CLI flags--kebab-case--run-dir, --prev-assembly

Avoid abbreviations (jt, hs, pi, ax_idx) and Hungarian prefixes. Use full words unless the domain term is standard (glb, usd, json).

Types and imports

  • Start every module with from __future__ import annotations.
  • Add return types on public functions; use dict[str, Any] for JSON blobs.
  • Order imports: stdlib → third-party → local (common).
  • Type-check Blender imports with # type: ignore[import-not-found].

CLI entrypoints

Every script exposes:

def main() -> None:
    ...
 
if __name__ == "__main__":
    main()
  • Use argparse; document usage in the module docstring.
  • Resolve paths with Path(...).expanduser().resolve().
  • Missing inputs: exit_if_missing() for CLI tools, or raise FileNotFoundError in library code.
  • Validate JSON inputs against schemas/ before processing; validate outputs before finishing. On KeyError / ValueError from placement math, exit with Error: … so agents can fix the source file.
  • Blender scripts parse argv after -- via parse_blender_args().

JSON and config

  • Read: load_json_file(path)
  • Write: write_json_file(path, data) (indent 2, trailing newline, UTF-8)
  • Config: load_yaml_config() from configs/base.yaml
  • Component dims: load_dims_map(data) or load_dims_file(run_dir)
  • Validation: validate_schema(name, path) at script entry (calls exit_if_invalid_json with fix hints); CLI: python3 tool_scripts/common.py --schema … --data … (fixtures in test_fixtures/)
  • Placement math: recompute_blender_transforms() in common.py (used by initialize_placement.py and update_placement.py)

User-facing output

Keep stdout minimal and consistent:

EventMessage
Artifact writtenWrote {path}
Skipped existing fileskip (exists): {path}
Validation passOK: {path}
Validation failINVALID: {path} + indented errors
Recoverable warningWarning: … on stderr

No progress or debug logging unless explicitly requested.

Formatting and lint

ruff check tool_scripts/
ruff format tool_scripts/

Configuration lives in pyproject.toml at the repo root. Run both commands before committing script changes.