stroblme 091a2ad0cf Housekeeping ahead of the Inc 1-4 coverage work
- inventory.py --methods: report the instance methods the app calls per class,
  plus chained calls that constrain a return type. --check says which classes
  to bind; this says what to bind on them, which is what writing ~38 module
  TUs needs.
- Drop StlAPI from the inventory: StlAPI_Writer has no app call site (the only
  use was a test fixture, now on the app's own STL writer). 138 symbols / 47
  modules.
- adding-symbols.md: scope the executing-constructor ban to the BRepAlgoAPI
  booleans, which are the only classes with a deferred Set*/Build form —
  BRepMesh_IncrementalMesh, GeomAPI_*, BRepCheck_Analyzer and friends compute
  in their constructor by design and bind as stock. Replace the per-increment
  app-test guidance: backend/tests/conftest.py imports n3xd.main, so no app
  test can collect until the last module is bound. Increments gate on
  stock-recorded fixtures here; the app suite is the Inc 4 gate.
- parity_venv.sh: run the ocp suite in the swapped venv (it imports only
  OCP/n3xd_ocp, so it works throughout).
- Fix a stale macro name in occt_handle.h (ocp_new, not OCP_TRANSIENT_NEW) and
  drop the unused ocp_transient_class helper.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DfriM8XUkn7uYf5Dwe2xo6
2026-08-10 19:23:27 +02:00
up
2026-08-10 17:18:21 +02:00

n3xd-ocp

Hand-written nanobind bindings for the OpenCASCADE (OCCT) geometry kernel, covering exactly the surface the N3XD CAD backend uses — 139 symbols across 48 OCP.* modules, not all of OCCT.

The package installs as a top-level OCP, so it is a drop-in replacement for cadquery-ocp-novtk and the app's 442 import sites stay untouched.

Status: Inc 0 (spike) shipped — build system, OCCT builder image, handle model, and the first module surface (gp, TopAbs, TopoDS, TopExp, TopLoc, TopTools, BRep, BinTools, Poly, Standard), published as 7.9.3.1.dev1. BREP serialisation is byte-identical to the stock wheel, which is the gate that mattered: the pools and the content-addressed derive payloads both depend on it. Coverage is 34 of the 139 symbols the app imports; the rest lands in increments 1-4 (roadmap 10C).

Start with docs/design.md for the decisions, docs/building.md to build one, and docs/adding-symbols.md to extend the surface. The phase plan lives in the app repo at docs-private/reference/roadmap.md (Phase 10).

Why

cadquery-ocp lags OCCT (it wraps 7.9.3; OCCT 8.0 shipped 2026-05), builds Windows and macOS wheels we never use, and until recently forced a 638 MB VTK dependency into the image. Binding call overhead is not a bottleneck — the CAD hotspots live inside the C++ kernel — so this exists for version velocity, footprint, and two defects that a binding we control prevents by construction:

  • OCCT sub-shapes are returned by value, so a wrapper can never alias a TShape whose owner has died (this segfaulted a process-global face memo).
  • Executing constructors (the two-argument BRepAlgoAPI_* forms) are not bound, so the double-execution footgun is unrepresentable.

It also releases the GIL around kernel calls and ships type stubs, neither of which upstream does.

Build

OCCT is compiled once into a builder image and reused; it is never built on the production host (4 cores, and a kernel build is multi-hour). Wheels are built here on a dev box and published to the Gitea package registry.

make image    # once, ~40 min: compiles OCCT 7.9.3 into the builder image
make dev      # inner loop: incremental compile + tests
make wheel    # compile, stubs, auditwheel, self-containment smoke test
make publish  # -> https://git.stroblme.de/api/packages/N3XD/pypi

Credentials go in .secrets (gitignored) as UV_PUBLISH_USERNAME / UV_PUBLISH_PASSWORD. Consumers read anonymously — the package is public:

uv pip install --index-url https://git.stroblme.de/api/packages/N3XD/pypi/simple/ \
    --prerelease=allow n3xd-ocp

Versions are <occt-version>.N, enforced at configure time against the OCCT actually found, so the kernel a wheel wraps is readable from its version alone. The registry refuses to republish a version; iteration builds therefore carry a .devN suffix and are the only ones the registry's cleanup rule collects.

Description
No description provided
Readme 273 KiB
Languages
C++ 59.6%
Python 34.2%
Shell 3.2%
Dockerfile 1.2%
CMake 0.9%
Other 0.9%