mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 22:50:18 +00:00
Vendor in latest python-dotenv.
This commit is contained in:
Vendored
+11
-71
@@ -1,78 +1,18 @@
|
||||
python-dotenv
|
||||
Copyright (c) 2014, Saurabh Kumar
|
||||
|
||||
All rights reserved.
|
||||
Copyright (c) 2014, Saurabh Kumar (python-dotenv), 2013, Ted Tieken (django-dotenv-rw), 2013, Jacob Kaplan-Moss (django-dotenv)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of python-dotenv nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
django-dotenv-rw
|
||||
Copyright (c) 2013, Ted Tieken
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of django-dotenv nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Original django-dotenv
|
||||
Copyright (c) 2013, Jacob Kaplan-Moss
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of django-dotenv nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
- Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of django-dotenv nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
|
||||
Vendored
+3
-3
@@ -23,16 +23,16 @@ def get_cli_string(
|
||||
"""
|
||||
command = ['dotenv']
|
||||
if quote:
|
||||
command.append('-q %s' % quote)
|
||||
command.append(f'-q {quote}')
|
||||
if path:
|
||||
command.append('-f %s' % path)
|
||||
command.append(f'-f {path}')
|
||||
if action:
|
||||
command.append(action)
|
||||
if key:
|
||||
command.append(key)
|
||||
if value:
|
||||
if ' ' in value:
|
||||
command.append('"%s"' % value)
|
||||
command.append(f'"{value}"')
|
||||
else:
|
||||
command.append(value)
|
||||
|
||||
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
"""Entry point for cli, enables execution with `python -m dotenv`"""
|
||||
|
||||
from .cli import cli
|
||||
|
||||
if __name__ == "__main__":
|
||||
cli()
|
||||
Vendored
+69
-34
@@ -1,7 +1,10 @@
|
||||
import json
|
||||
import os
|
||||
import shlex
|
||||
import sys
|
||||
from contextlib import contextmanager
|
||||
from subprocess import Popen
|
||||
from typing import Any, Dict, List
|
||||
from typing import Any, Dict, IO, Iterator, List
|
||||
|
||||
try:
|
||||
import pipenv.vendor.click as click
|
||||
@@ -10,12 +13,26 @@ except ImportError:
|
||||
'Run pip install "python-dotenv[cli]" to fix this.')
|
||||
sys.exit(1)
|
||||
|
||||
from .main import dotenv_values, get_key, set_key, unset_key
|
||||
from .main import dotenv_values, set_key, unset_key
|
||||
from .version import __version__
|
||||
|
||||
|
||||
def enumerate_env():
|
||||
"""
|
||||
Return a path for the ${pwd}/.env file.
|
||||
|
||||
If pwd does not exist, return None.
|
||||
"""
|
||||
try:
|
||||
cwd = os.getcwd()
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
path = os.path.join(cwd, '.env')
|
||||
return path
|
||||
|
||||
|
||||
@click.group()
|
||||
@click.option('-f', '--file', default=os.path.join(os.getcwd(), '.env'),
|
||||
@click.option('-f', '--file', default=enumerate_env(),
|
||||
type=click.Path(file_okay=True),
|
||||
help="Location of the .env file, defaults to .env file in current working directory.")
|
||||
@click.option('-q', '--quote', default='always',
|
||||
@@ -27,26 +44,49 @@ from .version import __version__
|
||||
@click.version_option(version=__version__)
|
||||
@click.pass_context
|
||||
def cli(ctx: click.Context, file: Any, quote: Any, export: Any) -> None:
|
||||
'''This script is used to set, get or unset values from a .env file.'''
|
||||
ctx.obj = {}
|
||||
ctx.obj['QUOTE'] = quote
|
||||
ctx.obj['EXPORT'] = export
|
||||
ctx.obj['FILE'] = file
|
||||
"""This script is used to set, get or unset values from a .env file."""
|
||||
ctx.obj = {'QUOTE': quote, 'EXPORT': export, 'FILE': file}
|
||||
|
||||
|
||||
@contextmanager
|
||||
def stream_file(path: os.PathLike) -> Iterator[IO[str]]:
|
||||
"""
|
||||
Open a file and yield the corresponding (decoded) stream.
|
||||
|
||||
Exits with error code 2 if the file cannot be opened.
|
||||
"""
|
||||
|
||||
try:
|
||||
with open(path) as stream:
|
||||
yield stream
|
||||
except OSError as exc:
|
||||
print(f"Error opening env file: {exc}", file=sys.stderr)
|
||||
exit(2)
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.pass_context
|
||||
def list(ctx: click.Context) -> None:
|
||||
'''Display all the stored key/value.'''
|
||||
@click.option('--format', default='simple',
|
||||
type=click.Choice(['simple', 'json', 'shell', 'export']),
|
||||
help="The format in which to display the list. Default format is simple, "
|
||||
"which displays name=value without quotes.")
|
||||
def list(ctx: click.Context, format: bool) -> None:
|
||||
"""Display all the stored key/value."""
|
||||
file = ctx.obj['FILE']
|
||||
if not os.path.isfile(file):
|
||||
raise click.BadParameter(
|
||||
'Path "%s" does not exist.' % (file),
|
||||
ctx=ctx
|
||||
)
|
||||
dotenv_as_dict = dotenv_values(file)
|
||||
for k, v in dotenv_as_dict.items():
|
||||
click.echo('%s=%s' % (k, v))
|
||||
|
||||
with stream_file(file) as stream:
|
||||
values = dotenv_values(stream=stream)
|
||||
|
||||
if format == 'json':
|
||||
click.echo(json.dumps(values, indent=2, sort_keys=True))
|
||||
else:
|
||||
prefix = 'export ' if format == 'export' else ''
|
||||
for k in sorted(values):
|
||||
v = values[k]
|
||||
if v is not None:
|
||||
if format in ('export', 'shell'):
|
||||
v = shlex.quote(v)
|
||||
click.echo(f'{prefix}{k}={v}')
|
||||
|
||||
|
||||
@cli.command()
|
||||
@@ -54,13 +94,13 @@ def list(ctx: click.Context) -> None:
|
||||
@click.argument('key', required=True)
|
||||
@click.argument('value', required=True)
|
||||
def set(ctx: click.Context, key: Any, value: Any) -> None:
|
||||
'''Store the given key/value.'''
|
||||
"""Store the given key/value."""
|
||||
file = ctx.obj['FILE']
|
||||
quote = ctx.obj['QUOTE']
|
||||
export = ctx.obj['EXPORT']
|
||||
success, key, value = set_key(file, key, value, quote, export)
|
||||
if success:
|
||||
click.echo('%s=%s' % (key, value))
|
||||
click.echo(f'{key}={value}')
|
||||
else:
|
||||
exit(1)
|
||||
|
||||
@@ -69,14 +109,13 @@ def set(ctx: click.Context, key: Any, value: Any) -> None:
|
||||
@click.pass_context
|
||||
@click.argument('key', required=True)
|
||||
def get(ctx: click.Context, key: Any) -> None:
|
||||
'''Retrieve the value for the given key.'''
|
||||
"""Retrieve the value for the given key."""
|
||||
file = ctx.obj['FILE']
|
||||
if not os.path.isfile(file):
|
||||
raise click.BadParameter(
|
||||
'Path "%s" does not exist.' % (file),
|
||||
ctx=ctx
|
||||
)
|
||||
stored_value = get_key(file, key)
|
||||
|
||||
with stream_file(file) as stream:
|
||||
values = dotenv_values(stream=stream)
|
||||
|
||||
stored_value = values.get(key)
|
||||
if stored_value:
|
||||
click.echo(stored_value)
|
||||
else:
|
||||
@@ -87,12 +126,12 @@ def get(ctx: click.Context, key: Any) -> None:
|
||||
@click.pass_context
|
||||
@click.argument('key', required=True)
|
||||
def unset(ctx: click.Context, key: Any) -> None:
|
||||
'''Removes the given key.'''
|
||||
"""Removes the given key."""
|
||||
file = ctx.obj['FILE']
|
||||
quote = ctx.obj['QUOTE']
|
||||
success, key = unset_key(file, key, quote)
|
||||
if success:
|
||||
click.echo("Successfully removed %s" % key)
|
||||
click.echo(f"Successfully removed {key}")
|
||||
else:
|
||||
exit(1)
|
||||
|
||||
@@ -110,7 +149,7 @@ def run(ctx: click.Context, override: bool, commandline: List[str]) -> None:
|
||||
file = ctx.obj['FILE']
|
||||
if not os.path.isfile(file):
|
||||
raise click.BadParameter(
|
||||
'Invalid value for \'-f\' "%s" does not exist.' % (file),
|
||||
f'Invalid value for \'-f\' "{file}" does not exist.',
|
||||
ctx=ctx
|
||||
)
|
||||
dotenv_as_dict = {
|
||||
@@ -158,7 +197,3 @@ def run_command(command: List[str], env: Dict[str, str]) -> int:
|
||||
_, _ = p.communicate()
|
||||
|
||||
return p.returncode
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
cli()
|
||||
|
||||
Vendored
+85
-63
@@ -12,12 +12,13 @@ from typing import (IO, Dict, Iterable, Iterator, Mapping, Optional, Tuple,
|
||||
from .parser import Binding, parse_stream
|
||||
from .variables import parse_variables
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
# A type alias for a string path to be used for the paths in this file.
|
||||
# These paths may flow to `open()` and `shutil.move()`; `shutil.move()`
|
||||
# only accepts string paths, not byte paths or file descriptors. See
|
||||
# https://github.com/python/typeshed/pull/6832.
|
||||
StrPath = Union[str, 'os.PathLike[str]']
|
||||
|
||||
if sys.version_info >= (3, 6):
|
||||
_PathLike = os.PathLike
|
||||
else:
|
||||
_PathLike = str
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def with_warn_for_invalid_lines(mappings: Iterator[Binding]) -> Iterator[Binding]:
|
||||
@@ -30,28 +31,28 @@ def with_warn_for_invalid_lines(mappings: Iterator[Binding]) -> Iterator[Binding
|
||||
yield mapping
|
||||
|
||||
|
||||
class DotEnv():
|
||||
class DotEnv:
|
||||
def __init__(
|
||||
self,
|
||||
dotenv_path: Optional[Union[str, _PathLike]],
|
||||
dotenv_path: Optional[StrPath],
|
||||
stream: Optional[IO[str]] = None,
|
||||
verbose: bool = False,
|
||||
encoding: Union[None, str] = None,
|
||||
encoding: Optional[str] = None,
|
||||
interpolate: bool = True,
|
||||
override: bool = True,
|
||||
) -> None:
|
||||
self.dotenv_path = dotenv_path # type: Optional[Union[str, _PathLike]]
|
||||
self.stream = stream # type: Optional[IO[str]]
|
||||
self._dict = None # type: Optional[Dict[str, Optional[str]]]
|
||||
self.verbose = verbose # type: bool
|
||||
self.encoding = encoding # type: Union[None, str]
|
||||
self.interpolate = interpolate # type: bool
|
||||
self.override = override # type: bool
|
||||
self.dotenv_path: Optional[StrPath] = dotenv_path
|
||||
self.stream: Optional[IO[str]] = stream
|
||||
self._dict: Optional[Dict[str, Optional[str]]] = None
|
||||
self.verbose: bool = verbose
|
||||
self.encoding: Optional[str] = encoding
|
||||
self.interpolate: bool = interpolate
|
||||
self.override: bool = override
|
||||
|
||||
@contextmanager
|
||||
def _get_stream(self) -> Iterator[IO[str]]:
|
||||
if self.dotenv_path and os.path.isfile(self.dotenv_path):
|
||||
with io.open(self.dotenv_path, encoding=self.encoding) as stream:
|
||||
with open(self.dotenv_path, encoding=self.encoding) as stream:
|
||||
yield stream
|
||||
elif self.stream is not None:
|
||||
yield self.stream
|
||||
@@ -87,6 +88,9 @@ class DotEnv():
|
||||
"""
|
||||
Load the current dotenv as system environment variable.
|
||||
"""
|
||||
if not self.dict():
|
||||
return False
|
||||
|
||||
for k, v in self.dict().items():
|
||||
if k in os.environ and not self.override:
|
||||
continue
|
||||
@@ -109,38 +113,44 @@ class DotEnv():
|
||||
return None
|
||||
|
||||
|
||||
def get_key(dotenv_path: Union[str, _PathLike], key_to_get: str) -> Optional[str]:
|
||||
def get_key(
|
||||
dotenv_path: StrPath,
|
||||
key_to_get: str,
|
||||
encoding: Optional[str] = "utf-8",
|
||||
) -> Optional[str]:
|
||||
"""
|
||||
Gets the value of a given key from the given .env
|
||||
Get the value of a given key from the given .env.
|
||||
|
||||
If the .env path given doesn't exist, fails
|
||||
Returns `None` if the key isn't found or doesn't have a value.
|
||||
"""
|
||||
return DotEnv(dotenv_path, verbose=True).get(key_to_get)
|
||||
return DotEnv(dotenv_path, verbose=True, encoding=encoding).get(key_to_get)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def rewrite(path: Union[str, _PathLike]) -> Iterator[Tuple[IO[str], IO[str]]]:
|
||||
try:
|
||||
if not os.path.isfile(path):
|
||||
with io.open(path, "w+") as source:
|
||||
source.write("")
|
||||
with tempfile.NamedTemporaryFile(mode="w+", delete=False) as dest:
|
||||
with io.open(path) as source:
|
||||
yield (source, dest) # type: ignore
|
||||
except BaseException:
|
||||
if os.path.isfile(dest.name):
|
||||
def rewrite(
|
||||
path: StrPath,
|
||||
encoding: Optional[str],
|
||||
) -> Iterator[Tuple[IO[str], IO[str]]]:
|
||||
if not os.path.isfile(path):
|
||||
with open(path, mode="w", encoding=encoding) as source:
|
||||
source.write("")
|
||||
with tempfile.NamedTemporaryFile(mode="w", encoding=encoding, delete=False) as dest:
|
||||
try:
|
||||
with open(path, encoding=encoding) as source:
|
||||
yield (source, dest)
|
||||
except BaseException:
|
||||
os.unlink(dest.name)
|
||||
raise
|
||||
else:
|
||||
shutil.move(dest.name, path)
|
||||
raise
|
||||
shutil.move(dest.name, path)
|
||||
|
||||
|
||||
def set_key(
|
||||
dotenv_path: Union[str, _PathLike],
|
||||
dotenv_path: StrPath,
|
||||
key_to_set: str,
|
||||
value_to_set: str,
|
||||
quote_mode: str = "always",
|
||||
export: bool = False,
|
||||
encoding: Optional[str] = "utf-8",
|
||||
) -> Tuple[Optional[bool], str, str]:
|
||||
"""
|
||||
Adds or Updates a key/value to the given .env
|
||||
@@ -149,7 +159,7 @@ def set_key(
|
||||
an orphan .env somewhere in the filesystem
|
||||
"""
|
||||
if quote_mode not in ("always", "auto", "never"):
|
||||
raise ValueError("Unknown quote_mode: {}".format(quote_mode))
|
||||
raise ValueError(f"Unknown quote_mode: {quote_mode}")
|
||||
|
||||
quote = (
|
||||
quote_mode == "always"
|
||||
@@ -161,41 +171,46 @@ def set_key(
|
||||
else:
|
||||
value_out = value_to_set
|
||||
if export:
|
||||
line_out = 'export {}={}\n'.format(key_to_set, value_out)
|
||||
line_out = f'export {key_to_set}={value_out}\n'
|
||||
else:
|
||||
line_out = "{}={}\n".format(key_to_set, value_out)
|
||||
line_out = f"{key_to_set}={value_out}\n"
|
||||
|
||||
with rewrite(dotenv_path) as (source, dest):
|
||||
with rewrite(dotenv_path, encoding=encoding) as (source, dest):
|
||||
replaced = False
|
||||
missing_newline = False
|
||||
for mapping in with_warn_for_invalid_lines(parse_stream(source)):
|
||||
if mapping.key == key_to_set:
|
||||
dest.write(line_out)
|
||||
replaced = True
|
||||
else:
|
||||
dest.write(mapping.original.string)
|
||||
missing_newline = not mapping.original.string.endswith("\n")
|
||||
if not replaced:
|
||||
if missing_newline:
|
||||
dest.write("\n")
|
||||
dest.write(line_out)
|
||||
|
||||
return True, key_to_set, value_to_set
|
||||
|
||||
|
||||
def unset_key(
|
||||
dotenv_path: Union[str, _PathLike],
|
||||
dotenv_path: StrPath,
|
||||
key_to_unset: str,
|
||||
quote_mode: str = "always",
|
||||
encoding: Optional[str] = "utf-8",
|
||||
) -> Tuple[Optional[bool], str]:
|
||||
"""
|
||||
Removes a given key from the given .env
|
||||
Removes a given key from the given `.env` file.
|
||||
|
||||
If the .env path given doesn't exist, fails
|
||||
If the given key doesn't exist in the .env, fails
|
||||
If the .env path given doesn't exist, fails.
|
||||
If the given key doesn't exist in the .env, fails.
|
||||
"""
|
||||
if not os.path.exists(dotenv_path):
|
||||
logger.warning("Can't delete from %s - it doesn't exist.", dotenv_path)
|
||||
return None, key_to_unset
|
||||
|
||||
removed = False
|
||||
with rewrite(dotenv_path) as (source, dest):
|
||||
with rewrite(dotenv_path, encoding=encoding) as (source, dest):
|
||||
for mapping in with_warn_for_invalid_lines(parse_stream(source)):
|
||||
if mapping.key == key_to_unset:
|
||||
removed = True
|
||||
@@ -213,14 +228,14 @@ def resolve_variables(
|
||||
values: Iterable[Tuple[str, Optional[str]]],
|
||||
override: bool,
|
||||
) -> Mapping[str, Optional[str]]:
|
||||
new_values = {} # type: Dict[str, Optional[str]]
|
||||
new_values: Dict[str, Optional[str]] = {}
|
||||
|
||||
for (name, value) in values:
|
||||
if value is None:
|
||||
result = None
|
||||
else:
|
||||
atoms = parse_variables(value)
|
||||
env = {} # type: Dict[str, Optional[str]]
|
||||
env: Dict[str, Optional[str]] = {}
|
||||
if override:
|
||||
env.update(os.environ) # type: ignore
|
||||
env.update(new_values)
|
||||
@@ -294,7 +309,7 @@ def find_dotenv(
|
||||
|
||||
|
||||
def load_dotenv(
|
||||
dotenv_path: Union[str, _PathLike, None] = None,
|
||||
dotenv_path: Optional[StrPath] = None,
|
||||
stream: Optional[IO[str]] = None,
|
||||
verbose: bool = False,
|
||||
override: bool = False,
|
||||
@@ -303,16 +318,19 @@ def load_dotenv(
|
||||
) -> bool:
|
||||
"""Parse a .env file and then load all the variables found as environment variables.
|
||||
|
||||
- *dotenv_path*: absolute or relative path to .env file.
|
||||
- *stream*: Text stream (such as `io.StringIO`) with .env content, used if
|
||||
`dotenv_path` is `None`.
|
||||
- *verbose*: whether to output a warning the .env file is missing. Defaults to
|
||||
`False`.
|
||||
- *override*: whether to override the system environment variables with the variables
|
||||
in `.env` file. Defaults to `False`.
|
||||
- *encoding*: encoding to be used to read the file.
|
||||
Parameters:
|
||||
dotenv_path: Absolute or relative path to .env file.
|
||||
stream: Text stream (such as `io.StringIO`) with .env content, used if
|
||||
`dotenv_path` is `None`.
|
||||
verbose: Whether to output a warning the .env file is missing.
|
||||
override: Whether to override the system environment variables with the variables
|
||||
from the `.env` file.
|
||||
encoding: Encoding to be used to read the file.
|
||||
Returns:
|
||||
Bool: True if at least one environment variable is set else False
|
||||
|
||||
If both `dotenv_path` and `stream`, `find_dotenv()` is used to find the .env file.
|
||||
If both `dotenv_path` and `stream` are `None`, `find_dotenv()` is used to find the
|
||||
.env file.
|
||||
"""
|
||||
if dotenv_path is None and stream is None:
|
||||
dotenv_path = find_dotenv()
|
||||
@@ -329,7 +347,7 @@ def load_dotenv(
|
||||
|
||||
|
||||
def dotenv_values(
|
||||
dotenv_path: Union[str, _PathLike, None] = None,
|
||||
dotenv_path: Optional[StrPath] = None,
|
||||
stream: Optional[IO[str]] = None,
|
||||
verbose: bool = False,
|
||||
interpolate: bool = True,
|
||||
@@ -338,14 +356,18 @@ def dotenv_values(
|
||||
"""
|
||||
Parse a .env file and return its content as a dict.
|
||||
|
||||
- *dotenv_path*: absolute or relative path to .env file.
|
||||
- *stream*: `StringIO` object with .env content, used if `dotenv_path` is `None`.
|
||||
- *verbose*: whether to output a warning the .env file is missing. Defaults to
|
||||
`False`.
|
||||
in `.env` file. Defaults to `False`.
|
||||
- *encoding*: encoding to be used to read the file.
|
||||
The returned dict will have `None` values for keys without values in the .env file.
|
||||
For example, `foo=bar` results in `{"foo": "bar"}` whereas `foo` alone results in
|
||||
`{"foo": None}`
|
||||
|
||||
If both `dotenv_path` and `stream`, `find_dotenv()` is used to find the .env file.
|
||||
Parameters:
|
||||
dotenv_path: Absolute or relative path to the .env file.
|
||||
stream: `StringIO` object with .env content, used if `dotenv_path` is `None`.
|
||||
verbose: Whether to output a warning if the .env file is missing.
|
||||
encoding: Encoding to be used to read the file.
|
||||
|
||||
If both `dotenv_path` and `stream` are `None`, `find_dotenv()` is used to find the
|
||||
.env file.
|
||||
"""
|
||||
if dotenv_path is None and stream is None:
|
||||
dotenv_path = find_dotenv()
|
||||
|
||||
Vendored
+10
-17
@@ -25,23 +25,16 @@ _double_quote_escapes = make_regex(r"\\[\\'\"abfnrtv]")
|
||||
_single_quote_escapes = make_regex(r"\\[\\']")
|
||||
|
||||
|
||||
Original = NamedTuple(
|
||||
"Original",
|
||||
[
|
||||
("string", str),
|
||||
("line", int),
|
||||
],
|
||||
)
|
||||
class Original(NamedTuple):
|
||||
string: str
|
||||
line: int
|
||||
|
||||
Binding = NamedTuple(
|
||||
"Binding",
|
||||
[
|
||||
("key", Optional[str]),
|
||||
("value", Optional[str]),
|
||||
("original", Original),
|
||||
("error", bool),
|
||||
],
|
||||
)
|
||||
|
||||
class Binding(NamedTuple):
|
||||
key: Optional[str]
|
||||
value: Optional[str]
|
||||
original: Original
|
||||
error: bool
|
||||
|
||||
|
||||
class Position:
|
||||
@@ -155,7 +148,7 @@ def parse_binding(reader: Reader) -> Binding:
|
||||
reader.read_regex(_whitespace)
|
||||
if reader.peek(1) == "=":
|
||||
reader.read_regex(_equal_sign)
|
||||
value = parse_value(reader) # type: Optional[str]
|
||||
value: Optional[str] = parse_value(reader)
|
||||
else:
|
||||
value = None
|
||||
reader.read_regex(_comment)
|
||||
|
||||
Vendored
+10
-12
@@ -1,8 +1,8 @@
|
||||
import re
|
||||
from abc import ABCMeta
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from typing import Iterator, Mapping, Optional, Pattern
|
||||
|
||||
_posix_variable = re.compile(
|
||||
_posix_variable: Pattern[str] = re.compile(
|
||||
r"""
|
||||
\$\{
|
||||
(?P<name>[^\}:]*)
|
||||
@@ -12,20 +12,18 @@ _posix_variable = re.compile(
|
||||
\}
|
||||
""",
|
||||
re.VERBOSE,
|
||||
) # type: Pattern[str]
|
||||
)
|
||||
|
||||
|
||||
class Atom():
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
class Atom(metaclass=ABCMeta):
|
||||
def __ne__(self, other: object) -> bool:
|
||||
result = self.__eq__(other)
|
||||
if result is NotImplemented:
|
||||
return NotImplemented
|
||||
return not result
|
||||
|
||||
def resolve(self, env: Mapping[str, Optional[str]]) -> str:
|
||||
raise NotImplementedError
|
||||
@abstractmethod
|
||||
def resolve(self, env: Mapping[str, Optional[str]]) -> str: ...
|
||||
|
||||
|
||||
class Literal(Atom):
|
||||
@@ -33,7 +31,7 @@ class Literal(Atom):
|
||||
self.value = value
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "Literal(value={})".format(self.value)
|
||||
return f"Literal(value={self.value})"
|
||||
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if not isinstance(other, self.__class__):
|
||||
@@ -53,7 +51,7 @@ class Variable(Atom):
|
||||
self.default = default
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "Variable(name={}, default={})".format(self.name, self.default)
|
||||
return f"Variable(name={self.name}, default={self.default})"
|
||||
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if not isinstance(other, self.__class__):
|
||||
@@ -74,8 +72,8 @@ def parse_variables(value: str) -> Iterator[Atom]:
|
||||
|
||||
for match in _posix_variable.finditer(value):
|
||||
(start, end) = match.span()
|
||||
name = match.groupdict()["name"]
|
||||
default = match.groupdict()["default"]
|
||||
name = match["name"]
|
||||
default = match["default"]
|
||||
|
||||
if start > cursor:
|
||||
yield Literal(value=value[cursor:start])
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
__version__ = "0.19.0"
|
||||
__version__ = "1.0.0"
|
||||
|
||||
Vendored
+1
-1
@@ -10,7 +10,7 @@ pexpect==4.8.0
|
||||
pipdeptree==2.3.1
|
||||
plette[validation]==0.4.4
|
||||
ptyprocess==0.7.0
|
||||
python-dotenv==0.19.0
|
||||
python-dotenv==1.0.0
|
||||
pythonfinder==1.3.2
|
||||
requirementslib==2.2.4
|
||||
ruamel.yaml==0.17.21
|
||||
|
||||
Reference in New Issue
Block a user