Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve error message for get and list commands when env file can't be opened #441

Merged
merged 1 commit into from Nov 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
48 changes: 31 additions & 17 deletions src/dotenv/cli.py
Expand Up @@ -2,8 +2,9 @@
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 click
Expand All @@ -12,7 +13,7 @@
'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__


Expand All @@ -33,6 +34,22 @@ def cli(ctx: click.Context, file: Any, quote: Any, export: Any) -> None:
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
@click.option('--format', default='simple',
Expand All @@ -42,18 +59,16 @@ def cli(ctx: click.Context, file: Any, quote: Any, export: Any) -> None:
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(
f'Path "{file}" does not exist.',
ctx=ctx
)
dotenv_as_dict = dotenv_values(file)

with stream_file(file) as stream:
values = dotenv_values(stream=stream)

if format == 'json':
click.echo(json.dumps(dotenv_as_dict, indent=2, sort_keys=True))
click.echo(json.dumps(values, indent=2, sort_keys=True))
else:
prefix = 'export ' if format == 'export' else ''
for k in sorted(dotenv_as_dict):
v = dotenv_as_dict[k]
for k in sorted(values):
v = values[k]
if v is not None:
if format in ('export', 'shell'):
v = shlex.quote(v)
Expand Down Expand Up @@ -82,12 +97,11 @@ def set(ctx: click.Context, key: Any, value: 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):
raise click.BadParameter(
f'Path "{file}" does not exist.',
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:
Expand Down
20 changes: 17 additions & 3 deletions tests/test_cli.py
Expand Up @@ -40,7 +40,14 @@ def test_list_non_existent_file(cli):
result = cli.invoke(dotenv_cli, ['--file', 'nx_file', 'list'])

assert result.exit_code == 2, result.output
assert "does not exist" in result.output
assert "Error opening env file" in result.output


def test_list_not_a_file(cli):
result = cli.invoke(dotenv_cli, ['--file', '.', 'list'])

assert result.exit_code == 2, result.output
assert "Error opening env file" in result.output


def test_list_no_file(cli):
Expand All @@ -64,11 +71,18 @@ def test_get_non_existent_value(cli, dotenv_file):
assert (result.exit_code, result.output) == (1, "")


def test_get_no_file(cli):
def test_get_non_existent_file(cli):
result = cli.invoke(dotenv_cli, ['--file', 'nx_file', 'get', 'a'])

assert result.exit_code == 2
assert "does not exist" in result.output
assert "Error opening env file" in result.output


def test_get_not_a_file(cli):
result = cli.invoke(dotenv_cli, ['--file', '.', 'get', 'a'])

assert result.exit_code == 2
assert "Error opening env file" in result.output


def test_unset_existing_value(cli, dotenv_file):
Expand Down