poetry icon indicating copy to clipboard operation
poetry copied to clipboard

Add support for environment variables at pyproject.toml

Open loop0 opened this issue 7 years ago • 52 comments

It would be handy to have support for using values from environment vars on pyproject.toml The use case I have is that I need to use different repository urls depending on my environment. Something like:

[[tool.poetry.source]]                                                          
name = "private"                                                          
url = "${PRIVATE_REPO_URL}"

I'm still new to poetry, but I could help implementing the feature with some guidance.

loop0 avatar Jun 12 '18 18:06 loop0

I too would like to not check in a private repo url. Perhaps in this case, the value from config.toml could be used for the repository?

The docs already mention adding a repository url for pushing. If url was missing from source you could check for the following key:

f"repositories.{source.name}.url"

I pushed up a spike 290e8863da8b8596d82f60484dcc08534abb3b3d to see if it would work and it looks like it does, I'm not sure if it is the correct solution though.

My suggestion becomes a little cumbersome when building docker images. Currently I'm doing everything on one line so nothing sensitive is cached in a layer:

ARG PYPI_USERNAME
ARG PYPI_PASSWORD
RUN poetry config http-basic.my-repo ${PYPI_USERNAME} ${PYPI_PASSWORD} && poetry install ${POETRY_INSTALL_OPTIONS} && poetry config --unset http-basic.my-repo

jordanhamill avatar Aug 05 '18 20:08 jordanhamill

@loop0 did you take a stab at this? I'd love to see this implemented and have some ideas around how to do it.

kofron avatar Oct 01 '18 21:10 kofron

Not yet, I was planning to tackle this next week as I am starting to use poetry again. Do you mind sharing your ideas?

loop0 avatar Oct 01 '18 22:10 loop0

Awesome, great to hear - let me know if I can help at all.

Basically what I was imagining is a new function (or class) that lives in poetry.util.helpers called environment_expander or similar.

The basic idea is that after pyproject.toml is read from disk, and after we know that it exists, we take a transformation pass over the TomlFile object, and applying a function to all of the values in the object that evaluate expressions of the form ${SOME_ENV_VARIABLE} by calling os.env.

I would want to apply this pass as early as often - at poetry/puzzle/provider.py:161 for example.

Not sure if you would want to raise if SOME_ENV_VARIABLE didn't exist...

Thoughts?

kofron avatar Oct 02 '18 00:10 kofron

Sounds a great idea! And of course you can help, I will try to make some time tomorrow to write the first code for it. If you feel you want to write it first just mark me on the PR and I can also help you later.

loop0 avatar Oct 02 '18 00:10 loop0

Any update on this one?

dimkirt avatar Mar 12 '19 09:03 dimkirt

@dimkirt https://github.com/sdispater/poetry/pull/481 - was closed a couple of days ago by the author, who doesn't want to add this feature.

kofron avatar Mar 12 '19 15:03 kofron

Pipenv implements this feature. As they mention, it is "quite useful if you need to authenticate to a private PyPI". That is my case too.

@sdispater Being ranked as the 11th most popular issue in this repository (out of 400+), would you reconsider accepting pull-requests for this? :innocent:

Peque avatar Jul 06 '19 13:07 Peque

For us it's also a blocker to finally migrate from Pipenv

metrofun avatar Jul 12 '19 14:07 metrofun

We need this feature to migrate to poetry from pipenv as well, that's why I initially open this issue. Unfortunately I didn't have much time to work in the solution, but as far as I remember the code, it shouldn't be hard. We only need the bless from poetry's developers.

loop0 avatar Jul 12 '19 16:07 loop0

I did actually do this work in this PR: https://github.com/sdispater/poetry/pull/481

However, @sdispater did not want to add this feature to the project.

kofron avatar Jul 12 '19 20:07 kofron

Let us hope they eventually change their mind and reconsider adding this to Poetry. :innocent:

Peque avatar Jul 12 '19 23:07 Peque

Although this solution would solve the problem, and it's the same solution as Pipenv, it's only good for CI, but terrible for humans. Once you put environment variable names in pyproject.toml, every developer must somehow export the variables to use Poetry, they can't just use poetry config http-basic anymore.

It would be much better if Poetry recognized specific environment variables as credentials (such as POETRY_USERNAME and POETRY_PASSWORD or maybe POETRY_REPONAME_USERNAME, to support different credentials for different repositories), like twine does, for instance. Then the environment variables are needed only for CI and humans can do whatever they want in their machines.

But this is not something you can do with an external program, it's something that needs to be implemented in Poetry.

absassi avatar Aug 30 '19 08:08 absassi

@absassi I disagree. Any large enterprise already has a set of consistent environment variables every developer must export. These are used across many languages and toolsets (pipenv, cake, gradle, maven, ant, node, yarn, docker, terraform, etc.). Adding a new set of environment variables is just as bad as using whatever people want.

Maybe just compromise and do both. look for some poetry-specific variable, but also allow environment variables to be interpolated like just about every other build tool that exists today.

delphyne avatar Aug 31 '19 16:08 delphyne

Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

stale[bot] avatar Nov 13 '19 10:11 stale[bot]

Still relevant.

Maybe @loop0 has some updates on this? :blush:

Peque avatar Nov 13 '19 10:11 Peque

No updates, sorry. We still want to migrate from pipenv to poetry here, but this issue is a blocker for most projects.

loop0 avatar Nov 13 '19 16:11 loop0

