Skip to content

Python environment engine + generic check_module() gate - #2

Merged
jefferis merged 4 commits into
mainfrom
env-engine
Aug 18, 2026
Merged

Python environment engine + generic check_module() gate#2
jefferis merged 4 commits into
mainfrom
env-engine

Conversation

@jefferis

Copy link
Copy Markdown
Member

Summary

Brings fafbseg's Python provisioning engine and module install/load gate into
nat.python, so the natverse ecosystem has one place to set Python up and one
generic way to check a module is usable. seatabler (and later fafbseg,
bancr) can then depend on nat.python for provisioning rather than on fafbseg.

Four logically discrete commits, each builds on its own:

  1. Drop dead reticulate guard in rids2pyint() — reticulate is a hard
    Imports dependency, so the requireNamespace() guard can never fire.
  2. Collapse py_module_info() to a single metadata-based introspector
    drop the import-based py_module_info() and the separate
    py_module_info2(); keep the metadata (no-import) implementation under the
    name py_module_info() (columns module/available/version).
    module_version() now reads metadata first and falls back to importing +
    __version__ only when metadata yields nothing, so versions still resolve
    for namespace/editable installs and when importlib.metadata is absent.
    Removes the now-unused python_module_path().
  3. Add the Python environment engine (simple_python, check_reticulate)
    ported near-verbatim from fafbseg's simple_python family, including the
    curated basic/full/extra bundles. Messaging uses cli rather than
    usethis; fafbseg.condaenvnat.python.condaenv (default
    r-reticulate). check_reticulate() collapses to a Python-availability gate.
    Reframes the Title/Description around managing Python for the natverse.
  4. Add generic check_module() install/load gate — installed-first /
    load-second ordering so a failed import of an installed module is reported
    as an environment problem (wrong Python) rather than a missing package.
    install = c("ask", "never", "always") gates only the install action, never
    the instructions. Results are memoised (cache = TRUE); simple_python()
    forgets that cache after an install. Package-specific checks (fafbseg's
    check_seatable etc.) become thin wrappers over this and need not memoise
    themselves.

Dependency changes

Adds cli, jsonlite, memoise to Imports.

Testing

Full suite green offline (check-module covers every decision branch by
mocking the Python-touching pieces; py_module_info/module_version tests pass
unchanged — numpy resolves via metadata, a bogus module via the import
fallback).

🤖 Generated with Claude Code

reticulate is a hard Imports dependency, so requireNamespace() can never
fail here; remove the guard.
Drop the import-based py_module_info() and the separate py_module_info2();
keep the metadata (no-import) implementation under the name py_module_info().
It reports module/available/version without importing, which is cheaper and
safe for modules with heavy or side-effecting imports.

module_version() now reads that metadata first and only falls back to
importing + __version__ (module_version_by_import) when metadata yields
nothing, so versions still resolve for namespace/editable installs and when
importlib.metadata is unavailable. The now-unused python_module_path() and
the dead reticulate guards in the introspectors are removed.
Port fafbseg's simple_python provisioning family into nat.python as the
ecosystem's shared entry point for setting up a managed miniconda Python
environment, including the curated basic/full/extra package bundles. Messaging
uses cli rather than usethis, and the fafbseg.condaenv option is generalised to
nat.python.condaenv (default r-reticulate). check_reticulate() collapses to a
Python-availability gate now that reticulate is a hard dependency.

Adds cli and jsonlite to Imports; reframes the Title/Description around managing
Python for the natverse (this package is opinionated about how the environment
should be set up, unlike bare reticulate).
A single entry point for code that needs a particular Python module: it checks
the module is installed (from distribution metadata, no import), imports it,
optionally enforces a minimum version, and on absence either installs it or
errors with actionable guidance. Ordered installed-first / load-second so a
failed import of an installed module is reported as an environment problem
(wrong Python) rather than a missing package.

install = c("ask", "never", "always") is self-documenting; instructions are
always shown, only the install action is gated. Results are memoised (cache =
TRUE) via check_module_impl, and simple_python() forgets that cache after an
install so later checks see newly installed packages. Package-specific checks
(fafbseg's check_seatable etc.) become thin wrappers over this and need not
memoise themselves.

Adds memoise to Imports.
@jefferis
jefferis merged commit bf9492f into main Aug 18, 2026
3 checks passed
@jefferis
jefferis deleted the env-engine branch August 18, 2026 15:05
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