11import os
22import sys
33import warnings
4+ from collections import OrderedDict
45
5- def read_dotenv ( dotenv = None ):
6+ def load_dotenv ( dotenv_path ):
67 """
7- Read a .env file into os.environ.
8-
9- If not given a path to a dotenv path, does filthy magic stack backtracking
10- to find manage.py and then find the dotenv.
8+ Read a .env file and load into os.environ.
119 """
12- if dotenv is None :
13- frame = sys ._getframe ()
14- dotenv = os .path .join (os .path .dirname (frame .f_back .f_code .co_filename ), '.env' )
15- if not os .path .exists (dotenv ):
16- warnings .warn ("not reading %s - it doesn't exist." % dotenv )
17- return
18- for k , v in parse_dotenv (dotenv ):
10+ if not os .path .exists (dotenv_path ):
11+ warnings .warn ("can't read %s - it doesn't exist." % dotenv_path )
12+ return None
13+ for k , v in parse_dotenv (dotenv_path ):
1914 os .environ .setdefault (k , v )
15+ return True
16+
17+
18+ def read_dotenv (dotenv_path ):
19+ warnings .warn ("read_dotenv deprecated, use load_dotenv instead" )
20+ return load_dotenv (dotenv_path )
2021
21- def write_dotenv (dotenv = None ):
22+
23+ def get_key (dotenv_path , key_to_get ):
24+ """
25+ Gets the value of a given key from the given .env
2226
27+ If the .env path given doesn't exist, fails
28+ """
29+ key_to_get = str (key_to_get )
30+ if not os .path .exists (dotenv_path ):
31+ warnings .warn ("can't read %s - it doesn't exist." % dotenv_path )
32+ return None
33+ dotenv_as_dict = OrderedDict (parse_dotenv (dotenv_path ))
34+ if dotenv_as_dict .has_key (key_to_get ):
35+ return dotenv_as_dict [key_to_get ]
36+ else :
37+ warnings .warn ("key %s not found in %s." % (key_to_get , dotenv_path ))
38+ return None
39+
40+
41+ def set_key (dotenv_path , key_to_set , value_to_set ):
42+ """
43+ Adds or Updates a key/value to the given .env
44+
45+ If the .env path given doesn't exist, fails instead of risking creating
46+ an orphan .env somewhere in the filesystem
47+ """
48+ key_to_set = str (key_to_set )
49+ value_to_set = str (value_to_set ).strip ("'" ).strip ('"' )
50+ if not os .path .exists (dotenv_path ):
51+ warnings .warn ("can't write to %s - it doesn't exist." % dotenv_path )
52+ return None
53+ dotenv_as_dict = OrderedDict (parse_dotenv (dotenv_path ))
54+ dotenv_as_dict [key_to_set ] = value_to_set
55+ success = flatten_and_write (dotenv_path , dotenv_as_dict )
56+ return success , key_to_set , value_to_set
2357
24- def parse_dotenv (dotenv ):
25- for line in open (dotenv ):
26- line = line .strip ()
27- if not line or line .startswith ('#' ) or '=' not in line :
28- continue
29- k , v = line .split ('=' , 1 )
30- v = v .strip ("'" ).strip ('"' )
31- yield k , v
58+
59+ def unset_key (dotenv_path , key_to_unset ):
60+ """
61+ Removes a given key from the given .env
62+
63+ If the .env path given doesn't exist, fails
64+ If the given key doesn't exist in the .env, fails
65+ """
66+ key_to_unset = str (key_to_unset )
67+ if not os .path .exists (dotenv_path ):
68+ warnings .warn ("can't delete from %s - it doesn't exist." % dotenv_path )
69+ return None
70+ dotenv_as_dict = OrderedDict (parse_dotenv (dotenv_path ))
71+ if dotenv_as_dict .has_key (key_to_unset ):
72+ dotenv_as_dict .pop (key_to_unset , None )
73+ else :
74+ warnings .warn ("key %s not removed from %s - key doesn't exist." % (key_to_unset , dotenv_path ))
75+ return None
76+ success = flatten_and_write (dotenv_path , dotenv_as_dict )
77+ return success , key_to_unset
78+
79+
80+ def parse_dotenv (dotenv_path ):
81+ with open (dotenv_path ) as f :
82+ for line in f :
83+ line = line .strip ()
84+ if not line or line .startswith ('#' ) or '=' not in line :
85+ continue
86+ k , v = line .split ('=' , 1 )
87+ v = v .strip ("'" ).strip ('"' )
88+ yield k , v
89+
90+
91+ def flatten_and_write (dotenv_path , dotenv_as_dict ):
92+ with open (dotenv_path , "w" ) as f :
93+ for k , v in dotenv_as_dict .items ():
94+ f .write ('%s="%s"\r \n ' % (k , v ))
95+ return True
96+
97+ if __name__ == "__main__" :
98+ import argparse
99+ parser = argparse .ArgumentParser ()
100+ parser .add_argument ("file_path" , help = "the absolute path of the .env file you want to use" )
101+ parser .add_argument ("action" , help = "what you want to do with the .env file (get, set, unset)" , nargs = '?' )
102+ parser .add_argument ("key" , help = "the environment key you want to set" , nargs = '?' )
103+ parser .add_argument ("value" , help = "the value you want to set 'key' to" , nargs = '?' )
104+ parser .add_argument ("--force" , help = "force writing even if the file at the given path doesn't end in .env" )
105+ args = parser .parse_args ()
106+
107+ if not os .path .exists (args .file_path ):
108+ warnings .warn ("there doesn't appear to be a file at %s" % args .file_path )
109+ exit (1 )
110+ if not args .force :
111+ if not args .file_path .endswith (".env" ):
112+ warnings .warn ("the file %s doesn't appear to be a .env file, use --force to proceed" % args .file_path )
113+ exit (1 )
114+
115+ if args .action == None :
116+ with open (args .file_path ) as f :
117+ print f .read ()
118+ exit (0 )
119+ elif args .action == "get" :
120+ stored_value = get_key (args .file_path , args .key )
121+ if stored_value != None :
122+ print (args .key )
123+ print (stored_value )
124+ else :
125+ exit (1 )
126+ elif args .action == "set" :
127+ success , key , value = set_key (args .file_path , args .key , args .value )
128+ if success != None :
129+ print ("%s: %s" % (key , value ))
130+ else :
131+ exit (1 )
132+ elif args .action == "unset" :
133+ success , key = unset_key (args .file_path , args .key )
134+ if success != None :
135+ print ("unset %s" % key )
136+ else :
137+ exit (1 )
138+ # Need to investigate if this can actually work or if the scope of the new environ variables
139+ # Expires when python exits
140+ #
141+ # elif args.action == "load":
142+ # success = load_dotenv(args.file_path)
143+ # if success != None:
144+ # print("loaded %s into environment" % args.file_path)
145+ # else:
146+ # exit(1)
147+ exit (0 )
0 commit comments