Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support .env-files #1384

Open
woutervh opened this issue Feb 15, 2024 · 69 comments
Open

Support .env-files #1384

woutervh opened this issue Feb 15, 2024 · 69 comments
Assignees
Labels
configuration Settings and such enhancement New feature or improvement to existing functionality

Comments

@woutervh
Copy link

In my workflow I make heavy use of env-files.

several tools support .env out of the box:

It would be nice if uv could support .env-files in the $CWD or parent-dirs.
see https://crates.io/crates/dotenv

@zanieb
Copy link
Member

zanieb commented Feb 15, 2024

Thanks for engaging with the project!

Specifically, you would like us to read .env files before every operation? Or something else?

@zanieb zanieb added the enhancement New feature or improvement to existing functionality label Feb 15, 2024
@woutervh
Copy link
Author

Specifically, you would like us to read .env files before every operation?
yes.

pip supports a config-file pip.ini / pip.conf
all those values in that config-support can also be set as environment-variables

I have not yet seen a reference that uv pip supports such config-file or these envvars,
but many times I set such project-specific pip-envvars, the same for twine.

some examples:

  • PIP_EXTRA_INDEX_URL
  • RUFF_CACHE_DIR
  • TWINE_USERNAME
  • TWINE_REPOSITORY_URL
<project-dir>
   .env
  .venv/
   docs/
   src/
   tests/

so my request is to support .env-files in $CWD,
and optionally in parent-levels (e.g in just this is configurable)

@woutervh
Copy link
Author

I always try to setup projects in an isolated way:

<project-dir>
   .env
  .venv/
   docs/
   src/
   tests/
   var/cache
   var/cache/ipython
   var/cache/pytest
   var/cache/python
   var/cache/ruff
   var/cache/sphinx
   var/cache   
   var/log
   var/tmp

to make ruff use the my .env to read RUFF_CACHE_DIR,
I currently have to install ruff in the .venv and use python-entrypoint to execute ruff (slowing things down)

I use my package https://github.com/libranet/autoread-dotenv to read the .env via sitecustomize-hooks,
so the env-vars become available for any python-generated entrypoint.

@zanieb zanieb added the configuration Settings and such label Feb 16, 2024
@zanieb
Copy link
Member

zanieb commented Jul 1, 2024

I'm going to mark this as not-planned for now. We may revisit in the future. If people have additional use-cases or thoughts please feel free to share!

@zanieb zanieb closed this as not planned Won't fix, can't repro, duplicate, stale Jul 1, 2024
@dustalov
Copy link

I have a similar use case.

I am launching machine learning demos for students, and I am currently using Pipenv which loads environment variables from a file named .env. That file contains variables like DO_NOT_TRACK=1 and HF_HUB_DISABLE_TELEMETRY=1 which are applied for all the commands I run via pipenv run.

As a workaround, I can define them in my shell profile, but it would be great to have it natively supported by uv.

@Count-Count
Copy link

I am also migrating from pipenv which uses .env out of the box. It would be great if uv run could support this.

@zanieb
Copy link
Member

zanieb commented Aug 21, 2024

Willing to consider this further, i.e., we'd read it in uv run only.

@zanieb zanieb reopened this Aug 21, 2024
@patrick91
Copy link

This might of inspiration, PDM supports something like this: https://pdm-project.org/en/latest/usage/scripts/#env_file

I've personally used this as a way to not use tools like dotenv, since I usually need them locally and not on production 😊 (plus is one less thing to worry about)

@lcoleman-scorability
Copy link

lcoleman-scorability commented Aug 22, 2024

We would really love teh ability to load from a .env file for the same reason as above - we use a lot of our applications configuration in .env files.

@simonw
Copy link
Contributor

simonw commented Aug 24, 2024

Supporting this in uv run seems like it could be really useful to me. When I'm working with Django I often have it pick up os.environ["..."] for things like API keys needed by my application. uv run ./manage.py runserver to pick up those from a .env file could be a really nice pattern.

@LucasRoesler
Copy link

