Skip to content

Commit cceca1b

Browse files
committed
env
1 parent a71106e commit cceca1b

File tree

19 files changed

+1557
-2
lines changed

19 files changed

+1557
-2
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ node_modules/
1313
tests/coverage_html/
1414
tests/.coverage
1515
build/
16-
tests/report/
16+
tests/report/
17+
djangoStarter/.env

requirements.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
Django~=3.1.6
22
djangorestframework
33
psycopg2-binary
4-
django-crispy-forms
4+
django-crispy-forms
5+
python-dotenv

venv/bin/dotenv

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/home/ritesh/pythonProjects/djangoStarter/venv/bin/python
2+
# -*- coding: utf-8 -*-
3+
import re
4+
import sys
5+
from dotenv.cli import cli
6+
if __name__ == '__main__':
7+
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
8+
sys.exit(cli())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
from .compat import IS_TYPE_CHECKING
2+
from .main import load_dotenv, get_key, set_key, unset_key, find_dotenv, dotenv_values
3+
4+
if IS_TYPE_CHECKING:
5+
from typing import Any, Optional
6+
7+
8+
def load_ipython_extension(ipython):
9+
# type: (Any) -> None
10+
from .ipython import load_ipython_extension
11+
load_ipython_extension(ipython)
12+
13+
14+
def get_cli_string(path=None, action=None, key=None, value=None, quote=None):
15+
# type: (Optional[str], Optional[str], Optional[str], Optional[str], Optional[str]) -> str
16+
"""Returns a string suitable for running as a shell script.
17+
18+
Useful for converting a arguments passed to a fabric task
19+
to be passed to a `local` or `run` command.
20+
"""
21+
command = ['dotenv']
22+
if quote:
23+
command.append('-q %s' % quote)
24+
if path:
25+
command.append('-f %s' % path)
26+
if action:
27+
command.append(action)
28+
if key:
29+
command.append(key)
30+
if value:
31+
if ' ' in value:
32+
command.append('"%s"' % value)
33+
else:
34+
command.append(value)
35+
36+
return ' '.join(command).strip()
37+
38+
39+
__all__ = ['get_cli_string',
40+
'load_dotenv',
41+
'dotenv_values',
42+
'get_key',
43+
'set_key',
44+
'unset_key',
45+
'find_dotenv',
46+
'load_ipython_extension']
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import os
2+
import sys
3+
from subprocess import Popen
4+
5+
try:
6+
import click
7+
except ImportError:
8+
sys.stderr.write('It seems python-dotenv is not installed with cli option. \n'
9+
'Run pip install "python-dotenv[cli]" to fix this.')
10+
sys.exit(1)
11+
12+
from .compat import IS_TYPE_CHECKING, to_env
13+
from .main import dotenv_values, get_key, set_key, unset_key
14+
from .version import __version__
15+
16+
if IS_TYPE_CHECKING:
17+
from typing import Any, List, Dict
18+
19+
20+
@click.group()
21+
@click.option('-f', '--file', default=os.path.join(os.getcwd(), '.env'),
22+
type=click.Path(file_okay=True),
23+
help="Location of the .env file, defaults to .env file in current working directory.")
24+
@click.option('-q', '--quote', default='always',
25+
type=click.Choice(['always', 'never', 'auto']),
26+
help="Whether to quote or not the variable values. Default mode is always. This does not affect parsing.")
27+
@click.option('-e', '--export', default=False,
28+
type=click.BOOL,
29+
help="Whether to write the dot file as an executable bash script.")
30+
@click.version_option(version=__version__)
31+
@click.pass_context
32+
def cli(ctx, file, quote, export):
33+
# type: (click.Context, Any, Any, Any) -> None
34+
'''This script is used to set, get or unset values from a .env file.'''
35+
ctx.obj = {}
36+
ctx.obj['QUOTE'] = quote
37+
ctx.obj['EXPORT'] = export
38+
ctx.obj['FILE'] = file
39+
40+
41+
@cli.command()
42+
@click.pass_context
43+
def list(ctx):
44+
# type: (click.Context) -> None
45+
'''Display all the stored key/value.'''
46+
file = ctx.obj['FILE']
47+
if not os.path.isfile(file):
48+
raise click.BadParameter(
49+
'Path "%s" does not exist.' % (file),
50+
ctx=ctx
51+
)
52+
dotenv_as_dict = dotenv_values(file)
53+
for k, v in dotenv_as_dict.items():
54+
click.echo('%s=%s' % (k, v))
55+
56+
57+
@cli.command()
58+
@click.pass_context
59+
@click.argument('key', required=True)
60+
@click.argument('value', required=True)
61+
def set(ctx, key, value):
62+
# type: (click.Context, Any, Any) -> None
63+
'''Store the given key/value.'''
64+
file = ctx.obj['FILE']
65+
quote = ctx.obj['QUOTE']
66+
export = ctx.obj['EXPORT']
67+
success, key, value = set_key(file, key, value, quote, export)
68+
if success:
69+
click.echo('%s=%s' % (key, value))
70+
else:
71+
exit(1)
72+
73+
74+
@cli.command()
75+
@click.pass_context
76+
@click.argument('key', required=True)
77+
def get(ctx, key):
78+
# type: (click.Context, Any) -> None
79+
'''Retrieve the value for the given key.'''
80+
file = ctx.obj['FILE']
81+
if not os.path.isfile(file):
82+
raise click.BadParameter(
83+
'Path "%s" does not exist.' % (file),
84+
ctx=ctx
85+
)
86+
stored_value = get_key(file, key)
87+
if stored_value:
88+
click.echo('%s=%s' % (key, stored_value))
89+
else:
90+
exit(1)
91+
92+
93+
@cli.command()
94+
@click.pass_context
95+
@click.argument('key', required=True)
96+
def unset(ctx, key):
97+
# type: (click.Context, Any) -> None
98+
'''Removes the given key.'''
99+
file = ctx.obj['FILE']
100+
quote = ctx.obj['QUOTE']
101+
success, key = unset_key(file, key, quote)
102+
if success:
103+
click.echo("Successfully removed %s" % key)
104+
else:
105+
exit(1)
106+
107+
108+
@cli.command(context_settings={'ignore_unknown_options': True})
109+
@click.pass_context
110+
@click.argument('commandline', nargs=-1, type=click.UNPROCESSED)
111+
def run(ctx, commandline):
112+
# type: (click.Context, List[str]) -> None
113+
"""Run command with environment variables present."""
114+
file = ctx.obj['FILE']
115+
if not os.path.isfile(file):
116+
raise click.BadParameter(
117+
'Invalid value for \'-f\' "%s" does not exist.' % (file),
118+
ctx=ctx
119+
)
120+
dotenv_as_dict = {to_env(k): to_env(v) for (k, v) in dotenv_values(file).items() if v is not None}
121+
122+
if not commandline:
123+
click.echo('No command given.')
124+
exit(1)
125+
ret = run_command(commandline, dotenv_as_dict)
126+
exit(ret)
127+
128+
129+
def run_command(command, env):
130+
# type: (List[str], Dict[str, str]) -> int
131+
"""Run command in sub process.
132+
133+
Runs the command in a sub process with the variables from `env`
134+
added in the current environment variables.
135+
136+
Parameters
137+
----------
138+
command: List[str]
139+
The command and it's parameters
140+
env: Dict
141+
The additional environment variables
142+
143+
Returns
144+
-------
145+
int
146+
The return code of the command
147+
148+
"""
149+
# copy the current environment variables and add the vales from
150+
# `env`
151+
cmd_env = os.environ.copy()
152+
cmd_env.update(env)
153+
154+
p = Popen(command,
155+
universal_newlines=True,
156+
bufsize=0,
157+
shell=False,
158+
env=cmd_env)
159+
_, _ = p.communicate()
160+
161+
return p.returncode
162+
163+
164+
if __name__ == "__main__":
165+
cli()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import sys
2+
3+
PY2 = sys.version_info[0] == 2 # type: bool
4+
5+
if PY2:
6+
from StringIO import StringIO # noqa
7+
else:
8+
from io import StringIO # noqa
9+
10+
11+
def is_type_checking():
12+
# type: () -> bool
13+
try:
14+
from typing import TYPE_CHECKING
15+
except ImportError:
16+
return False
17+
return TYPE_CHECKING
18+
19+
20+
IS_TYPE_CHECKING = is_type_checking()
21+
22+
23+
if IS_TYPE_CHECKING:
24+
from typing import Text
25+
26+
27+
def to_env(text):
28+
# type: (Text) -> str
29+
"""
30+
Encode a string the same way whether it comes from the environment or a `.env` file.
31+
"""
32+
if PY2:
33+
return text.encode(sys.getfilesystemencoding() or "utf-8")
34+
else:
35+
return text
36+
37+
38+
def to_text(string):
39+
# type: (str) -> Text
40+
"""
41+
Make a string Unicode if it isn't already.
42+
43+
This is useful for defining raw unicode strings because `ur"foo"` isn't valid in
44+
Python 3.
45+
"""
46+
if PY2:
47+
return string.decode("utf-8")
48+
else:
49+
return string
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from __future__ import print_function
2+
3+
from IPython.core.magic import Magics, line_magic, magics_class # type: ignore
4+
from IPython.core.magic_arguments import (argument, magic_arguments, # type: ignore
5+
parse_argstring) # type: ignore
6+
7+
from .main import find_dotenv, load_dotenv
8+
9+
10+
@magics_class
11+
class IPythonDotEnv(Magics):
12+
13+
@magic_arguments()
14+
@argument(
15+
'-o', '--override', action='store_true',
16+
help="Indicate to override existing variables"
17+
)
18+
@argument(
19+
'-v', '--verbose', action='store_true',
20+
help="Indicate function calls to be verbose"
21+
)
22+
@argument('dotenv_path', nargs='?', type=str, default='.env',
23+
help='Search in increasingly higher folders for the `dotenv_path`')
24+
@line_magic
25+
def dotenv(self, line):
26+
args = parse_argstring(self.dotenv, line)
27+
# Locate the .env file
28+
dotenv_path = args.dotenv_path
29+
try:
30+
dotenv_path = find_dotenv(dotenv_path, True, True)
31+
except IOError:
32+
print("cannot find .env file")
33+
return
34+
35+
# Load the .env file
36+
load_dotenv(dotenv_path, verbose=args.verbose, override=args.override)
37+
38+
39+
def load_ipython_extension(ipython):
40+
"""Register the %dotenv magic."""
41+
ipython.register_magics(IPythonDotEnv)

0 commit comments

Comments
 (0)