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

Fix #979 - validators must not parse with toml #980

Closed
wants to merge 1 commit into from
Closed

Conversation

rochacbruno
Copy link
Member

@rochacbruno rochacbruno commented Aug 16, 2023

#979 #905
3 years ago I made the wrong decision to pass validators defaults to TOML parser.

Validator object is created at Python level, or at YAML level where there is no need to use toml as parser.

TOML parser must ideally be used only on environment variables where there is no type system available.

That said, this PR ensures toml will keep parsing values coming from envvars, but setdefault method will stop passing tomlfy=True so the type informed on the validator will be the type set as default value.

The only possible breaking change on this is if someone is setting defaults relying on TOML to parse the data, in that case, user will need to manually call parse_with_toml on default data.

I think that is not a common case, if someone reports it as a broken change, we can provide a new argument parse_default_with_toml on the Validator object later.

3 years ago I made the wrong decision to pass validators defaults to
TOML parser.

Validator object is created at Python level, or at YAML level where
there is no need to use toml as parser.

TOML parser must ideally be used only on environment variables
where there is no type system available.

That said, this PR ensures toml will keep parsing values coming from
envvars, but setdefault method will stop passing `tomlfy=True`
so the type informed on the validator will be the type set as default
value.

The only possible breaking change on this is if someone is setting
defaults relying on TOML to parse the data, in that case, user
will need to manually call `parse_with_toml` on default data.

I think that is not a common case, if someone reports it as a broken
change, we can provide a new argument `parse_default_with_toml` on
the Validator object later.
@github-actions
Copy link
Contributor

Test Results (Python 3.11)

467 tests  ±0   467 ✔️ ±0   39s ⏱️ -9s
    1 suites ±0       0 💤 ±0 
    1 files   ±0       0 ±0 

Results for commit c105e41. ± Comparison against base commit 9ca687a.

@github-actions
Copy link
Contributor

Test Results (Python 3.10)

467 tests  ±0   467 ✔️ ±0   38s ⏱️ -1s
    1 suites ±0       0 💤 ±0 
    1 files   ±0       0 ±0 

Results for commit c105e41. ± Comparison against base commit 9ca687a.

@github-actions
Copy link
Contributor

Test Results (Python 3.8)

467 tests  ±0   467 ✔️ ±0   38s ⏱️ -3s
    1 suites ±0       0 💤 ±0 
    1 files   ±0       0 ±0 

Results for commit c105e41. ± Comparison against base commit 9ca687a.

@@ -396,7 +396,7 @@ def setdefault(
item,
default,
loader_identifier=loader_identifier,
tomlfy=True,
tomlfy=False,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all other set methods such as set and update have tomlfy=False as a default, the reason for it is for loaders to be able to enable it on-demand, env_loader will always pass `True to that parameter, while other loaders that can rely on a type system will probably not need to parse data again. (but looks like that is not the current case)

If I was going to reimplement this today, I would accept just the bare value and do not parse it, require that the caller parses data if needed, but now it is too late for this change, so lets deal with it.

@@ -262,7 +262,8 @@ def _validate_items(
and self.is_type_of is str
):
# avoid TOML from parsing "+-1" as integer
default_value = f"'{default_value}'"
# by forcing casting to str
default_value = f"@str {default_value}"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toml parsing will not be executed by setdefault, however the converters like @str will keep being processed! (this must have been the solution 3 years ago)

validators=[Validator("TEST", default="+172800")]
validators=[Validator("TEST", default=-172800)]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a possible breaking change, but I guess no one is relying on it, it was odd to pass a str to a default and expect an integer back.

Now the behavior is more consistent, if default needs to be integer, the user must pass integer or add @int as prefix.

DYNACONF_GROUP__TEST_LIST = ["'1'", "'2'"] # double quotes to cast as string
DYNACONF_GROUP__TEST_LIST="['1', '2']"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double quotes is required to force str internal values, but the recommended way is to pass it outside not internally.

$ DYNACONF_LIST="['1','2']" dynaconf list -k LIST
LIST<BoxList> <BoxList: ['1', '2']>

Copy link
Member

@pedro-psb pedro-psb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've found tomlfy confusing sometimes, but now its clearer what it purpose was.

I think it is ok to do this break changes as it is low risk and is a design fix. It may be worth to review the documentation on this to assure it is up-to-date (I can do it tomorrow). I'd also suggest adding this to the next minor release (3.3.0) and add a upcoming Breaking Change Warning on the changelog of the next patches (3.2.x).

@pedro-psb
Copy link
Member

@rochacbruno This section of the docs needs to be updated:

dynaconf/docs/validation.md

Lines 533 to 550 in 297eefc

!!! info
All values in dynaconf are parsed using toml format, TOML tries to be smart
and infer the type of the settings variables, some variables will be automatically
converted to integer:
```
FOO = "0x..." # hexadecimal
FOO = "0o..." # Octal
FOO = "0b..." # Binary
```
All cases are on toml specs https://github.com/toml-lang/toml/blob/master/toml.abnf
If you need to force a specific type casting there are 2 options.
1. Use double quoted for strings ex: `FOO = "'0x...'" will be string.
2. Specify the type using `@` ex: FOO = "@str 0x..."
(available converters are `@int, @float, @bool, @json`)

@pedro-psb
Copy link
Member

And it would be good to add the motivation for tomlfy on parse_conf_data docstring, it may be usefull for someone digging in the codebase.

@rochacbruno
Copy link
Member Author

This implementation will be obsolete and replaced by #981

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[bug] when using a validator with a default for nested data it parses value via toml twice
2 participants