Merge pull request #1769 from dvf/dvf/parse-environment-variables

Allow values in Pipfile to consume Environment Variables
This commit is contained in:
2018-03-20 08:16:31 -04:00
committed by GitHub
3 changed files with 78 additions and 1 deletions
+21
View File
@@ -302,6 +302,27 @@ To prevent pipenv from loading the ``.env`` file, set the ``PIPENV_DONT_LOAD_ENV
$ PIPENV_DONT_LOAD_ENV=1 pipenv shell
☤ Support for Environment Variables
-----------------------------------
``pipenv`` supports the usage of environment variables in values. For example:
[[source]]
url = "https://${PYPI_USERNAME}:${PYPI_PASSWORD}@my_private_repo.example.com/simple"
verify_ssl = true
name = "pypi"
[dev-packages]
[packages]
requests = {version="*", index="home"}
maya = {version="*", index="pypi"}
records = "*"
Environment variables may be specified as ``${MY_ENVAR}`` or ``$MY_ENVAR``.
On Windows, ``%MY_ENVAR%`` is supported in addition to ``${MY_ENVAR}`` or ``$MY_ENVAR``.
☤ Configuration With Environment Variables
------------------------------------------
+22 -1
View File
@@ -62,6 +62,24 @@ class PipfileParser(object):
def __repr__(self):
return '<PipfileParser path={0!r}'.format(self.filename)
def inject_environment_variables(self, d):
"""
Recursively injects environment variables into TOML values
"""
if not d:
return d
for k, v in d.items():
if isinstance(v, str):
d[k] = os.path.expandvars(v)
elif isinstance(v, dict):
d[k] = self.inject_environment_variables(v)
elif isinstance(v, list):
d[k] = [self.inject_environment_variables(e) for e in v]
return d
def parse(self):
# Open the Pipfile.
with open(self.filename) as f:
@@ -78,8 +96,11 @@ class PipfileParser(object):
config = {}
config.update(default_config)
# Deserialize the TOML, and parse for Environment Variables
parsed_toml = self.inject_environment_variables(toml.loads(content))
# Load the Pipfile's configuration.
config.update(toml.loads(content))
config.update(parsed_toml)
# Structure the data for output.
data = {
+35
View File
@@ -1,5 +1,6 @@
# Make sure we use the patched packages.
import pipenv # noqa
import os
from prettytoml import lexer
from prettytoml.elements.atomic import AtomicElement
@@ -7,6 +8,7 @@ from prettytoml.elements.metadata import (
WhitespaceElement, PunctuationElement, CommentElement
)
from prettytoml.elements.table import TableElement
from pipenv.vendor.pipfile.api import PipfileParser
def test_table():
@@ -27,3 +29,36 @@ def test_table():
assert set(table.items()) == {('id', 42), ('age', 14)}
del table['id']
assert set(table.items()) == {('age', 14)}
class TestPipfileParser:
def test_inject_environment_variables(self):
os.environ['PYTEST_PIPFILE_TEST'] = "XYZ"
p = PipfileParser()
parsed_dict = p.inject_environment_variables({
"a_string": "https://$PYTEST_PIPFILE_TEST@something.com",
"another_string": "https://${PYTEST_PIPFILE_TEST}@something.com",
"nested": {
"a_string": "https://$PYTEST_PIPFILE_TEST@something.com",
"another_string": "${PYTEST_PIPFILE_TEST}",
},
"list": [
{
"a_string": "https://$PYTEST_PIPFILE_TEST@something.com",
"another_string": "${PYTEST_PIPFILE_TEST}"
},
{},
],
"bool": True,
"none": None,
})
assert parsed_dict["a_string"] == "https://XYZ@something.com"
assert parsed_dict["another_string"] == "https://XYZ@something.com"
assert parsed_dict["nested"]["another_string"] == "XYZ"
assert parsed_dict["list"][0]["a_string"] == "https://XYZ@something.com"
assert parsed_dict["list"][1] == {}
assert parsed_dict["bool"] is True
assert parsed_dict["none"] is None