Skip to content

yggdrasil.environ.environment

environment

Python environment management with uv-first toolchain.

:class:PyEnv wraps a single Python interpreter path and provides:

  • Resolution — locate interpreters by path, version selector, or venv dir.
  • Virtual-env lifecycle — create, delete, and reuse virtual environments via uv venv (with automatic uv bootstrap).
  • Package management — install / update / uninstall via uv pip or python -m pip with private-API fallback.
  • Subprocess execution — run Python code under uv run or bare Python.
  • Runtime imports — import-or-install a module at call time.

The module prefers uv for all pip and subprocess operations but falls back to plain pip / python transparently when uv is unavailable.

Public API

.. autosummary::

PyEnv safe_pip_name runtime_import_module

PyEnv dataclass

PyEnv(
    python_path: Path,
    cwd: Path = (lambda: Path.cwd())(),
    prefer_uv: bool = True,
)

Thin wrapper around a single Python interpreter path.

:class:PyEnv is the central primitive for environment-related operations: package management (install / update / uninstall), subprocess execution, and dynamic imports with auto-install.

Design constraints
  • python_path is the sole interpreter anchor — no explicit venv_dir is stored.
  • All operations are working-directory–relative via cwd.
  • When prefer_uv=True (default), uv is preferred for pip operations and subprocess execution, but calls fall back to plain pip / python when uv is unavailable.
Execution strategy
  • prefer_uv=True -> uv run --python <python_path> python ...
  • prefer_uv=False -> <python_path> ...

is_current property

is_current: bool

True when this instance is the module-level :data:CURRENT_PYENV singleton.

is_windows property

is_windows: bool

True when running on Windows (os.name == 'nt').

bin_path property

bin_path: Path

Directory containing the Python executable (Scripts on Windows, bin elsewhere).

root_path property

root_path: Path

Parent of :attr:bin_path — typically the venv root.

userinfo property

userinfo: UserInfo

Return the current :class:~yggdrasil.environ.userinfo.UserInfo.

version_info property

version_info: VersionInfo

Return the interpreter version for this environment.

uv_path property

uv_path: Path

Resolve the uv command, installing it into the runtime interpreter if needed.

resolve_python_executable staticmethod

resolve_python_executable(python: str | Path | None) -> Path

Resolve a Python selector to an absolute executable path.

Accepts: * None -> sys.executable * Path to an executable * version selectors such as '3.12' or 'python3.12' * directory paths containing a Python executable * raw executable paths

current classmethod

current(*, python: str | Path | None = None, prefer_uv: bool = True) -> PyEnv

Return the module-level singleton for the current interpreter.

get_or_create classmethod

get_or_create(
    identifier: str | Path | PyEnv | None = None,
    *,
    version: str | None = None,
    packages: list[str] | None = None,
    prefer_uv: bool = True,
    seed: bool = True,
    cwd: Path | None = None
) -> PyEnv

Resolve or create a Python environment from a flexible identifier.

venv

venv(
    identifier: str | Path | None,
    *,
    cwd: Path | None = None,
    prefer_uv: bool = True,
    seed: bool = True,
    version: str | None = None,
    packages: list[str] | None = None
) -> PyEnv

Resolve an environment identifier or create a venv when needed.

create

create(
    folder: Path | str,
    *,
    cwd: Path | None = None,
    prefer_uv: bool = True,
    seed: bool = True,
    version: str | None = None,
    packages: list[str] | None = None,
    linked: bool = False,
    native_tls: bool = True,
    wait: WaitingConfigArg = True,
    clear: bool = True
) -> PyEnv

Create a new virtual environment at folder via uv venv.

in_databricks_notebook classmethod

in_databricks_notebook() -> bool

True when running inside a Databricks notebook cell.

Notebook execution drives Python via an IPython kernel; a Databricks job's plain entry point does not. The combination of DATABRICKS_RUNTIME_VERSION + a live IPython instance is the standard heuristic — the same signal dbutils itself uses to surface its notebook-only helpers.

in_aws_lambda classmethod

in_aws_lambda() -> bool

True when running inside the AWS Lambda runtime.

AWS_LAMBDA_FUNCTION_NAME is set on every Lambda invocation by the runtime bootstrap and is documented as reserved — it is not user-settable and never leaks to non-Lambda environments, making it the canonical detector.

in_aws_batch classmethod

in_aws_batch() -> bool

True when running inside an AWS Batch job container.

AWS_BATCH_JOB_ID is injected into every Batch container by the Batch agent and is the canonical detector.

in_aws classmethod

in_aws() -> bool

True when running on an AWS-managed compute surface.

