from __future__ import absolute_import,print_function,unicode_literals _D='always' _C=True _B=False _A=None import io,logging,os,re,shutil,sys,tempfile from collections import OrderedDict from contextlib import contextmanager from.compat import IS_TYPE_CHECKING,PY2,StringIO,to_env from.parser import Binding,parse_stream logger=logging.getLogger(__name__) if IS_TYPE_CHECKING: from typing import Dict,Iterator,Match,Optional,Pattern,Union,Text,IO,Tuple if sys.version_info>=(3,6):_PathLike=os.PathLike else:_PathLike=Text if sys.version_info>=(3,0):_StringIO=StringIO else:_StringIO=StringIO[Text] __posix_variable=re.compile('\n \\$\\{\n (?P[^\\}:]*)\n (?::-\n (?P[^\\}]*)\n )?\n \\}\n ',re.VERBOSE) def with_warn_for_invalid_lines(mappings): for A in mappings: if A.error:logger.warning('Python-dotenv could not parse statement starting at line %s',A.original.line) yield A class DotEnv: def __init__(A,dotenv_path,verbose=_B,encoding=_A,interpolate=_C):A.dotenv_path=dotenv_path;A._dict=_A;A.verbose=verbose;A.encoding=encoding;A.interpolate=interpolate @contextmanager def _get_stream(self): A=self if isinstance(A.dotenv_path,StringIO):yield A.dotenv_path elif os.path.isfile(A.dotenv_path): with io.open(A.dotenv_path,encoding=A.encoding)as B:yield B else: if A.verbose:logger.info('Python-dotenv could not find configuration file %s.',A.dotenv_path or'.env') yield StringIO('') def dict(A): if A._dict:return A._dict B=OrderedDict(A.parse());A._dict=resolve_nested_variables(B)if A.interpolate else B;return A._dict def parse(B): with B._get_stream()as C: for A in with_warn_for_invalid_lines(parse_stream(C)): if A.key is not _A:yield(A.key,A.value) def set_as_environment_variables(C,override=_B): for(A,B)in C.dict().items(): if A in os.environ and not override:continue if B is not _A:os.environ[to_env(A)]=to_env(B) return _C def get(A,key): B=key;C=A.dict() if B in C:return C[B] if A.verbose:logger.warning('Key %s not found in %s.',B,A.dotenv_path) def get_key(dotenv_path,key_to_get):return DotEnv(dotenv_path,verbose=_C).get(key_to_get) @contextmanager def rewrite(path): try: with tempfile.NamedTemporaryFile(mode='w+',delete=_B)as A: with io.open(path)as B:yield(B,A) except BaseException: if os.path.isfile(A.name):os.unlink(A.name) raise else:shutil.move(A.name,path) def set_key(dotenv_path,key_to_set,value_to_set,quote_mode=_D): E=quote_mode;C=dotenv_path;B=key_to_set;A=value_to_set;A=A.strip("'").strip('"') if not os.path.exists(C):logger.warning("Can't write to %s - it doesn't exist.",C);return _A,B,A if' 'in A:E=_D if E==_D:F='"{}"'.format(A.replace('"','\\"')) else:F=A G='{}={}\n'.format(B,F) with rewrite(C)as(J,D): H=_B for I in with_warn_for_invalid_lines(parse_stream(J)): if I.key==B:D.write(G);H=_C else:D.write(I.original.string) if not H:D.write(G) return _C,B,A def unset_key(dotenv_path,key_to_unset,quote_mode=_D): B=dotenv_path;A=key_to_unset if not os.path.exists(B):logger.warning("Can't delete from %s - it doesn't exist.",B);return _A,A C=_B with rewrite(B)as(E,F): for D in with_warn_for_invalid_lines(parse_stream(E)): if D.key==A:C=_C else:F.write(D.original.string) if not C:logger.warning("Key %s not removed from %s - key doesn't exist.",A,B);return _A,A return C,A def resolve_nested_variables(values): def C(name,default):A=default;A=A if A is not _A else'';C=os.getenv(name,B.get(name,A));return C def D(match):A=match.groupdict();return C(name=A['name'],default=A['default']) B={} for(E,A)in values.items():B[E]=__posix_variable.sub(D,A)if A is not _A else _A return B def _walk_to_root(path): A=path if not os.path.exists(A):raise IOError('Starting path not found') if os.path.isfile(A):A=os.path.dirname(A) C=_A;B=os.path.abspath(A) while C!=B:yield B;D=os.path.abspath(os.path.join(B,os.path.pardir));C,B=B,D def find_dotenv(filename='.env',raise_error_if_not_found=_B,usecwd=_B): E='.py' def F():A='__file__';B=__import__('__main__',_A,_A,fromlist=[A]);return not hasattr(B,A) if usecwd or F()or getattr(sys,'frozen',_B):B=os.getcwd() else: A=sys._getframe() if PY2 and not __file__.endswith(E):C=__file__.rsplit('.',1)[0]+E else:C=__file__ while A.f_code.co_filename==C:assert A.f_back is not _A;A=A.f_back G=A.f_code.co_filename;B=os.path.dirname(os.path.abspath(G)) for H in _walk_to_root(B): D=os.path.join(H,filename) if os.path.isfile(D):return D if raise_error_if_not_found:raise IOError('File not found') return'' def load_dotenv(dotenv_path=_A,stream=_A,verbose=_B,override=_B,interpolate=_C,**A):B=dotenv_path or stream or find_dotenv();return DotEnv(B,verbose=verbose,interpolate=interpolate,**A).set_as_environment_variables(override=override) def dotenv_values(dotenv_path=_A,stream=_A,verbose=_B,interpolate=_C,**A):B=dotenv_path or stream or find_dotenv();return DotEnv(B,verbose=verbose,interpolate=interpolate,**A).dict()