-
Notifications
You must be signed in to change notification settings - Fork 133
Refactor and Document check_env.check() #1826
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
base: main
Are you sure you want to change the base?
Changes from all commits
404bdc0
511293f
c292205
fa492f7
942c0e5
18edcc7
7ea1336
b3e6543
486789f
c460a9f
bfea4c6
d0f78a0
28999f9
db86692
3fb8a3e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,18 +1,106 @@ | ||
| import os | ||
| import warnings | ||
| from typing import Literal, TypeVar, overload | ||
|
|
||
| T = TypeVar("T") | ||
|
|
||
| def check(env: str, field: str | None, optional: bool | None = False) -> str | None: | ||
|
|
||
| @overload | ||
| def check( | ||
| env: str, | ||
| value: T, | ||
| opt: bool | None = ..., | ||
| *, | ||
| optional: bool = ..., | ||
| field: T | None = ..., | ||
| ) -> T: ... | ||
|
|
||
|
|
||
| @overload | ||
| def check( | ||
| env: str, | ||
| value: None = None, | ||
| opt: bool | None = ..., | ||
| *, | ||
| optional: Literal[True], | ||
| field: None = None, | ||
| ) -> str | None: ... | ||
|
|
||
|
|
||
| @overload | ||
| def check( | ||
| env: str, | ||
| value: None = None, | ||
| opt: bool | None = ..., | ||
| *, | ||
| optional: Literal[False] = False, | ||
| field: None = None, | ||
| ) -> str: ... | ||
|
|
||
|
|
||
| def check( | ||
| env: str, | ||
| value: T | None = None, | ||
| opt: bool | None = None, | ||
| *, | ||
| optional: bool = False, | ||
| field: T | None = None, | ||
| ) -> T | str | None: | ||
| """ | ||
| Check if an environment variable has been set. If it has not been set | ||
| and the passed field or arguments have not been passed, then raise an | ||
| error. | ||
| Check if an environment variable has been set or value has been provided. | ||
|
|
||
| Args: | ||
| env: | ||
| Name of environment variable to check. | ||
| value: | ||
| If provided, ignore environment variable and return this. | ||
| opt: | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is the opt parameter coming from? I get that it's being listed as deprecated, but I'm not seeing where it's used at all.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. optional (the former 3rd positional argument) is now a keyword-only argument. So I added "opt" as the 3rd positional argument with the deprecation warning. That way it's not a breaking change if people try to provide the optional parameter as a positional argument.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gotcha. What's your reasoning on moving it from a 3rd positional argument to a keyword-only argument?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| Deprecated; use `optional` instead. | ||
| If ``True``, return ``None`` if no value is found instead of raising ``KeyError``. | ||
|
|
||
| Keyword Args: | ||
| optional: | ||
| If ``True``, return ``None`` if no value is found instead of raising ``KeyError``. | ||
| field: | ||
| Deprecated; use `value` instead. | ||
| If provided, ignore environment variable and return this. | ||
|
|
||
| Returns: | ||
| The value of the requested environment variable (str) or the provided value (T). | ||
| If called with ``optional=True``, will return ``None`` if no value is found or provided. | ||
|
|
||
| Raises: | ||
| KeyError: If no value is found/provided and `optional` is ``False``. | ||
|
|
||
| """ | ||
| if field: | ||
| return field | ||
| try: | ||
| return os.environ[env] | ||
| except KeyError as e: | ||
| if not optional: | ||
| raise KeyError( | ||
| f"No {env} found. Store as environment variable or pass as an argument." | ||
| ) from e | ||
| # Handle deprecated arguments | ||
| if opt is not None: | ||
| warnings.warn( | ||
| "The 'opt' positional argument is deprecated. " | ||
| "Use the 'optional' keyword argument. " | ||
| "Overriding 'optional' with value of 'opt' for backwards-compatibility.", | ||
| DeprecationWarning, | ||
| stacklevel=2, | ||
| ) | ||
| optional = opt | ||
|
|
||
| if field is not None: | ||
| warnings.warn( | ||
| "The 'field' keyword argument is deprecated. " | ||
| "Use the 'value' positional or keyword argument. " | ||
| "Overriding 'value' with value of 'field' for backwards-compatibility.", | ||
| DeprecationWarning, | ||
| stacklevel=2, | ||
| ) | ||
| value = field | ||
|
|
||
| if value is not None: | ||
| return value | ||
|
|
||
| if (environment_variable := os.environ.get(env)) is not None: | ||
| return environment_variable | ||
|
|
||
| if optional: | ||
| return None | ||
|
|
||
| raise KeyError(f"No '{env}' found. Store as environment variable or pass as an argument.") | ||
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.
What are these @overload decorators doing?
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.
Overload is a type hinting feature.
It tells static type checkers that if you provide a certain type as an input you get a certain type as an output.
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.
Gotcha. Why are there three of them? It feels more verbose than is ideal (but maybe if we can use a comment to signal to the reader that these are type hints with no impact on the code itself, the verbosity is less of an issue)
Uh oh!
There was an error while loading. Please reload this page.
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.
That's just how the syntax works, unfortunately.
That's why overload is only used situationally. I think it's worth it here since check is used in a ton of connectors so having accurate typing is extra useful.
Uh oh!
There was an error while loading. Please reload this page.
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.
Happy to chat through how this works sometime, I just keep being busy on Thursdays 😅
It's a very helpful feature.
Uh oh!
There was an error while loading. Please reload this page.
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.
You've got some other PRs I could review too so yeah let's schedule a call.