Perform type validation on string var_type for benefit of default value #24
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The Problem
I wouldn't call this a bug with this library per se, but it does create a situation where it's easy for a developer writing client code using
envs
to get themselves into trouble.At various points I've seen devs omit the
var_type
argument on theenv()
call out of habit, but supply a non-string argument as thedefault
; for example,env('TIMEOUT_IN_S', 5)
.The
'string'
var_type
is the default if no other is supplied, but is mapped toNone
as a validator/caster in thevalid_types
dictionary, meaning it'll just pass-through whatever value is supplied. This is fine when it's reading the value out of the environment, sinceos.getenv
returns astr
.However, this also operates on the
default
argument passed in if no value is found in the environment. Effectively, the'string'
var_type
will allow any old type to be used as a default. It's worth pointing out this is not the case for the other types; using avar_type='boolean'
will validate the default to be one of the acceptable boolean values. It's only because of the pass-through behavior for'string'
that this type mismatch can occur.This is a problem because client code now has a bug with inconsistent types that won't be discovered until the value is overridden in the environment. In the
TIMEOUT_IN_S
example above, if no environment override is set, the value will be theint
5
. However when the environment specifies10
, that will be read as a string rather than an integer, which can break the code depending what this value is passed into.Proposed Solution
The behavior we want, arguably, is that when
var_type
anddefault
are both supplied, they must be type-compatible with one another based on the logic invalidate_type
. Becausevalidate_type
is called afteros.getenv(key, default)
, it's already operating on both the default value and any value found in the environment. The least-intrusive change is to remove theNone
bypass logic for strings invalid_types
andvalidate_type
.After this change, strings read out of the environment will still resolve just fine in the
if isinstance(value, klass): return value
branch, but a programmer supplying an integer default while omitting thevar_type
argument (or even just supplying avar_type
argument that doesn't match the type ofdefault
) will be cautioned immediately by the call throwing aTypeError
.I don't believe there's any existing valid use case that this change breaks; I've also verified all existing unit tests still pass successfully, and added a case for the behavior against which I'm trying to guard.
Let me know if you have any questions or feedback on the change that would block this from being accepted, thanks!