Skip to content

Commit 3d84003

Browse files
milonimrodtheskumar
authored andcommitted
Support override variables (theskumar#63)
* Added an override option to the load_dotenv * Added test to override * added .idea to .gitignore * Added readme information * Added IPython magic option to override * Added a test for the IPython part. Both with and without override * Fixed make coverage (now looks for the correct src dir) * Added the verbose option to ipython * Added documentation about verbose and override * Fixed a small typo
1 parent 3aa526c commit 3d84003

File tree

7 files changed

+92
-19
lines changed

7 files changed

+92
-19
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ __pycache__
88
.DS_Store
99
htmlcov/
1010
.cache/
11+
.idea

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ test:
2626
py.test tests/
2727

2828
coverage:
29-
coverage run --source=dotenv.py --omit='*tests*' -m py.test tests/ -v --tb=native
29+
coverage run --source=dotenv --omit='*tests*' -m py.test tests/ -v --tb=native
3030
coverage report
3131

3232
coverage-html: coverage

README.rst

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ specified file -- called ``.env`` by default.
6363
from dotenv import load_dotenv, find_dotenv
6464
load_dotenv(find_dotenv())
6565
66+
You can also set _load_dotenv_ to override existing variables:
67+
.. code:: python
68+
69+
from dotenv import load_dotenv, find_dotenv
70+
load_dotenv(find_dotenv(), override=True)
71+
6672
Now, you can access the variables either from system environment
6773
variable or loaded from ``.env`` file. **System environment variables
6874
gets higher precedence** and it's advised not to include it in version control.
@@ -154,6 +160,12 @@ You can use dotenv with iPython. You can either let the dotenv search for .env w
154160
# Specify a particular file
155161
%dotenv relative/or/absolute/path/to/.env
156162

163+
# Use _-o_ to indicate override of existing variables
164+
%dotenv -o
165+
166+
# Use _-v_ to turn verbose mode on
167+
%dotenv -v
168+
157169

158170
Setting config on remote servers
159171
--------------------------------
@@ -220,7 +232,7 @@ commands like so ``fab config:set,<key1>,<value1> config:set,<key2>,<value2>``
220232
$ fab config:set,hello,world config:set,foo,bar config:set,fizz=buzz
221233

222234

223-
Releated Projects
235+
Related Projects
224236
=================
225237

226238
- `Honcho <https://github.com/nickstenning/honcho>`__ - For managing

dotenv/ipython.py

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,40 @@
11
from __future__ import print_function
22
from .main import load_dotenv, find_dotenv
33

4+
from IPython.core.magic import Magics, magics_class, line_magic
5+
from IPython.core.magic_arguments import (argument, magic_arguments,
6+
parse_argstring)
47

5-
def _magic(dotenv_path):
6-
"""
7-
dotenv [dotenv_path]
88

9-
Search in increasingly higher folders for the `dotenv_path`
10-
"""
11-
# Locate the .env file
12-
dotenv_path = dotenv_path or '.env'
13-
try:
14-
dotenv_path = find_dotenv(dotenv_path, True, True)
15-
except IOError:
16-
print("cannot find .env file")
17-
return
9+
@magics_class
10+
class IPythonDotEnv(Magics):
1811

19-
# Load the .env file
20-
load_dotenv(dotenv_path)
12+
@magic_arguments()
13+
@argument(
14+
'-o', '--override', action='store_true',
15+
help="Indicate to override existing variables"
16+
)
17+
@argument(
18+
'-v', '--verbose', action='store_true',
19+
help="Indicate function calls to be verbose"
20+
)
21+
@argument('dotenv_path', nargs='?', type=str, default='.env',
22+
help='Search in increasingly higher folders for the `dotenv_path`')
23+
@line_magic
24+
def dotenv(self, line):
25+
args = parse_argstring(self.dotenv, line)
26+
# Locate the .env file
27+
dotenv_path = args.dotenv_path
28+
try:
29+
dotenv_path = find_dotenv(dotenv_path, True, True)
30+
except IOError:
31+
print("cannot find .env file")
32+
return
33+
34+
# Load the .env file
35+
load_dotenv(dotenv_path, verbose=args.verbose, override=args.override)
2136

2237

2338
def load_ipython_extension(ipython):
2439
"""Register the %dotenv magic."""
25-
ipython.register_magic_function(_magic, magic_name='dotenv')
40+
ipython.register_magics(IPythonDotEnv)

dotenv/main.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def decode_escaped(escaped):
1616
return __escape_decoder(escaped)[0]
1717

1818

19-
def load_dotenv(dotenv_path, verbose=False):
19+
def load_dotenv(dotenv_path, verbose=False, override=False):
2020
"""
2121
Read a .env file and load into os.environ.
2222
"""
@@ -25,7 +25,10 @@ def load_dotenv(dotenv_path, verbose=False):
2525
warnings.warn("Not loading %s - it doesn't exist." % dotenv_path)
2626
return None
2727
for k, v in dotenv_values(dotenv_path).items():
28-
os.environ.setdefault(k, v)
28+
if override:
29+
os.environ[k] = v
30+
else:
31+
os.environ.setdefault(k, v)
2932
return True
3033

3134

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ wheel
66
pytest-cov
77
pytest-flake8
88
click
9+
ipython

tests/test_core.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import sh
77

88
from dotenv import load_dotenv, find_dotenv, set_key
9+
from IPython.terminal.embed import InteractiveShellEmbed
910

1011

1112
def test_warns_if_file_does_not_exist():
@@ -69,3 +70,43 @@ def test_load_dotenv(cli):
6970
assert 'DOTENV' in os.environ
7071
assert os.environ['DOTENV'] == 'WORKS'
7172
sh.rm(dotenv_path)
73+
74+
75+
def test_load_dotenv_override(cli):
76+
dotenv_path = '.test_load_dotenv_override'
77+
key_name = "DOTENV_OVER"
78+
79+
with cli.isolated_filesystem():
80+
sh.touch(dotenv_path)
81+
os.environ[key_name] = "OVERRIDE"
82+
set_key(dotenv_path, key_name, 'WORKS')
83+
success = load_dotenv(dotenv_path, override=True)
84+
assert success
85+
assert key_name in os.environ
86+
assert os.environ[key_name] == 'WORKS'
87+
sh.rm(dotenv_path)
88+
89+
90+
def test_ipython():
91+
tmpdir = os.path.realpath(tempfile.mkdtemp())
92+
os.chdir(tmpdir)
93+
filename = os.path.join(tmpdir, '.env')
94+
with open(filename, 'w') as f:
95+
f.write("MYNEWVALUE=q1w2e3\n")
96+
ipshell = InteractiveShellEmbed()
97+
ipshell.magic("load_ext dotenv")
98+
ipshell.magic("dotenv")
99+
assert os.environ["MYNEWVALUE"] == 'q1w2e3'
100+
101+
102+
def test_ipython_override():
103+
tmpdir = os.path.realpath(tempfile.mkdtemp())
104+
os.chdir(tmpdir)
105+
filename = os.path.join(tmpdir, '.env')
106+
os.environ["MYNEWVALUE"] = "OVERRIDE"
107+
with open(filename, 'w') as f:
108+
f.write("MYNEWVALUE=q1w2e3\n")
109+
ipshell = InteractiveShellEmbed()
110+
ipshell.magic("load_ext dotenv")
111+
ipshell.magic("dotenv -o")
112+
assert os.environ["MYNEWVALUE"] == 'q1w2e3'

0 commit comments

Comments
 (0)