-
Notifications
You must be signed in to change notification settings - Fork 415
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
Update load_dotenv to return False if no dotenv source is loaded #263
Conversation
The slight decrease in code coverage is happening because of how I combined the exception and return in main.py L106. The tests actually still pass because of how I set up Pytest context management. I will separate out the exception handling from the return, maybe adding a |
#164 #245 `load_dotenv` calls `DotEnv.set_as_environment_variables()`, confusingly always returning True, even if no .env file is found or no environment variables are loaded. This commit will: - Improve `DotEnv.set_as_environment_variables()` to log a message, and return `False` when no variables are loaded and `verbose=True`. It will still return `True` as usual if `verbose=False`. - Raise a `LookupError` exception with `load_dotenv()` if `verbose=True` and `DotEnv.set_as_environment_variables()` returns `False`. - Add `test_load_dotenv_empty_file()`, with tests for `verbose=True` and `verbose=False`. - Update `test_load_dotenv_no_file_verbose()` to handle the new `LookupError` exception.
Alright cool, I re-did my commit. It looks like all the checks are passing, and the code coverage actually increased slightly. |
Thank you for trying to improve the situation with regards to missing .env files. I agree it's not great at the moment. Here's my main concern: For consistency with most other programs, a Changing the return value of |
Thanks for your helpful review.
That's a great point. We should handle logging and exceptions separately. For example, a user might want to load an empty .env file, and then add values to it with
Right. We could add separate keyword arguments to
The latest commit will add these suggested arguments and avoid throwing exceptions with I'm happy to keep helping with this until we have a satisfactory API. I'm also happy to work on updating the docs if we do merge these changes. |
Hi @bbc2, just wanted to check in about this PR. Is there anything more I can help with? |
Sorry I didn't reply sooner. The issue got kind of stuck in my head because I wasn't really satisfied with the API and didn't really know what else to suggest. This is a difficult issue. I've thought a bit more now and I think I want to keep the API simple:
What do you think? I think I would be happy to review code that just fixes the return value of |
#164 #245 #263 1011590 b5a9613 - Restore previous behavior of `DotEnv.set_as_environment_variables()`: Always returns `True`, even if dict is empty. - Remove the `raise_error_if_nothing_set` argument added in b5a9613 - Remove additional use of `raise_error_if_not_found` - Find `dotenv_path`: If `load_dotenv(dotenv_path="filename")` is run, resulting in `f = dotenv_path`, the path will now be passed to `find_dotenv()` to ensure the file can be found. If `find_dotenv()` can't find a .env file, `load_dotenv` will return `False`.
#164 #245 #263 1011590 b5a9613 33cf7f4 https://travis-ci.com/github/theskumar/python-dotenv/jobs/401778048 lint run-test: commands[5] | mypy --python-version=3.5 src tests src/dotenv/main.py:319: error: Argument 1 to "DotEnv" has incompatible type "Iterable[str]"; expected "Union[str, str, StringIO]"
Thanks for your feedback @bbc2. I agree that this is challenging, and that keeping the API simple will help us move forward. The latest commits will remove some of the complications introduced in 1011590 and b5a9613:
The simplest solution I have come up with so far is to pass # old (docstring omitted for simplicity)
def load_dotenv(dotenv_path=None, stream=None, verbose=False, override=False, interpolate=True, **kwargs):
f = dotenv_path or stream or find_dotenv()
return DotEnv(f, verbose=verbose, interpolate=interpolate, **kwargs).set_as_environment_variables(override=override)
# new
def load_dotenv(dotenv_path=None, stream=None, verbose=False, override=False, interpolate=True, **kwargs):
f = find_dotenv(filename=str(dotenv_path)) or stream or find_dotenv()
env = DotEnv(f, verbose=verbose, interpolate=interpolate, **kwargs).set_as_environment_variables(override=override)
return env if f else False If the user runs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the update. Here are some comments.
The maintainer was unwilling to implement the breaking change proposed by this PR. |
#164 was closed, but I still find the behavior of
load_dotenv()
confusing.The
load_dotenv()
function is supposed to "Parse a .env file and then load all the variables found as environment variables," according to its docstring. However, the function always returnsTrue
, even if no .env file is found or no environment variables are set, because ofDotEnv.set_as_environment_variables()
.@theskumar commented in #164:
Rather than adding
fail_silently=False
, which is very similar toverbose=True
, I think the easiest way to move forward on this is to update the behavior ofverbose=True
. This PR will improveload_dotenv(verbose=True)
in the following ways:DotEnv.set_as_environment_variables()
to log a message and returnFalse
when no variables are loaded andverbose=True
. It will still returnTrue
as usual ifverbose=False
.logger.info()
is used for consistency with Added better context for can't find config file error message #245, although I think a warning would be clearer.test_load_dotenv_empty_file()
with tests forverbose=True
andverbose=False
.test_load_dotenv_no_file_verbose()
to handle the newLookupError
exception.Flake8, Pytest, and Tox (only tried Python 2.7 and 3.7) are currently passing on my branch.