Lightweight data/VCML layer: lazy heavy deps + optional-dependency extras - #46
Merged
Conversation
Downstream consumers (e.g. vcell-fenics) need only pyvcell.vcml.models_* and VcmlReader, but today the whole solver/viz/remote/libvcell stack is forced on them. Three coordinated changes: A. Import light. __init__ eagerly re-exports only the light data layer (models, models_geometry, models_math, VcmlReader); heavy names (VcmlWriter, Field, SegmentedImageGeometry, session/remote/simulate, utils/workspace) load lazily (PEP 562) with a clear "install pyvcell[<extra>]" error when their optional dep is missing. Decouple libvcell from the data/reader path: every `import libvcell` (python_infix, utils, vcml_simulation, sbml_simulation) is now imported inside the function that uses it, and utils' module-level sympy / sbml_spatial_model imports are likewise lazy. B. Optional-dependency extras. Core [project.dependencies] is now just lxml/numexpr/numpy/pydantic/typing-extensions; everything else moved to extras: solver, viz, remote, io, convert, native, and all (= union). `pyvcell[all]` is added to the dev group so dev/CI keep the full set. C. Reader robustness (already landed in #44) — lenient physiology parse; the bundled corpus loads 100%. Verified in a clean venv with only core deps: importing the data models + VcmlReader and reading VCML pulls no libvcell/vtk/requests/trame; `pip install pyvcell` installs a tiny tree; `pip install pyvcell[all]` restores full behavior and the suite passes. make check green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The subprocess uses sys.executable + a literal code string (no untrusted input); add the same noqa as tests/guides/test_notebooks.py. (Local pre-commit cache had a stale ruff that missed it.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Goal
Make pyvcell's data models + VCML read/write usable as a lightweight, dependency-light layer, so downstream consumers (e.g. vcell-fenics) can
import pyvcell.vcml.models_math/import pyvcell.vcml.models_geometryand read VCML with only pydantic + lxml + numpy + numexpr installed — without dragging in the solver / viz / remote / libvcell stack.pip install pyvcell[all]reproduces today's behavior.Change A — import light
pyvcell/vcml/__init__.pyrewritten (PEP 562): the light data layer is eager (models,models_geometry,models_math,VcmlReader); heavy names (VcmlWriter,Field,SegmentedImageGeometry,VCellSession/connect/logout/simulate, and theutils/workspacehelpers) are imported lazily on first access. ATYPE_CHECKINGblock keeps static types/IDE autocomplete intact. When a heavy name's optional dependency is missing, the lazy import raises a clear error, e.g.pyvcell.vcml.simulate requires the optional dependency 'pyvcell_fvsolver' … Install it with pip install pyvcell[solver].libvcellfrom the data/reader path: everyimport libvcell(_internal/simdata/python_infix.py,vcml/utils.py,vcml/vcml_simulation.py,sbml/sbml_simulation.py) now lives inside the function that uses it.utils.py's module-levelsympyandsbml_spatial_modelimports are likewise made lazy, so the lightload_vcml_*helpers andfield/utilsimport with core deps only.Change B — optional-dependency extras
Core
[project.dependencies]is now justlxml,numexpr,numpy,pydantic,typing-extensions. Everything else moved to[project.optional-dependencies]:solvervizremoteioconvertnativeallpyvcell[all]is added to thedevdependency-group souv sync/uv run(which includedevby default) keep the full feature set for dev/CI — no Makefile/CI command changes needed. (uv has nodefault-extrasfield; the dev-group self-reference is the version-portable idiom.) A[tool.deptry] DEP002ignore covers that self-reference.Change C — reader robustness
Already landed in #44 (merged): the physiology visitors are lenient, so the bundled corpus loads 100% (was 77%). This branch includes that plus a spot-check (50/50) and the existing
test_reader_leniency.py.Verification (clean venv, core deps only)
tests/vcml/test_lightweight_import.py: subprocess-isolated assertion that the data layer + reader pull no heavy modules, plus the helpful-error behavior.make checkgreen (ruff, mypy 310 files, deptry);pytest tests/vcml tests/sbml→ 44 passed, 5 skipped.pip install pyvcell[all]== today.🤖 Generated with Claude Code