I am also interested in the uv run support. I am coming from Poetry and currently use this plugin to achieve the same flow to pick up env variables from the .env at the project root.

@kamuridesu
Copy link

I think it would be useful to have a flag like --env-file or some section in the config file like PDM does.

But why limit it to uv run only? uv uses a set of environment variables in place of command line arguments, that way you can use different definitions for uv depending on your environment. I personally think it would be useful for situations like when you use a custom packages index for example.

@Dufran
Copy link

Dufran commented Sep 1, 2024

I am also interested in the uv run support. I am coming from Poetry and currently use this plugin to achieve the same flow to pick up env variables from the .env at the project root.

Hi, I was also migrating from poetry to uv, and currently use taskfile to handle .env variable passing to uv run

Example of the taskfile

version: "3"
dotenv: [".env"]
tasks:
  manage:
    cmds:
      - uv run ./backend/manage.py {{.CLI_ARGS}}

and then i can run stuff like
task manage -- makemigraitons
task manage -- shell_plus etc

@sminnee
Copy link

sminnee commented Sep 4, 2024

Another user-case: I supply environment variables to my dev server with a .env file. I've been using poetry run bin/serve-dev to start things with a dotenv loading plugin for poetry.

uv run bin/serve-dev auto-loading my .env file would be nice, but to be honest uv run --env-file .env bin/serve-dev is fine too, if you want to limit the blast radius of this change.

@TheRealBecks
Copy link

After the migration from pipenv to uv our local Ansible environments are now broken as uv does not read the .env file.

@zanieb @charliermarsh After reading this thread it looks like that missing feature is a real showstopper?

@gusutabopb
Copy link

Here's a non-Python example: Node JS added native support to this feature in September 2023 (changelog) and it has been supported by Bun/Deno for a while now.

@petermbauer
Copy link

My use case is to use a separate project-specific Conan Local Cache when entering the respective venv. This simply means setting the CONAN_USER_HOME env var to the venv path with source .venv/bin/activate.
Currently, this is done by fumbling this into the generated activate/deactivate scripts. These scripts also vary between the Python versions so this also needs to be tested and updated for new Python versions :-(

@cbrnr
Copy link

cbrnr commented Sep 18, 2024

I'm not sure if my use case is related, but I really enjoy pyenv automatically activating a specific venv if it finds a .python-version file in the directory. I guess the same can be achieved with .env, but maybe there is already a way to use uv to auto-activate envs? Or is this not necessary anymore with uv run (sorry for my ignorance, I haven't really used uv much yet)?

@zanieb
Copy link
Member

zanieb commented Sep 18, 2024

