The script environment lifecycle manages the creation, caching, and execution of ephemeral Python environments for standalone scripts containing PEP 723 inline metadata. Unlike project-based environments, these are short-lived and tied to the specific requirements of a single file.
When uv run is invoked on a script (e.g., uv run script.py), uv identifies if the file contains PEP 723 metadata crates/uv/src/commands/project/run.rs180-182 If metadata is present, uv bypasses the local project environment (if any) and creates a specialized environment for that script crates/uv/src/commands/project/run.rs431-443 This same logic extends to other commands via the --script flag, such as uv check --script crates/uv/src/commands/project/check.rs72-73 uv workspace metadata --script crates/uv/src/commands/project/mod.rs58-59 and uv export --script crates/uv/src/commands/project/export.rs79
| Component | Role |
|---|---|
Pep723Script | Represents a script file with its parsed inline metadata; initialized via Pep723Script::init crates/uv/src/commands/project/lock.rs124 |
ScriptInterpreter | Handles Python interpreter discovery specifically for script execution crates/uv/src/commands/project/mod.rs74 |
ScriptEnvironment | Manages the lifecycle (init, update, cache) of the script's virtual environment crates/uv/src/commands/project/mod.rs73 |
EphemeralEnvironment | A non-persistent environment used for one-off executions crates/uv/src/commands/project/environment.rs29 |
CachedEnvironment | A persistent environment stored in the uv cache for reuse across script runs crates/uv/src/commands/project/environment.rs103 |
Sources: crates/uv/src/commands/project/run.rs68-82 crates/uv/src/commands/project/mod.rs67-82 crates/uv/src/commands/project/environment.rs27-103 crates/uv/src/commands/project/check.rs72-75
The process begins by discovering a suitable Python interpreter and then determining if a cached environment already exists for the script's specific requirement set.
For scripts, uv uses ScriptInterpreter::discover crates/uv/src/commands/project/run.rs273 This ensures the interpreter satisfies the script's requires-python constraint, even if it differs from the current workspace's Python version crates/uv/src/commands/project/lock.rs178-192 If a script is executed via uv run --with, uv creates a ScriptEnvironment that may extend a base interpreter with additional requirements crates/uv/src/commands/project/run.rs73-75
The following diagram illustrates how uv transitions from a script file to an executable environment.
Script Environment Initialization
Sources: crates/uv/src/commands/project/run.rs270-430 crates/uv/src/commands/project/sync.rs183-195 crates/uv/src/commands/project/lock.rs178-192 crates/uv/src/commands/project/environment.rs27-103
To avoid re-installing dependencies every time a script runs, uv caches script environments in a dedicated bucket within the global cache crates/uv/src/commands/project/mod.rs13
The cache key is generated using cache_digest and cache_name crates/uv/src/commands/project/mod.rs14 For CachedEnvironment, the hash is constructed from the resolution graph crates/uv/src/commands/project/environment.rs161-187 The hashing process involves:
Node::Dist weights crates/uv/src/commands/project/environment.rs165-172CachedEnvironmentDist which includes the ResolvedDist and its HashDigests crates/uv/src/commands/project/environment.rs112-116If the script's metadata changes, the hash changes, and uv automatically triggers a fresh resolution and installation into a new cached environment via ScriptEnvironment::get_or_init crates/uv/src/commands/project/sync.rs183
Sources: crates/uv/src/commands/project/mod.rs12-14 crates/uv/src/commands/project/sync.rs183-185 crates/uv/src/commands/project/environment.rs112-195
Once the environment is prepared, uv executes the script. This involves setting up the environment variables (like VIRTUAL_ENV and PATH) to point to the script-specific environment.
EphemeralEnvironment supports an overlay mechanism via .pth files. The set_overlay function writes a _uv_ephemeral_overlay.pth file into the site-packages directory crates/uv/src/commands/project/environment.rs45-53 This allows the environment to dynamically extend another environment's search path.
Additionally, uv sets the extends-environment key in pyvenv.cfg via set_parent_environment crates/uv/src/commands/project/environment.rs75-84 This writes the sys.prefix of the parent environment (escaped for Python) into the configuration file, enabling static analysis tools to understand the environment hierarchy crates/uv/src/commands/project/environment.rs70-74
CachedEnvironment or an EphemeralEnvironment crates/uv/src/commands/project/run.rs68-74tokio::process::Command crates/uv/src/commands/project/run.rs16run_to_completion crates/uv/src/commands/project/run.rs52Entity Mapping: Execution Logic
Sources: crates/uv/src/commands/project/run.rs395-580 crates/uv/src/commands/project/environment.rs45-84 crates/uv/src/commands/project/sync.rs183-185
The uv check --script and uv workspace metadata --script (preview) commands leverage the script environment lifecycle to provide analysis for standalone files.
When running uv check on a script:
ScriptEnvironment crates/uv/src/commands/project/check.rs141-152The uv workspace metadata command (preview) supports a --script flag crates/uv/src/commands/project/mod.rs58-59 It can also trigger a sync via the --sync flag, which initializes the ScriptEnvironment crates/uv/src/commands/project/sync.rs183-185 and populates the metadata context for the script target.
Sources: crates/uv/src/commands/project/check.rs58-175 crates/uv/src/commands/project/export.rs79-100 crates/uv/src/commands/project/sync.rs183-185
The update_environment function is the core engine for ensuring the script environment matches the requested state crates/uv/src/commands/project/mod.rs76
SitePackages satisfy the Requirement set extracted from the script crates/uv/src/commands/project/run.rs31Installer to link wheels from the global cache into the script's virtual environment crates/uv/src/commands/project/sync.rs25Sources: crates/uv/src/commands/project/mod.rs48-51 crates/uv/src/commands/project/sync.rs25-52 crates/uv/src/commands/project/run.rs31-420
Refresh this wiki