Skip to content

Commit

Permalink
Make opt-in
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Nov 4, 2024
1 parent 69e89f4 commit b66360d
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 90 deletions.
7 changes: 1 addition & 6 deletions crates/uv-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,9 +618,6 @@ pub enum ProjectCommand {
/// arguments to uv. All options to uv must be provided before the command,
/// e.g., `uv run --verbose foo`. A `--` can be used to separate the command
/// from uv options for clarity, e.g., `uv run --python 3.12 -- python`.
///
/// Respects `.env` files in the current directory unless `--no-env-file` is
/// provided.
#[command(
after_help = "Use `uv help run` for more details.",
after_long_help = ""
Expand Down Expand Up @@ -2663,13 +2660,11 @@ pub struct RunArgs {
///
/// Can be provided multiple times, with subsequent files overriding values defined in
/// previous files.
///
/// Defaults to reading `.env` in the current working directory.
#[arg(long, env = EnvVars::UV_ENV_FILE)]
pub env_file: Vec<PathBuf>,

/// Avoid reading environment variables from a `.env` file.
#[arg(long, conflicts_with = "env_file", value_parser = clap::builder::BoolishValueParser::new(), env = EnvVars::UV_NO_ENV_FILE)]
#[arg(long, value_parser = clap::builder::BoolishValueParser::new(), env = EnvVars::UV_NO_ENV_FILE)]
pub no_env_file: bool,

/// The command to run.
Expand Down
4 changes: 2 additions & 2 deletions crates/uv-static/src/env_vars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,9 +520,9 @@ impl EnvVars {
#[attr_hidden]
pub const KEYRING_TEST_CREDENTIALS: &'static str = "KEYRING_TEST_CREDENTIALS";

/// Used to overwrite path for loading `.env` files when executing `uv run` commands.
/// `.env` files from which to load environment variables when executing `uv run` commands.
pub const UV_ENV_FILE: &'static str = "UV_ENV_FILE";

/// Used to ignore `.env` files when executing `uv run` commands.
/// Ignore `.env` files when executing `uv run` commands.
pub const UV_NO_ENV_FILE: &'static str = "UV_NO_ENV_FILE";
}
39 changes: 10 additions & 29 deletions crates/uv/src/commands/project/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::path::{Path, PathBuf};
use anstream::eprint;
use anyhow::{anyhow, bail, Context};
use futures::StreamExt;
use itertools::{Either, Itertools};
use itertools::Itertools;
use owo_colors::OwoColorize;
use tokio::process::Command;
use tracing::{debug, warn};
Expand Down Expand Up @@ -111,38 +111,19 @@ pub(crate) async fn run(

// Read from the `.env` file, if necessary.
if !no_env_file {
let env_file_paths = if env_file.is_empty() {
Either::Left(std::iter::once(Path::new(".env")))
} else {
Either::Right(env_file.iter().rev().map(PathBuf::as_path))
};
for env_file_path in env_file_paths {
for env_file_path in env_file.iter().rev().map(PathBuf::as_path) {
match dotenvy::from_path(env_file_path) {
Err(dotenvy::Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => {
if env_file.is_empty() {
debug!(
"No environment file found at: `{}`",
env_file_path.simplified_display()
);
} else {
bail!(
"No environment file found at: `{}`",
env_file_path.simplified_display()
);
}
bail!(
"No environment file found at: `{}`",
env_file_path.simplified_display()
);
}
Err(dotenvy::Error::Io(err)) => {
if env_file.is_empty() {
debug!(
"Failed to read environment file `{}`: {err}",
env_file_path.simplified_display()
);
} else {
bail!(
"Failed to read environment file `{}`: {err}",
env_file_path.simplified_display()
);
}
bail!(
"Failed to read environment file `{}`: {err}",
env_file_path.simplified_display()
);
}
Err(dotenvy::Error::LineParse(content, position)) => {
warn_user!(
Expand Down
56 changes: 14 additions & 42 deletions crates/uv/tests/it/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2855,6 +2855,18 @@ fn run_with_env() -> Result<()> {
success: true
exit_code: 0
----- stdout -----
None
None
None
None
----- stderr -----
"###);

uv_snapshot!(context.filters(), context.run().arg("--env-file").arg(".env").arg("test.py"), @r###"
success: true
exit_code: 0
----- stdout -----
palpatine
leia_organa
obi_wan_kenobi
Expand Down Expand Up @@ -2965,51 +2977,11 @@ fn run_with_env_omitted() -> Result<()> {
"
})?;

uv_snapshot!(context.filters(), context.run().arg("--no-env-file").arg("test.py"), @r###"
success: true
exit_code: 0
----- stdout -----
None
----- stderr -----
"###);

Ok(())
}

#[test]
fn run_with_parent_env() -> Result<()> {
let context = TestContext::new("3.12");

context
.temp_dir
.child("test")
.child("test.py")
.write_str(indoc! { "
import os
print(os.environ.get('THE_EMPIRE_VARIABLE'))
print(os.environ.get('REBEL_1'))
print(os.environ.get('REBEL_2'))
print(os.environ.get('REBEL_3'))
"
})?;

context.temp_dir.child(".env").write_str(indoc! { "
THE_EMPIRE_VARIABLE=palpatine
REBEL_1=leia_organa
REBEL_2=obi_wan_kenobi
REBEL_3=C3PO
"
})?;

uv_snapshot!(context.filters(), context.run().arg("test.py").current_dir(context.temp_dir.child("test")), @r###"
uv_snapshot!(context.filters(), context.run().arg("--env-file").arg(".env").arg("--no-env-file").arg("test.py"), @r###"
success: true
exit_code: 0
----- stdout -----
None
None
None
None
----- stderr -----
"###);
Expand All @@ -3032,7 +3004,7 @@ fn run_with_malformed_env() -> Result<()> {
"
})?;

uv_snapshot!(context.filters(), context.run().arg("test.py"), @r###"
uv_snapshot!(context.filters(), context.run().arg("--env-file").arg(".env").arg("test.py"), @r###"
success: true
exit_code: 0
----- stdout -----
Expand Down
4 changes: 2 additions & 2 deletions docs/configuration/environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,5 +174,5 @@ uv respects the following environment variables:
For example, `RUST_LOG=trace` will enable trace-level logging.
See the [tracing documentation](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#example-syntax)
for more.
- <a id="UV_ENV_FILE"></a> [`UV_ENV_FILE`](#UV_ENV_FILE): Used to overwrite path for loading `.env` files when executing `uv run` commands.
- <a id="UV_NO_ENV_FILE"></a> [`UV_NO_ENV_FILE`](#UV_NO_ENV_FILE): Used to ignore `.env` files when executing `uv run` commands.
- <a id="UV_ENV_FILE"></a> [`UV_ENV_FILE`](#UV_ENV_FILE): `.env` files from which to load environment variables when executing `uv run` commands.
- <a id="UV_NO_ENV_FILE"></a> [`UV_NO_ENV_FILE`](#UV_NO_ENV_FILE): Ignore `.env` files when executing `uv run` commands.
16 changes: 11 additions & 5 deletions docs/configuration/files.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,25 @@ See the [settings reference](../reference/settings.md) for an enumeration of the

## `.env`

By default, `uv run` will load environment variables from a `.env` file in the current working
directory, following the discovery and parsing rules of the
[`dotenvy`](https://github.com/allan2/dotenvy) crate.
`uv run` can load environment variables from dotenv files (e.g., `.env`, `.env.local`,
`.env.development`), powered by the [`dotenvy`](https://github.com/allan2/dotenvy) crate.

To load a `.env` file from a dedicated location, set the `UV_ENV_FILE` environment variable, or pass
the `--env-file` flag to `uv run`.

For example, to load environment variables from a `.env` file in the current working directory:

```console
$ uv run --env-file .env -- echo $MY_ENV_VAR
```

The `--env-file` flag can be provided multiple times, with subsequent files overriding values
defined in previous files. To provide multiple files via the `UV_ENV_FILE` environment variable,
separate the paths with a space (e.g., `UV_ENV_FILE="/path/to/file1 /path/to/file2"`).

To disable this behavior, set the `UV_NO_ENV_FILE` environment variable to `1`, or pass the
`--no-env-file` flag to `uv run`.
To disable dotenv loading (e.g., to override `UV_ENV_FILE` or the `--env-file` command-line
argument), set the `UV_NO_ENV_FILE` environment variable to `1`, or pass the`--no-env-file` flag to
`uv run`.

If the same variable is defined in the environment and in a `.env` file, the value from the
environment will take precedence.
Expand Down
4 changes: 0 additions & 4 deletions docs/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@ When used outside a project, if a virtual environment can be found in the curren

Arguments following the command (or script) are not interpreted as arguments to uv. All options to uv must be provided before the command, e.g., `uv run --verbose foo`. A `--` can be used to separate the command from uv options for clarity, e.g., `uv run --python 3.12 -- python`.

Respects `.env` files in the current directory unless `--no-env-file` is provided.

<h3 class="cli-reference">Usage</h3>

```
Expand Down Expand Up @@ -145,8 +143,6 @@ uv run [OPTIONS] [COMMAND]

<p>Can be provided multiple times, with subsequent files overriding values defined in previous files.</p>

<p>Defaults to reading <code>.env</code> in the current working directory.</p>

<p>May also be set with the <code>UV_ENV_FILE</code> environment variable.</p>
</dd><dt><code>--exclude-newer</code> <i>exclude-newer</i></dt><dd><p>Limit candidate packages to those that were uploaded prior to the given date.</p>

Expand Down

0 comments on commit b66360d

Please sign in to comment.