From 1167e7b2f24dc4f2732f9e52cd5b841134d77d16 Mon Sep 17 00:00:00 2001 From: Nimrod Milo Date: Mon, 21 Aug 2017 22:41:03 +0300 Subject: [PATCH 01/10] Added an override option to the load_dotenv --- dotenv/main.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dotenv/main.py b/dotenv/main.py index de1eb6f0..c9f5a9e2 100644 --- a/dotenv/main.py +++ b/dotenv/main.py @@ -16,7 +16,7 @@ def decode_escaped(escaped): return __escape_decoder(escaped)[0] -def load_dotenv(dotenv_path): +def load_dotenv(dotenv_path, override=False): """ Read a .env file and load into os.environ. """ @@ -24,7 +24,10 @@ def load_dotenv(dotenv_path): warnings.warn("Not loading %s - it doesn't exist." % dotenv_path) return None for k, v in dotenv_values(dotenv_path).items(): - os.environ.setdefault(k, v) + if override: + os.environ[k] = v + else: + os.environ.setdefault(k, v) return True From 4a9392c5ffade98efdd6a548cd9b10452b872a7a Mon Sep 17 00:00:00 2001 From: Nimrod Milo Date: Mon, 21 Aug 2017 22:41:18 +0300 Subject: [PATCH 02/10] Added test to override --- tests/test_core.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/test_core.py b/tests/test_core.py index 29f0f9a3..9ce20f57 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -69,3 +69,18 @@ def test_load_dotenv(cli): assert 'DOTENV' in os.environ assert os.environ['DOTENV'] == 'WORKS' sh.rm(dotenv_path) + + +def test_load_dotenv_override(cli): + dotenv_path = '.test_load_dotenv_override' + key_name = "DOTENV_OVER" + + with cli.isolated_filesystem(): + sh.touch(dotenv_path) + os.environ[key_name] = "OVERRIDE" + set_key(dotenv_path, key_name, 'WORKS') + success = load_dotenv(dotenv_path, override=True) + assert success + assert key_name in os.environ + assert os.environ[key_name] == 'WORKS' + sh.rm(dotenv_path) From 8d94c30d4896e99adbc40a55e902ba2e18d072c0 Mon Sep 17 00:00:00 2001 From: Nimrod Milo Date: Mon, 21 Aug 2017 22:42:05 +0300 Subject: [PATCH 03/10] added .idea to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d4939536..d2a48392 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ __pycache__ .DS_Store htmlcov/ .cache/ +.idea From ee6bde5a5096a5956df72cb9886e660f18db53eb Mon Sep 17 00:00:00 2001 From: Nimrod Milo Date: Mon, 21 Aug 2017 22:49:41 +0300 Subject: [PATCH 04/10] Added readme information --- README.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.rst b/README.rst index e41aa9d0..93f33e37 100644 --- a/README.rst +++ b/README.rst @@ -60,6 +60,12 @@ specified file -- called ``.env`` by default. from dotenv import load_dotenv, find_dotenv load_dotenv(find_dotenv()) +You can also set _load_dotenv_ to override existing variables: +.. code:: python + + from dotenv import load_dotenv, find_dotenv + load_dotenv(find_dotenv(), override=True) + Now, you can access the variables either from system environment variable or loaded from ``.env`` file. **System environment variables gets higher precedence** and it's advised not to include it in version control. From d4f32431cb9e2a6404e3f2184794b69e66645fa1 Mon Sep 17 00:00:00 2001 From: Nimrod Milo Date: Tue, 22 Aug 2017 00:12:26 +0300 Subject: [PATCH 05/10] Added IPython magic option to override --- dotenv/ipython.py | 41 ++++++++++++++++++++++++++--------------- requirements.txt | 1 + 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/dotenv/ipython.py b/dotenv/ipython.py index ffb74f05..31ca20d0 100644 --- a/dotenv/ipython.py +++ b/dotenv/ipython.py @@ -1,25 +1,36 @@ from __future__ import print_function from .main import load_dotenv, find_dotenv +from IPython.core.magic import Magics, magics_class, line_magic +from IPython.core.magic_arguments import (argument, magic_arguments, + parse_argstring) -def _magic(dotenv_path): - """ - dotenv [dotenv_path] - Search in increasingly higher folders for the `dotenv_path` - """ - # Locate the .env file - dotenv_path = dotenv_path or '.env' - try: - dotenv_path = find_dotenv(dotenv_path, True, True) - except IOError: - print("cannot find .env file") - return +@magics_class +class IPythonDotEnv(Magics): - # Load the .env file - load_dotenv(dotenv_path) + @magic_arguments() + @argument( + '-o', '--override', action='store_true', + help="Indicate to override existing variables" + ) + @argument('dotenv_path', nargs='?', type=str, default='.env', + help='Search in increasingly higher folders for the `dotenv_path`') + @line_magic + def dotenv(self, line): + args = parse_argstring(self.dotenv, line) + # Locate the .env file + dotenv_path = args.dotenv_path + try: + dotenv_path = find_dotenv(dotenv_path, True, True) + except IOError: + print("cannot find .env file") + return + + # Load the .env file + load_dotenv(dotenv_path, override=args.override) def load_ipython_extension(ipython): """Register the %dotenv magic.""" - ipython.register_magic_function(_magic, magic_name='dotenv') + ipython.register_magics(IPythonDotEnv) diff --git a/requirements.txt b/requirements.txt index 55a766b6..673cb101 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,3 +6,4 @@ wheel pytest-cov pytest-flake8 click +ipython From 249cbdd80a5e5b2f04d2cacd91d917365f75f5d5 Mon Sep 17 00:00:00 2001 From: Nimrod Milo Date: Tue, 22 Aug 2017 10:47:35 +0300 Subject: [PATCH 06/10] Added a test for the IPython part. Both with and without override --- tests/test_core.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/test_core.py b/tests/test_core.py index 9ce20f57..0572913e 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -6,6 +6,7 @@ import sh from dotenv import load_dotenv, find_dotenv, set_key +from IPython.terminal.embed import InteractiveShellEmbed def test_warns_if_file_does_not_exist(): @@ -84,3 +85,28 @@ def test_load_dotenv_override(cli): assert key_name in os.environ assert os.environ[key_name] == 'WORKS' sh.rm(dotenv_path) + + +def test_ipython(): + tmpdir = os.path.realpath(tempfile.mkdtemp()) + os.chdir(tmpdir) + filename = os.path.join(tmpdir, '.env') + with open(filename, 'w') as f: + f.write("MYNEWVALUE=q1w2e3\n") + ipshell = InteractiveShellEmbed() + ipshell.magic("load_ext dotenv") + ipshell.magic("dotenv") + assert os.environ["MYNEWVALUE"] == 'q1w2e3' + + +def test_ipython_override(): + tmpdir = os.path.realpath(tempfile.mkdtemp()) + os.chdir(tmpdir) + filename = os.path.join(tmpdir, '.env') + os.environ["MYNEWVALUE"] = "OVERRIDE" + with open(filename, 'w') as f: + f.write("MYNEWVALUE=q1w2e3\n") + ipshell = InteractiveShellEmbed() + ipshell.magic("load_ext dotenv") + ipshell.magic("dotenv -o") + assert os.environ["MYNEWVALUE"] == 'q1w2e3' From 9679acea70b1756300cb467bf0a4c11bd357adde Mon Sep 17 00:00:00 2001 From: Nimrod Milo Date: Wed, 23 Aug 2017 08:18:56 +0300 Subject: [PATCH 07/10] Fixed make coverage (now looks for the correct src dir) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index bad2c7d3..50b80b40 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ test: py.test tests/ coverage: - coverage run --source=dotenv.py --omit='*tests*' -m py.test tests/ -v --tb=native + coverage run --source=dotenv --omit='*tests*' -m py.test tests/ -v --tb=native coverage report coverage-html: coverage From ed75d34eaaff39d5b78ff570ac822cd62718aa47 Mon Sep 17 00:00:00 2001 From: Nimrod Milo Date: Wed, 23 Aug 2017 09:32:42 +0300 Subject: [PATCH 08/10] Added the verbose option to ipython --- dotenv/ipython.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dotenv/ipython.py b/dotenv/ipython.py index 31ca20d0..7d84ac20 100644 --- a/dotenv/ipython.py +++ b/dotenv/ipython.py @@ -14,6 +14,10 @@ class IPythonDotEnv(Magics): '-o', '--override', action='store_true', help="Indicate to override existing variables" ) + @argument( + '-v', '--verbose', action='store_true', + help="Indicate function calls to be verbose" + ) @argument('dotenv_path', nargs='?', type=str, default='.env', help='Search in increasingly higher folders for the `dotenv_path`') @line_magic @@ -28,7 +32,7 @@ def dotenv(self, line): return # Load the .env file - load_dotenv(dotenv_path, override=args.override) + load_dotenv(dotenv_path, verbose=args.verbose, override=args.override) def load_ipython_extension(ipython): From edc41313a31fbbbfc394a3efa161d36c1c639219 Mon Sep 17 00:00:00 2001 From: Nimrod Milo Date: Wed, 23 Aug 2017 09:34:42 +0300 Subject: [PATCH 09/10] Added documentation about verbose and override --- README.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.rst b/README.rst index 1e3fcc64..ccc73f6a 100644 --- a/README.rst +++ b/README.rst @@ -160,6 +160,12 @@ You can use dotenv with iPython. You can either let the dotenv search for .env w # Specify a particular file %dotenv relative/or/absolute/path/to/.env + # Use _-o_ to indicate override of existing variables + %dotenv -o + + # Use _-v_ to turn verbose mode on + %dotenv -v + Setting config on remote servers -------------------------------- From e2131be8ec92ef527372f3037130997b4ac86ca4 Mon Sep 17 00:00:00 2001 From: Nimrod Milo Date: Wed, 23 Aug 2017 11:23:31 +0300 Subject: [PATCH 10/10] Fixed a small typo --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index ccc73f6a..08c3f156 100644 --- a/README.rst +++ b/README.rst @@ -232,7 +232,7 @@ commands like so ``fab config:set,, config:set,,`` $ fab config:set,hello,world config:set,foo,bar config:set,fizz=buzz -Releated Projects +Related Projects ================= - `Honcho `__ - For managing