Skip to content

Latest commit

 

History

History
98 lines (67 loc) · 4.67 KB

CONTRIBUTING.md

File metadata and controls

98 lines (67 loc) · 4.67 KB

Contributing

Setup

uv sync --all-extras --dev
git config core.hooksPath .githooks

The second command activates the shared pre-commit hook, which runs format, lint, and type-check before every commit.

Running tests

Tests run using bpy installed from pip (no need for Blender on PATH)

uv run pytest -n 4

The agent skill

src/nodebpy/skills/nodebpy/ is the source of the agent skill and ships in the wheel; skills/nodebpy/ at the repository root is the copy that npx skills add and the Claude Code marketplace (.claude-plugin/) read. After editing the source, run make skills to refresh the copy; a test fails when the two differ. Keep the skill in step with API changes in the same pull request, since it is what agents rely on for the current argument orders and method names: SKILL.md holds the loop, the core idioms and the errors table, and references/ one file per task. test_skill.py runs every Python block in it against the package, so an outdated example fails the tests.

Regenerating node classes

Most node classes under src/nodebpy/nodes/ are auto-generated from Blender's live node registry by the gen/ package (kept outside src/ so it never ships in the wheel). After a Blender / bpy version change, regenerate with:

make generate

which runs, in order:

  1. uv run python -m gen — regenerates the typed classes for Blender's bundled essentials asset libraries, then the node classes for every tree type
  2. make format — ruff format, ruff check --fix, and ty check --fix src

CI regenerates on every pull request and fails when the checked-in classes differ from the generator's output, so a change to gen/ ships with its regenerated classes. The generator imports the project's own nodebpy before bpy: Blender puts its extensions' site-packages first on the path when bpy loads, and a nodebpy installed there would otherwise shadow the sources being generated.

For faster iteration you can regenerate a single tree type:

uv run python -m gen --only geometry

(Geometry is always processed first because the shader and compositor trees re-export shared nodes from it.)

Inside gen/: config.py holds the per-tree-type configuration and the skip / hand-written / generate disposition for each node, customizations.py is the register_customization registry that layers generation-time mixins onto specific nodes, introspect.py inspects the live node registry, and model.py / emit.py / writers.py turn the results into module files.

The socket draw order table src/nodebpy/builder/_socket_order.py is generated separately, from Blender's C++ node declarations rather than the live registry: Blender draws nodes declared with use_custom_socket_order() in declaration order (inputs and outputs interleaved, aligned pairs sharing a row, buttons and panels where declared), which RNA does not expose. After a Blender version change regenerate it with

uv run python -m gen.socket_order            # sparse-clones the tag matching the installed bpy
uv run python -m gen.socket_order --source ~/src/blender   # or parse a local checkout

Nodes that need special handling are hand-written in src/nodebpy/nodes/*/manual.py (and the zone nodes in nodes/geometry/zone.py / nodes/shader/zone.py); the generator skips these and re-exports them alongside the generated classes.

Building the docs

The documentation is a Quarto site under docs/, with the API reference generated by quartodoc:

make docs

A note on bpy shadowing the repo package

Importing the pip bpy module prepends Blender's user extension site-packages (~/.config/blender/<ver>/extensions/.local/...) to sys.path. If a Blender extension bundles its own nodebpy wheel (MolecularNodes does), any process that imports bpy before nodebpy will silently import that bundled copy instead of the code in this repo — typically surfacing as AttributeErrors for APIs that exist in your working tree but not in the released wheel.

Two places already guard against this: tests/conftest.py re-inserts the repo's src/ at the front of sys.path, and docs/_environment points BLENDER_USER_EXTENSIONS / BLENDER_USER_SCRIPTS at nonexistent stubs so Quarto's render kernels never see the extension packages. For ad-hoc scripts, either import nodebpy before bpy or run with the same environment variables:

BLENDER_USER_EXTENSIONS=/nonexistent uv run python my_script.py

CI

Two GitHub Actions workflows run on every push and pull request:

  • lint.yml — ruff format check, ruff check, ty check (Ubuntu only, platform-independent)
  • tests.yml — pytest on macOS, Windows, and Ubuntu