Or is this not necessary anymore with uv run (sorry for my ignorance, I haven't really used uv much yet)?

It shouldn't be needed if you use uv run, though it's a bit more nuanced than that. Feel free to open a new issue if you run into problems there.

@blakeNaccarato
Copy link

blakeNaccarato commented Sep 20, 2024

I like Brett Cannon's and Jeff Triplett's takes on .env files, which identify the orthogonal purposes of using such files for configuration and for secrets. They also identify the issue with the lack of a standard of .env files, e.g. path separator variation and other nuances.

Brett posed the question, could we standardize on TOML for this? I think if uv picks this up, it could be done in stages, supporting .env today but with no promises on the unstandardized format, then eventually incorporating a more opinionated take inside pyproject.toml in a subtable of tool.uv.

Secrets management is it's own beast, of course.

The upside to uv tackling lockfiles is the standards discussion on that is already pretty mature, but there's no clear consensus on standardizing something for .env, so maybe that's a bridge too far.

@woutervh
Copy link
Author

@blakeNaccarato IMHO it is widely understood that .env-files should have a bash-compatible syntax. Besides that, there should not be anything language or tool specific.

@sminnee
Copy link

sminnee commented Sep 23, 2024

Brett posed the question, could we standardize on TOML for this?

The great thing about ruff is that it's essentially a drop-in replacement for pylint and other tools you were probably using before.

Doing the same with .env files would be a DX win.

Championing an emergent new format would be an interesting idea, as a separate and second step, but until it becomes comparable to .env in terms of adoption, it seems like a DX loss to deprecate .env.

@seapagan
Copy link

I use direnv for this exact use-case. It is installed as a global binary on pretty much any OS, then activates any .envrc or optionally also .env when the folder is entered. This is a mature tool that does exactly this one job very well, with the bonus of not being restricted to only Python as it works on any folder, anywhere.

The big plus for me is that you need to explicitly enable the file for each folder (once off check) so it will not activate any random file you get in a cloned repo.

uv doesn't need to do absolutely everything 😉

@petermbauer
Copy link

Unfortunately i have to use Windows so direnv won't work for me.

@theintz
Copy link

theintz commented Oct 24, 2024

We're switching from pipenv to uv, so in order to maintain our current workflows, I'd like to add my vote to the "include .env files by default" option.

@artificial-aidan
Copy link

artificial-aidan commented Oct 24, 2024

Another vote for load .env by default in build and run cases. A .env file is a sign a user is opting in, and being able to configure a build env with a .env file is incredibly useful for private repositories.

Pipenv has a nice loading .env file output when it runs if you have a .env file, which makes it clear what is going on. Also, uv is probably where most people are headed after escaping pipenv, so there is some reason to maintain an existing behavior. Where new uv users can just use an opt-out flag to get the behavior they want.

zanieb pushed a commit that referenced this issue Oct 24, 2024
I have been reading discussion #1384 about .env and how to include it in
the `uv run` command.

I have always wanted to include this possibility in `uv`, so I was
interested in the latest changes. Following @charliermarsh's [advice
](#1384 (comment)) I
have tried to respect the philosophy that `uv run` uses the default
`.env` and this can be discarded or changed via terminal or environment
variables.

The behaviour is as follows:
- `uv run file.py` executes file.py using the `.env` (if it exists).
- `uv run --env-file .env.development file.py` uses the
`.env.development` file to load the variables and then runs file.py. In
this case the program fails if the file does not exist.
- `uv run --no-env-file file.py` skips reading the `.env` file.

Equivalently, I have included the `UV_ENV_FILE` and `UV_NO_ENV_FILE`
environment variables.

I haven't got into including automated tests, I would need help with
this.

I have tried the above commands, with a python script that prints
environment variables.

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
zanieb pushed a commit that referenced this issue Oct 25, 2024
I have been reading discussion #1384 about .env and how to include it in
the `uv run` command.

I have always wanted to include this possibility in `uv`, so I was
interested in the latest changes. Following @charliermarsh's [advice
](#1384 (comment)) I
have tried to respect the philosophy that `uv run` uses the default
`.env` and this can be discarded or changed via terminal or environment
variables.

The behaviour is as follows:
- `uv run file.py` executes file.py using the `.env` (if it exists).
- `uv run --env-file .env.development file.py` uses the
`.env.development` file to load the variables and then runs file.py. In
this case the program fails if the file does not exist.
- `uv run --no-env-file file.py` skips reading the `.env` file.

Equivalently, I have included the `UV_ENV_FILE` and `UV_NO_ENV_FILE`
environment variables.

I haven't got into including automated tests, I would need help with
this.

I have tried the above commands, with a python script that prints
environment variables.

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
zanieb added a commit that referenced this issue Oct 25, 2024
I have been reading discussion #1384 about .env and how to include it in
the `uv run` command.

I have always wanted to include this possibility in `uv`, so I was
interested in the latest changes. Following @charliermarsh's [advice
](#1384 (comment)) I
have tried to respect the philosophy that `uv run` uses the default
`.env` and this can be discarded or changed via terminal or environment
variables.

The behaviour is as follows:
- `uv run file.py` executes file.py using the `.env` (if it exists).
- `uv run --env-file .env.development file.py` uses the
`.env.development` file to load the variables and then runs file.py. In
this case the program fails if the file does not exist.
- `uv run --no-env-file file.py` skips reading the `.env` file.

Equivalently, I have included the `UV_ENV_FILE` and `UV_NO_ENV_FILE`
environment variables.

I haven't got into including automated tests, I would need help with
this.

I have tried the above commands, with a python script that prints
environment variables.

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
@jonaslb
Copy link

jonaslb commented Oct 27, 2024

In #8263, some commenters are making the case that this should be opt-in rather than opt-out. I want to open up the conversation for more opinions here before this ships.

I don't know if it's too late now since that MR is merged. But, I'll try to outline a few arguments against making it a default:

  1. Dotenv files are often used in situations where a "real" configuration file (toml, json, etc etc) with an app defined schema would be more appropriate (easier to both organise, read and validate).
  2. Environment variables are often given preference over configuration files. Dotenv files are usually hidden (due to the leading dot) and it is counter intuitive that a hidden file should override a visible file.
  3. What uv makes default, a lot of people will think is good practice. It follows that if uv enters the space of app configuration, it should give at least some thought to what is considered best practice for app configuration. In my opinion, it does not involve automatic loading of hidden files into the environment.
  4. Runtime "environments" such as Kubernetes, Docker Swarm, Systemd services already offer ways of setting environment variables, and in my opinion their way should be preferred when running in those environments. They also all do it using non-hidden files (either explicitly configured environment files, or as part of their own service/resource configuration). In my opinion, it's fine for uv to similarly allow setup of environment variables, to enable locally running something that needs certain variables, but it should be explicit and opt-in, not opt-out.

@charliermarsh
Copy link
Member

(It's not too late, this was just merged into a feature branch for v0.5, but may still change between now and the actual v0.5 release.)

@artificial-aidan
Copy link

Is this issue also being used for tracking .env support in tools like uv sync, or is that already included in the merged PR.

@jonaslb
Copy link

jonaslb commented Oct 27, 2024

A few points raised in this thread that I want to respond to:

variables like DO_NOT_TRACK=1 and HF_HUB_DISABLE_TELEMETRY=1 [...] As a workaround, I can define them in my shell profile

These "purely preferential" variables probably do belong in each developer's personal setup rather than having to be defined in every project he works on. So, I don't think this should be considered just a "workaround". If you are making an application where some variables must always be set, you should probably make it part of the code.

Here's a non-Python example: Node JS added native support to this feature in September 2023 (changelog) and it has been supported by Bun/Deno for a while now.

While it seems Bun does automatically load the .env-file, going by their docs both Node and Deno appear to need an explicit --env-file=config.env argument, which is what I think should be required here as well. Besides, I would point out that most tools in other languages don't support this at all. When there is a blessed config provider, it is usually not environment files (instead you see e.g. appsettings.json (C#), application.properties (Java), ususally something.toml (Rust)). However, although I think it is misguided to use environment files, I can certainly accept that there is already some usage of them among Python users.

I also feel like having simple pyproject.toml config like read_dotenv_files = true (or equivalent CLI option) should opt-in to that behavior being automatic.

This would be a good way to also satisfy those who want it "always on", but I think it should probably be a string option, i.e. env_file = "dev.env" (such that the option name matches the --env-file cli option).

charliermarsh added a commit that referenced this issue Oct 28, 2024
I have been reading discussion #1384 about .env and how to include it in
the `uv run` command.

I have always wanted to include this possibility in `uv`, so I was
interested in the latest changes. Following @charliermarsh's [advice
](#1384 (comment)) I
have tried to respect the philosophy that `uv run` uses the default
`.env` and this can be discarded or changed via terminal or environment
variables.

The behaviour is as follows:
- `uv run file.py` executes file.py using the `.env` (if it exists).
- `uv run --env-file .env.development file.py` uses the
`.env.development` file to load the variables and then runs file.py. In
this case the program fails if the file does not exist.
- `uv run --no-env-file file.py` skips reading the `.env` file.

Equivalently, I have included the `UV_ENV_FILE` and `UV_NO_ENV_FILE`
environment variables.

I haven't got into including automated tests, I would need help with
this.

I have tried the above commands, with a python script that prints
environment variables.

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
zanieb added a commit that referenced this issue Oct 29, 2024
I have been reading discussion #1384 about .env and how to include it in
the `uv run` command.

I have always wanted to include this possibility in `uv`, so I was
interested in the latest changes. Following @charliermarsh's [advice
](#1384 (comment)) I
have tried to respect the philosophy that `uv run` uses the default
`.env` and this can be discarded or changed via terminal or environment
variables.

The behaviour is as follows:
- `uv run file.py` executes file.py using the `.env` (if it exists).
- `uv run --env-file .env.development file.py` uses the
`.env.development` file to load the variables and then runs file.py. In
this case the program fails if the file does not exist.
- `uv run --no-env-file file.py` skips reading the `.env` file.

Equivalently, I have included the `UV_ENV_FILE` and `UV_NO_ENV_FILE`
environment variables.

I haven't got into including automated tests, I would need help with
this.

I have tried the above commands, with a python script that prints
environment variables.

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
@majidaldo
Copy link

Unfortunately i have to use Windows so direnv won't work for me.

you can hack it. part of me says that this is best left to direnv. direnv should work on windows. this issue shouldn't have to do with a programming language. but it's in pixi's field.

zanieb added a commit that referenced this issue Nov 4, 2024
I have been reading discussion #1384 about .env and how to include it in
the `uv run` command.

I have always wanted to include this possibility in `uv`, so I was
interested in the latest changes. Following @charliermarsh's [advice
](#1384 (comment)) I
have tried to respect the philosophy that `uv run` uses the default
`.env` and this can be discarded or changed via terminal or environment
variables.

The behaviour is as follows:
- `uv run file.py` executes file.py using the `.env` (if it exists).
- `uv run --env-file .env.development file.py` uses the
`.env.development` file to load the variables and then runs file.py. In
this case the program fails if the file does not exist.
- `uv run --no-env-file file.py` skips reading the `.env` file.

Equivalently, I have included the `UV_ENV_FILE` and `UV_NO_ENV_FILE`
environment variables.

I haven't got into including automated tests, I would need help with
this.

I have tried the above commands, with a python script that prints
environment variables.

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
@charliermarsh
Copy link
Member

I've decided to make this opt-in for now. I'm going to remove it from the v0.5 branch and PR it to main, since it's no longer a "breaking" change in any sense -- we can ship it in a patch release.

@charliermarsh charliermarsh self-assigned this Nov 4, 2024
charliermarsh added a commit that referenced this issue Nov 4, 2024
I have been reading discussion #1384 about .env and how to include it in
the `uv run` command.

I have always wanted to include this possibility in `uv`, so I was
interested in the latest changes. Following @charliermarsh's [advice
](#1384 (comment)) I
have tried to respect the philosophy that `uv run` uses the default
`.env` and this can be discarded or changed via terminal or environment
variables.

The behaviour is as follows:
- `uv run file.py` executes file.py using the `.env` (if it exists).
- `uv run --env-file .env.development file.py` uses the
`.env.development` file to load the variables and then runs file.py. In
this case the program fails if the file does not exist.
- `uv run --no-env-file file.py` skips reading the `.env` file.

Equivalently, I have included the `UV_ENV_FILE` and `UV_NO_ENV_FILE`
environment variables.

I haven't got into including automated tests, I would need help with
this.

I have tried the above commands, with a python script that prints
environment variables.

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
@palewire
Copy link

palewire commented Nov 5, 2024

We're switching from pipenv to uv, so in order to maintain our current workflows, I'd like to add my vote to the "include .env files by default" option.

I'm in this camp. I just lost an hour of my time trying to sort of this discrepancy. I'd be much more happy switching to uv and recommending it to others if it "just worked" as a pipenv replacement.

@weihenglim
Copy link

I understand the decision to make this an opt-in feature, but can we also make it configurable via pyproject.toml?

@woutervh
Copy link
Author

woutervh commented Nov 6, 2024

Ii would be nice to also enable the env-file via uv.toml.

@ReinforcedKnowledge
Copy link
Contributor

ReinforcedKnowledge commented Nov 17, 2024

Hi!

I'd like to know what to know what are the actual best security practices when it comes to publishing to a private index. I know we can do it with one of the following ways:

  • use the CLI like uv publish --publish-url <url> --username <username> --password <password> or uv publish --publish-url <url> --token <token>.

    • But it seems like redundant / hassle, and I don't think it's the most secure way of doing (shell history, process list etc.).
  • use environment variables, UV_PUBLISH_URL, UV_PUBLISH_USERNAME, UV_PUBLISH_PASSWORD, UV_PUBLISH_TOKEN.

    • It's not the most secure way of doing things as well and the environment variables are available globally (in the limits of the shell session).

I recognize this might be delving into the extreme side of security concerns, I’m curious about what would be considered the best practice in this context.

Would implementing support for a .env file (I think not the most secure as well when we consider the security risk for the CLI, but at least it reduces the hassle and increases the flexibility I guess) or another secure configuration method be worth exploring?

I guess we can always come up with a way to set up the environment variables from an .env file and then remove them 🤔

You can consider my comment useless 😅

@vemonet
Copy link

vemonet commented Dec 10, 2024

I understand the decision to make this an opt-in feature, but can we also make it configurable via pyproject.toml?

Opt-in through CLI flags should be made illegal please. It is really bad UX design (imo at least, if there are argument for it and against config in config file I would love to hear them), configuration should be defined in the config file it seems quite logical and intuitive and reproducible.

Is it complex to add a new field to the pyproject.toml/uv.toml?

@reuben
Copy link

reuben commented Dec 19, 2024

We use several private package indexes and are currently migrating from pipenv to uv. With pipenv, one can setup an .env file once and copy it into projects. This file contains the equivalent of UV_INDEX_BLAH_USERNAME and UV_INDEX_BLAH_PASSWORD variables. So I would really like if uv sync and uv lock also read from .env by default, not just uv run.

@jefvantongerloo
Copy link

Interested in .env support for exposing API keys for local testing.

@reuben
Copy link

reuben commented Jan 7, 2025

We use several private package indexes and are currently migrating from pipenv to uv. With pipenv, one can setup an .env file once and copy it into projects. This file contains the equivalent of UV_INDEX_BLAH_USERNAME and UV_INDEX_BLAH_PASSWORD variables. So I would really like if uv sync and uv lock also read from .env by default, not just uv run.

Since writing this I've moved to .netrc for the credentials and to direnv to load .env files and it's working pretty well. direnv is more flexible than pipenv's .env file loading so we were able to put shared variables in the root of the project and only have project-specific overrides in the project folders, which we couldn't do before and required some duplication. So in the end I feel like being forced to think about a different solution landed us in a better setup.

@woutervh
Copy link
Author

woutervh commented Jan 7, 2025

Since writing this I've moved to .netrc

In a virtualenv-based project I'd like to be independent from a user's $HOME-dir.
.netrc feels a very ancient antiquated solution.

@reuben
Copy link

reuben commented Jan 7, 2025

Since writing this I've moved to .netrc

In a virtualenv-based project I'd like to be independent from a user's $HOME-dir. .netrc feels a very ancient antiquated solution.

Yea, I put a netrc.template in the root of the project dir which users copy and paste into the .netrc file in the root of the project. Then, next to those files in the root there's an .envrc file which does:

REPO_ROOT=$(expand_path .)

export NETRC=$REPO_ROOT/.netrc
dotenv $REPO_ROOT/.env

Inside each project folder (in our case projects/foo), I have the following .envrc file:

# Load root .envrc first
source_env ../../.envrc

# Load .env file
dotenv_if_exists .env

Which loads the root .envrc file and optionally the project overrides in the adjacent .env file.

Alternatively you could also just put the UV_INDEX_BLAH env vars in the root .envrc and not use netrc at all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
configuration Settings and such enhancement New feature or improvement to existing functionality
Projects
None yet
Development

Successfully merging a pull request may close this issue.