Detects AWS Lambda, AWS Batch, AWS ECS / Fargate, and AWS CodeBuild via the env vars those services inject. Bare EC2 is not covered — there's no environment-side signal for it (callers needing that should hit IMDS).

should_use_databricks_connect classmethod

should_use_databricks_connect() -> bool

True when the caller is outside Databricks but configured to reach a workspace.

Inside Databricks runtime the regular SparkSession is already wired by the runtime — no Connect needed. Outside Databricks, the presence of DATABRICKS_HOST is the canonical signal that the caller wants to talk to a remote workspace; the SDK reads the same env vars to resolve auth and target compute.

spark_session classmethod

spark_session(
    obj: Any = None,
    *,
    create: bool = False,
    connect: bool | None = None,
    import_error: bool = False,
    install_spark: bool = False,
    install_java: bool = False,
    local_setup: bool = True,
    extra_config: dict[str, str] | None = None
) -> "SparkSession | None"

Return a cached SparkSession, creating one if needed.

Resolution order: 1. Return the cached session if already resolved. 2. Decide Connect vs local based on connect / :meth:should_use_databricks_connect. 3. Probe for an active session of the chosen flavor. 4. When create is True, bootstrap a session of that flavor.

For richer Databricks Connect wiring (wheel publishing, DatabricksEnv, addArtifacts), use :meth:DatabricksClient.spark — it delegates the final getOrCreate() back here so the cache stays consistent.

has_uv

has_uv() -> bool

True if uv is reachable for this interpreter.

ensure_uv

ensure_uv(*, install_runtime: bool = True) -> Path | None

Resolve uv for this environment and optionally install it at runtime.

Resolution order: 1. cached path 2. env-local binary / PATH / python -m uv 3. install via python -m pip install uv (subprocess), with pip-internal-API fallback for the current interpreter.

install

install(
    *packages: str,
    requirements: str | Path | None = None,
    extra_args: Sequence[str] = (),
    wait: WaitingConfigArg = True,
    raise_error: bool = True,
    prefer_uv: bool | None = None,
    target: Path | str | None = None,
    break_system_packages: bool = False
) -> SystemCommand | None

Install packages into the environment anchored by :attr:python_path.

Fallback behavior
  1. Try normal subprocess install (uv pip or python -m pip)
  2. If that fails and this env is the current interpreter, try pip internal API

uninstall

uninstall(
    *packages: str,
    extra_args: Sequence[str] = (),
    wait: WaitingConfigArg = True,
    prefer_uv: bool | None = None
) -> SystemCommand | None

Uninstall one or more packages from the anchored environment.

pip

pip(
    *args: str, wait: WaitingConfigArg = True, prefer_uv: bool | None = None
) -> SystemCommand

Run an arbitrary pip subcommand against this environment.

First positional args element is the subcommand (install, freeze, list, …); the rest are passed through verbatim. With prefer_uv=True the call goes through uv pip <subcommand> --python <p> so installs land in the venv that owns python_path.

delete

delete(raise_error: bool = True) -> None

Delete the virtual environment that contains this interpreter.

run_python_code

run_python_code(
    code: str,
    *,
    cwd: Path | None = None,
    env: dict[str, str] | None = None,
    wait: WaitingConfigArg = True,
    raise_error: bool = True,
    stdin: str | None = None,
    python: PyEnv | Path | str | None = None,
    packages: list[str] | None = None,
    prefer_uv: bool | None = None,
    globs: dict[str, Any] | None = None,
    auto_install: bool = False
) -> SystemCommand

Execute Python source code in a subprocess under this or another env.

runtime_import_module classmethod

runtime_import_module(
    module_name: str | None = None,
    *,
    install: bool = True,
    pip_name: str | None = None,
    upgrade: bool = False,
    warn: bool = True,
    use_cache: bool = True
)

Class-level convenience wrapper for :meth:import_module.

import_module

import_module(
    module_name: str | None = None,
    *,
    wait: WaitingConfigArg = True,
    install: bool = True,
    pip_name: str | None = None,
    upgrade: bool = False,
    warn: bool = False,
    use_cache: bool = False
)

Import a module into the current interpreter, installing it if missing.

get_root_module_directory staticmethod

get_root_module_directory(module_name: str) -> Path

Return the filesystem directory of the root package/module.

runtime_import_module

runtime_import_module(
    module_name: str | None = None,
    *,
    install: bool = True,
    pip_name: str | None = None,
    upgrade: bool = False,
    warn: bool = True,
    use_cache: bool = True
)

Module-level convenience wrapper for :meth:PyEnv.runtime_import_module.