Skip to content

Commit

Permalink
Use Python 3 type hints for functions
Browse files Browse the repository at this point in the history
Unfortunately, we can't do the same for variables as that is only
supported in Python 3.6+.
  • Loading branch information
bbc2 committed Jul 13, 2021
1 parent 1914bac commit 4590015
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 127 deletions.
12 changes: 8 additions & 4 deletions src/dotenv/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
unset_key)


def load_ipython_extension(ipython):
# type: (Any) -> None
def load_ipython_extension(ipython: Any) -> None:
from .ipython import load_ipython_extension
load_ipython_extension(ipython)


def get_cli_string(path=None, action=None, key=None, value=None, quote=None):
# type: (Optional[str], Optional[str], Optional[str], Optional[str], Optional[str]) -> str
def get_cli_string(
path: Optional[str] = None,
action: Optional[str] = None,
key: Optional[str] = None,
value: Optional[str] = None,
quote: Optional[str] = None,
):
"""Returns a string suitable for running as a shell script.
Useful for converting a arguments passed to a fabric task
Expand Down
21 changes: 7 additions & 14 deletions src/dotenv/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@
help="Whether to write the dot file as an executable bash script.")
@click.version_option(version=__version__)
@click.pass_context
def cli(ctx, file, quote, export):
# type: (click.Context, Any, Any, Any) -> None
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
Expand All @@ -37,8 +36,7 @@ def cli(ctx, file, quote, export):

@cli.command()
@click.pass_context
def list(ctx):
# type: (click.Context) -> None
def list(ctx: click.Context) -> None:
'''Display all the stored key/value.'''
file = ctx.obj['FILE']
if not os.path.isfile(file):
Expand All @@ -55,8 +53,7 @@ def list(ctx):
@click.pass_context
@click.argument('key', required=True)
@click.argument('value', required=True)
def set(ctx, key, value):
# type: (click.Context, Any, Any) -> None
def set(ctx: click.Context, key: Any, value: Any) -> None:
'''Store the given key/value.'''
file = ctx.obj['FILE']
quote = ctx.obj['QUOTE']
Expand All @@ -71,8 +68,7 @@ def set(ctx, key, value):
@cli.command()
@click.pass_context
@click.argument('key', required=True)
def get(ctx, key):
# type: (click.Context, Any) -> None
def get(ctx: click.Context, key: Any) -> None:
'''Retrieve the value for the given key.'''
file = ctx.obj['FILE']
if not os.path.isfile(file):
Expand All @@ -90,8 +86,7 @@ def get(ctx, key):
@cli.command()
@click.pass_context
@click.argument('key', required=True)
def unset(ctx, key):
# type: (click.Context, Any) -> None
def unset(ctx: click.Context, key: Any) -> None:
'''Removes the given key.'''
file = ctx.obj['FILE']
quote = ctx.obj['QUOTE']
Expand All @@ -110,8 +105,7 @@ def unset(ctx, key):
help="Override variables from the environment file with those from the .env file.",
)
@click.argument('commandline', nargs=-1, type=click.UNPROCESSED)
def run(ctx, override, commandline):
# type: (click.Context, bool, List[str]) -> None
def run(ctx: click.Context, override: bool, commandline: List[str]) -> None:
"""Run command with environment variables present."""
file = ctx.obj['FILE']
if not os.path.isfile(file):
Expand All @@ -132,8 +126,7 @@ def run(ctx, override, commandline):
exit(ret)


def run_command(command, env):
# type: (List[str], Dict[str, str]) -> int
def run_command(command: List[str], env: Dict[str, str]) -> int:
"""Run command in sub process.
Runs the command in a sub process with the variables from `env`
Expand Down
96 changes: 51 additions & 45 deletions src/dotenv/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@
_PathLike = Text


