Skip to content

Lightweight data/VCML layer: lazy heavy deps + optional-dependency extras - #46

Merged
jcschaff merged 2 commits into
mainfrom
lightweight-data-layer
Jun 17, 2026
Merged

Lightweight data/VCML layer: lazy heavy deps + optional-dependency extras#46
jcschaff merged 2 commits into
mainfrom
lightweight-data-layer

Conversation

@jcschaff

Copy link
Copy Markdown
Member

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_geometry and 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__.py rewritten (PEP 562): the light data layer is eager (models, models_geometry, models_math, VcmlReader); heavy names (VcmlWriter, Field, SegmentedImageGeometry, VCellSession/connect/logout/simulate, and the utils/workspace helpers) are imported lazily on first access. A TYPE_CHECKING block 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].
  • Decouple libvcell from the data/reader path: every import 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-level sympy and sbml_spatial_model imports are likewise made lazy, so the light load_vcml_* helpers and field/utils import with core deps only.

Change B — optional-dependency extras

Core [project.dependencies] is now just lxml, numexpr, numpy, pydantic, typing-extensions. Everything else moved to [project.optional-dependencies]:

extra packages
solver pyvcell-fvsolver
viz vtk, pyvista, matplotlib, imageio, trame, trame-server, trame-vtk, trame-vuetify
remote requests, requests-oauth2client, urllib3, python-dateutil, overrides
io tensorstore, zarr, h5py, orjson, typer
convert antimony, python-libsbml, sympy
native libvcell
all union of all the above

pyvcell[all] is added to the dev dependency-group so uv sync/uv run (which include dev by default) keep the full feature set for dev/CI — no Makefile/CI command changes needed. (uv has no default-extras field; the dev-group self-reference is the version-portable idiom.) A [tool.deptry] DEP002 ignore 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)

$ uv pip install .            # core only
  installs: lxml, numexpr, numpy, pydantic(+core), typing-extensions/inspection  — and nothing else
$ python -c "from pyvcell.vcml.models_math import MathDescription; \
             from pyvcell.vcml.models_geometry import Geometry; \
             from pyvcell.vcml import VcmlReader; \
             bm = VcmlReader.biomodel_from_file('some.vcml'); import sys; \
             assert 'libvcell' not in sys.modules and 'vtk' not in sys.modules"
  -> reads VCML, math_description populated; no libvcell/vtk imported
$ python -c "import pyvcell.vcml as vc; vc.simulate"
  -> ModuleNotFoundError: … Install it with `pip install pyvcell[solver]`
  • New tests/vcml/test_lightweight_import.py: subprocess-isolated assertion that the data layer + reader pull no heavy modules, plus the helpful-error behavior.
  • make check green (ruff, mypy 310 files, deptry); pytest tests/vcml tests/sbml → 44 passed, 5 skipped.
  • Public API unchanged; pip install pyvcell[all] == today.

🤖 Generated with Claude Code

jcschaff and others added 2 commits June 17, 2026 17:24
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>
@jcschaff
jcschaff merged commit c71983c into main Jun 17, 2026
6 checks passed
@jcschaff
jcschaff deleted the lightweight-data-layer branch June 17, 2026 22:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant