| Title: | Manage Python Environments in R with uv |
|---|---|
| Description: | Provides uv-backed Python virtual-environment management for the fyr ecosystem (reportifyr, presentifyr R packages). |
| Authors: | Jacob Dumbleton [aut, cre], Matthew Smith [aut] |
| Maintainer: | Jacob Dumbleton <[email protected]> |
| License: | GPL (>= 3) |
| Version: | 0.1.1 |
| Built: | 2026-07-14 22:43:44 UTC |
| Source: | https://github.com/a2-ai/pyro |
Single canonical resolver for "where does this project live?". Used as
the default for pyproject_dir and venv_dir in
initialize_python(), and as a base for sibling-package wrappers that
need to locate the project's pyproject.toml.
get_proj_dir()get_proj_dir()
Resolution order:
getOption("venv_dir") if set (cached project root, written by
prior calls to initialize_python()).
here::here() otherwise.
Absolute path to the project root.
## Not run: get_proj_dir() ## End(Not run)## Not run: get_proj_dir() ## End(Not run)
Searches PATH first, then known install locations
(~/.local/bin/uv, ~/.cargo/bin/uv) cross-platform. Respects the
HOME environment variable for test isolation.
get_uv_path(quiet = FALSE)get_uv_path(quiet = FALSE)
quiet |
If |
Use this to detect whether uv is installed without triggering an
install. initialize_python() performs the install; this helper is
a pure lookup.
Path to the uv executable, or NULL if none is found.
## Not run: uv_path <- get_uv_path() if (is.null(uv_path)) message("uv not installed yet") ## End(Not run)## Not run: uv_path <- get_uv_path() if (is.null(uv_path)) message("uv not installed yet") ## End(Not run)
Shells out to uv --version and parses the result. Useful for
diagnostics and for callers that need to gate behavior on the uv
version (e.g. only set a flag introduced in a specific release).
get_uv_version(uv_path)get_uv_version(uv_path)
uv_path |
Path to the uv executable. Typically obtained from
|
Character scalar of the uv version (e.g., "0.7.8").
## Not run: uv_path <- get_uv_path() if (!is.null(uv_path)) get_uv_version(uv_path) ## End(Not run)## Not run: uv_path <- get_uv_path() if (!is.null(uv_path)) get_uv_version(uv_path) ## End(Not run)
.venv directoryLooks up the project root via get_proj_dir() (which reads
getOption("venv_dir"), falling back to here::here()) and caches
the resolved root in options("venv_dir") so subsequent calls are
cheap.
get_venv_uv_paths()get_venv_uv_paths()
Named list with uv (path to uv) and venv (path to the
.venv/ directory).
## Not run: get_venv_uv_paths() ## End(Not run)## Not run: get_venv_uv_paths() ## End(Not run)
Ensures uv is installed at uv_version, then locks and syncs the
project's .venv/ against <pyproject_dir>/pyproject.toml. If no
pyproject.toml exists at pyproject_dir, one is seeded from
pyro's bundled spec (templated with the project's directory
name) before lock and sync.
initialize_python( continue = NULL, venv_dir = get_proj_dir(), uv_version = getOption("uv.version"), groups = NULL, pyproject_dir = NULL )initialize_python( continue = NULL, venv_dir = get_proj_dir(), uv_version = getOption("uv.version"), groups = NULL, pyproject_dir = NULL )
continue |
Optional. |
venv_dir |
Parent directory of |
uv_version |
Version of uv to install. Defaults to
|
groups |
Character vector of dependency-group names from the
project's |
pyproject_dir |
Directory containing the project's
|
The project's pyproject.toml is the source of truth. pyro
seeds it on first call but never modifies an existing toml, group
upserts are the responsibility of sibling-package wrappers via
write_group_to_pyproject().
Invisibly NULL.
## Not run: initialize_python() # all groups initialize_python(groups = "reportifyr") # only reportifyr's group initialize_python(groups = "presentifyr") # only presentifyr's group initialize_python(pyproject_dir = "~/proj") # custom project root ## End(Not run)## Not run: initialize_python() # all groups initialize_python(groups = "reportifyr") # only reportifyr's group initialize_python(groups = "presentifyr") # only presentifyr's group initialize_python(pyproject_dir = "~/proj") # custom project root ## End(Not run)
Provides uv-backed Python virtual-environment management used across
the fyr ecosystem (reportifyr, presentifyr). Wraps the uv CLI via
processx for locating the uv binary, bootstrapping a .venv/,
installing pinned Python dependencies, and running Python scripts.
All exported functions are part of the public API and may be called directly by sibling fyr packages and third-party projects.
initialize_python: Bootstraps uv (if missing),
creates a .venv/, and installs the requested Python packages.
write_group_to_pyproject: Idempotent merge
helper for sibling and third-party packages to wire their Python
dependency group into the project's pyproject.toml.
get_proj_dir: Project-root resolver (reads
getOption("venv_dir") then falls back to here::here()).
get_venv_uv_paths: Resolves the paths to the uv
binary and the project's .venv/ directory. Used by host packages
before invoking Python scripts.
run_python_script: Invokes a Python script
inside the uv-managed venv via processx.
get_uv_path, get_uv_version: uv
binary resolution and version detection.
pyro writes log lines through an internal log4r logger whose
threshold is read from getOption("pyro.verbose", "WARN") on
each emission. To change verbosity, set the option
options(pyro.verbose = "DEBUG"). No reload or toggle call is
required; the next log call reflects the new level. Use
withr::with_options(list(pyro.verbose = "DEBUG"), ...) to scope a
verbose level to a single block.
Maintainer: Jacob Dumbleton [email protected]
Authors:
Matthew Smith [email protected]
Shells out to uv via processx::run() with the venv's VIRTUAL_ENV
and (optionally) a caller-supplied PYTHONPATH. pyro does not
persist subprocess output to any file — routing of the Python
subprocess' stderr is entirely the caller's concern. Supply
stderr_callback to capture, reformat, or filter stderr lines; wrap
this call in tryCatch() if you want to act on a subprocess crash.
run_python_script( uv_path, args, venv_path, script_name, pythonpath = NULL, stderr_callback = NULL, verbose_env = NULL )run_python_script( uv_path, args, venv_path, script_name, pythonpath = NULL, stderr_callback = NULL, verbose_env = NULL )
uv_path |
Path to the uv executable. |
args |
Arguments to pass to uv (e.g., |
venv_path |
Path to the |
script_name |
Human-readable label used in the error message. |
pythonpath |
Optional directory to expose as |
stderr_callback |
Optional |
verbose_env |
Optional name of an environment variable to surface to the subprocess (for example, the caller's verbosity control). |
The result from processx::run().
## Not run: paths <- pyro::get_venv_uv_paths() pyro::run_python_script( uv_path = paths$uv, venv_path = paths$venv, args = c("run", "-m", "my_module"), script_name = "my_module" ) ## End(Not run)## Not run: paths <- pyro::get_venv_uv_paths() pyro::run_python_script( uv_path = paths$uv, venv_path = paths$venv, args = c("run", "-m", "my_module"), script_name = "my_module" ) ## End(Not run)
pyproject.toml
Idempotent merge helper called by sibling-package wrappers
(reportifyr, presentifyr) and third-party apps to wire their Python
dependency group into the project's pyproject.toml.
write_group_to_pyproject(name, deps = NULL, pyproject_dir = get_proj_dir())write_group_to_pyproject(name, deps = NULL, pyproject_dir = get_proj_dir())
name |
Character group name (e.g. |
deps |
Optional character vector of dependency strings
(e.g. |
pyproject_dir |
Directory containing the project's
|
Merge semantics by case:
pyproject.toml
No-op, returns FALSE. Seeding is
initialize_python()'s job; this helper composes with it but
does not duplicate it.
[dependency-groups] tableAppend the table containing
name. Returns TRUE.
name subgroupAppend the subgroup with
deps. Returns TRUE.
Per-dep version comparison.
If versions match: no-op, returns FALSE. If versions differ:
keep the user's pin (do not overwrite), emit a one-line message
per diff. Returns FALSE.
Add any deps missing from
the project's group with the spec's pins. Never remove deps the
user added. Returns TRUE.
The "spec" is pyro's bundled pyproject.toml for fyr-blessed
groups (when deps = NULL), or the caller-supplied deps for
third-party apps.
Invisibly, TRUE if the toml was mutated, FALSE otherwise.
## Not run: # fyr-blessed group: pins read from bundled spec write_group_to_pyproject("reportifyr") # third-party app: pins supplied explicitly write_group_to_pyproject("myapp", deps = c("requests==2.31.0")) ## End(Not run)## Not run: # fyr-blessed group: pins read from bundled spec write_group_to_pyproject("reportifyr") # third-party app: pins supplied explicitly write_group_to_pyproject("myapp", deps = c("requests==2.31.0")) ## End(Not run)