def with_warn_for_invalid_lines(mappings):
# type: (Iterator[Binding]) -> Iterator[Binding]
def with_warn_for_invalid_lines(mappings: Iterator[Binding]) -> Iterator[Binding]:
for mapping in mappings:
if mapping.error:
logger.warning(
Expand All @@ -32,9 +31,14 @@ def with_warn_for_invalid_lines(mappings):


class DotEnv():

def __init__(self, dotenv_path, verbose=False, encoding=None, interpolate=True, override=True):
# type: (Union[Text, _PathLike, io.StringIO], bool, Union[None, Text], bool, bool) -> None
def __init__(
self,
dotenv_path: Union[Text, _PathLike, io.StringIO],
verbose: bool = False,
encoding: Union[None, Text] = None,
interpolate: bool = True,
override: bool = True,
) -> None:
self.dotenv_path = dotenv_path # type: Union[Text,_PathLike, io.StringIO]
self._dict = None # type: Optional[Dict[Text, Optional[Text]]]
self.verbose = verbose # type: bool
Expand All @@ -43,8 +47,7 @@ def __init__(self, dotenv_path, verbose=False, encoding=None, interpolate=True,
self.override = override # type: bool

@contextmanager
def _get_stream(self):
# type: () -> Iterator[IO[Text]]
def _get_stream(self) -> Iterator[IO[Text]]:
if isinstance(self.dotenv_path, io.StringIO):
yield self.dotenv_path
elif os.path.isfile(self.dotenv_path):
Expand All @@ -55,8 +58,7 @@ def _get_stream(self):
logger.info("Python-dotenv could not find configuration file %s.", self.dotenv_path or '.env')
yield io.StringIO('')

def dict(self):
# type: () -> Dict[Text, Optional[Text]]
def dict(self) -> Dict[Text, Optional[Text]]:
"""Return dotenv as dict"""
if self._dict:
return self._dict
Expand All @@ -70,15 +72,13 @@ def dict(self):

return self._dict

def parse(self):
# type: () -> Iterator[Tuple[Text, Optional[Text]]]
def parse(self) -> Iterator[Tuple[Text, Optional[Text]]]:
with self._get_stream() as stream:
for mapping in with_warn_for_invalid_lines(parse_stream(stream)):
if mapping.key is not None:
yield mapping.key, mapping.value

def set_as_environment_variables(self):
# type: () -> bool
def set_as_environment_variables(self) -> bool:
"""
Load the current dotenv as system environment variable.
"""
Expand All @@ -90,8 +90,7 @@ def set_as_environment_variables(self):

return True

def get(self, key):
# type: (Text) -> Optional[Text]
def get(self, key: Text) -> Optional[Text]:
"""
"""
data = self.dict()
Expand All @@ -105,8 +104,7 @@ def get(self, key):
return None


def get_key(dotenv_path, key_to_get):
# type: (Union[Text, _PathLike], Text) -> Optional[Text]
def get_key(dotenv_path: Union[Text, _PathLike], key_to_get: Text) -> Optional[Text]:
"""
Gets the value of a given key from the given .env
Expand All @@ -116,8 +114,7 @@ def get_key(dotenv_path, key_to_get):


@contextmanager
def rewrite(path):
# type: (_PathLike) -> Iterator[Tuple[IO[Text], IO[Text]]]
def rewrite(path: _PathLike) -> Iterator[Tuple[IO[Text], IO[Text]]]:
try:
if not os.path.isfile(path):
with io.open(path, "w+") as source:
Expand All @@ -133,8 +130,13 @@ def rewrite(path):
shutil.move(dest.name, path)


def set_key(dotenv_path, key_to_set, value_to_set, quote_mode="always", export=False):
# type: (_PathLike, Text, Text, Text, bool) -> Tuple[Optional[bool], Text, Text]
def set_key(
dotenv_path: _PathLike,
key_to_set: Text,
value_to_set: Text,
quote_mode: Text = "always",
export: bool = False,
) -> Tuple[Optional[bool], Text, Text]:
"""
Adds or Updates a key/value to the given .env
Expand Down Expand Up @@ -172,8 +174,11 @@ def set_key(dotenv_path, key_to_set, value_to_set, quote_mode="always", export=F
return True, key_to_set, value_to_set


def unset_key(dotenv_path, key_to_unset, quote_mode="always"):
# type: (_PathLike, Text, Text) -> Tuple[Optional[bool], Text]
def unset_key(
dotenv_path: _PathLike,
key_to_unset: Text,
quote_mode: Text = "always",
) -> Tuple[Optional[bool], Text]:
"""
Removes a given key from the given .env
Expand All @@ -199,9 +204,10 @@ def unset_key(dotenv_path, key_to_unset, quote_mode="always"):
return removed, key_to_unset


def resolve_variables(values, override):
# type: (Iterable[Tuple[Text, Optional[Text]]], bool) -> Mapping[Text, Optional[Text]]

def resolve_variables(
values: Iterable[Tuple[Text, Optional[Text]]],
override: bool,
) -> Mapping[Text, Optional[Text]]:
new_values = {} # type: Dict[Text, Optional[Text]]

for (name, value) in values:
Expand All @@ -223,8 +229,7 @@ def resolve_variables(values, override):
return new_values


def _walk_to_root(path):
# type: (Text) -> Iterator[Text]
def _walk_to_root(path: Text) -> Iterator[Text]:
"""
Yield directories starting from the given directory up to the root
"""
Expand All @@ -242,8 +247,11 @@ def _walk_to_root(path):
last_dir, current_dir = current_dir, parent_dir


def find_dotenv(filename='.env', raise_error_if_not_found=False, usecwd=False):
# type: (Text, bool, bool) -> Text
def find_dotenv(
filename: Text = '.env',
raise_error_if_not_found: bool = False,
usecwd: bool = False,
) -> Text:
"""
Search in increasingly higher folders for the given file
Expand Down Expand Up @@ -281,14 +289,13 @@ def _is_interactive():


def load_dotenv(
dotenv_path=None,
stream=None,
verbose=False,
override=False,
interpolate=True,
encoding="utf-8",
):
# type: (Union[Text, _PathLike, None], Optional[io.StringIO], bool, bool, bool, Optional[Text]) -> bool # noqa
dotenv_path: Union[Text, _PathLike, None] = None,
stream: Optional[io.StringIO] = None,
verbose: bool = False,
override: bool = False,
interpolate: bool = True,
encoding: Optional[Text] = "utf-8",
) -> bool:
"""Parse a .env file and then load all the variables found as environment variables.
- *dotenv_path*: absolute or relative path to .env file.
Expand All @@ -313,13 +320,12 @@ def load_dotenv(


def dotenv_values(
dotenv_path=None,
stream=None,
verbose=False,
interpolate=True,
encoding="utf-8",
):
# type: (Union[Text, _PathLike, None], Optional[io.StringIO], bool, bool, Optional[Text]) -> Dict[Text, Optional[Text]] # noqa: E501
dotenv_path: Union[Text, _PathLike, None] = None,
stream: Optional[io.StringIO] = None,
verbose: bool = False,
interpolate: bool = True,
encoding: Optional[Text] = "utf-8",
) -> Dict[Text, Optional[Text]]:
"""
Parse a .env file and return its content as a dict.
Expand Down
Loading

0 comments on commit 4590015

Please sign in to comment.