For instance, there is a way to use poetry with gemfury's repository, but the documentation is not clear, here are the steps:

poetry config repositories.your_repo https://pypi.fury.io/your_repo/
# at the auth configuration you just repeat your token twice
poetry config http-basic.your_repo YOUR_TOKEN YOUR_TOKEN

And then you add the following to your pyproject.toml (after the [tool.poetry] block)

[[tool.poetry.source]]
name = "your_repo"
url = "https://pypi.fury.io/your_repo/"

So with some scripting it is possible to have this running on your CI

loop0 avatar Nov 13 '19 16:11 loop0

For instance, there is a way to use poetry with gemfury's repository, but the documentation is not clear, here are the steps:

poetry config repositories.your_repo https://pypi.fury.io/your_repo/
# at the auth configuration you just repeat your token twice
poetry config http-basic.your_repo YOUR_TOKEN YOUR_TOKEN

And then you add the following to your pyproject.toml (after the [tool.poetry] block)

[[tool.poetry.source]]
name = "your_repo"
url = "https://pypi.fury.io/your_repo/"

So with some scripting it is possible to have this running on your CI

While this is true, if you are using docker, you run the risk of caching these credentials, which is obviously not good. As it stands, it's not really possible (without jumping through some serious hoops) to write a 12 Factor App (https://12factor.net/) with Poetry + Private Repos without better Environment Variable support.

adawalli avatar Dec 10 '19 13:12 adawalli

I want o add another reason for using variable interpolation in pyproject.toml. When you add a dependency on locally stored projects as in:

[tool.poetry.dev-dependencies]
thx-sphinx = {path = "../thx-sphinx"}

you're making strong assumptions on where people place their files that is definitely not a nice behaviour. Much better to set a default that users can overwrite. A .env is a typical solution in docker environment and not only (ie: autoenv). When you enter a directory the .env is read and configured correctly. This would make poetry flexible enought for normal workflow.

sandroden avatar Apr 29 '20 08:04 sandroden

This would be incredibly convenient for CI/CD pipelines and for reusing already available private repository urls in the form of environment variables.

papagala avatar Apr 29 '20 16:04 papagala

@sandroden, depending on what you want to accomplish, you might be interested also in the feature request #1168, which can be an alternative to path dependencies.

absassi avatar May 05 '20 10:05 absassi

@sdispater - Any reconsideration here? This is difficult when I want to test anything that needs environment variables but I can't set and unset them without editing the virtualenv activate file directly, which is a huge hassle. It makes it hard to test in multiple packages or environments that might need environment variables set, like DB_HOST, etc.

bubthegreat avatar May 29 '20 05:05 bubthegreat

the system administrator in me likes that. but apart from it, it would lead to a situation where poetry.lock wouldn't be reproducible without sharing all environment variables. and then, what would be the point?

besides, i'm missing defaults being mentioned in this thread for which Docker-Compose has a good syntax, as an example.

funkyfuture avatar May 30 '20 14:05 funkyfuture

I'm doing my own workarounds by having an .env file and pulling them from there, but my ideal world would be setting them locally in the virtualenv and adding them as checks in poetry.lock with a warning if they're not set.

bubthegreat avatar May 30 '20 17:05 bubthegreat

Assuming the following environment variables are set:

export EXAMPLE_PYPI_URL=https://pypi.example.com/pypi/
export EXAMPLE_PYPI_USERNAME=example
export EXAMPLE_PYPI_PASSWORD=example

This is how I handle uploads to a private PyPI server:

poetry build
poetry config repositories.example ${EXAMPLE_PYPI_URL}
poetry config http-basic.example ${EXAMPLE_PYPI_USERNAME} ${EXAMPLE_PYPI_PASSWORD}
poetry publish --repository example

I can see why adding environment variable expansion to pyproject.toml could be too much of a scope creep for Poetry.

jacebrowning avatar Aug 23 '20 22:08 jacebrowning

What should we do in the case that the url for the private repo contains private username and password? I.E.

[[tool.poetry.source]]                                                          
name = "private"                                                          
url = "https://${ARTIFACTORY_USER}:${ARTIFACTORY_APIKEY}@artifactory.corperation.com/artifactory/api/pypi/pip-local/simple"

SpicySyntax avatar Sep 25 '20 15:09 SpicySyntax

+1

What should we do in the case that the url for the private repo contains private username and password? I.E.

[[tool.poetry.source]]                                                          
name = "private"                                                          
url = "https://${ARTIFACTORY_USER}:${ARTIFACTORY_APIKEY}@artifactory.corperation.com/artifactory/api/pypi/pip-local/simple"

+1 on this. Any tips for poetry with private user/pass?

yousefissa avatar Sep 25 '20 21:09 yousefissa

With AWS codeartifact repository, the authentication token is a part of the URL, so this becomes even more important to get a smooth CI experience. Currently I am having to add git commits every time the token expires which is every 12 hours :(

gghildyal avatar Oct 08 '20 10:10 gghildyal

What should we do in the case that the url for the private repo contains private username and password? I.E.

[[tool.poetry.source]]                                                          
name = "private"                                                          
url = "https://${ARTIFACTORY_USER}:${ARTIFACTORY_APIKEY}@artifactory.corperation.com/artifactory/api/pypi/pip-local/simple"

Can't do poetry update with url set like this and depend on packages from our repository in local development. And yes – we would like CI to work too.

pawel-ch avatar Oct 20 '20 09:10 pawel-ch