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 _replace_field_names_case_insensitively precondition inconsistency #130

Conversation

AlexVndnblcke
Copy link
Contributor

@AlexVndnblcke AlexVndnblcke commented Jul 18, 2023

Make recursive PydanticBaseEnvSettingsSource._replace_field_names_case_insensitively behave similarly to the check in PydanticBaseEnvSettingsSource.__call__.

Use in __call__:

if field_value is not None:
    if (
        not self.case_sensitive
        and lenient_issubclass(field.annotation, BaseModel)
        and isinstance(field_value, dict)
    ):
        data[field_key] = self._replace_field_names_case_insensitively(field, field_value)
    else:
        data[field_key] = field_value

this use-case checks if the field_value is of type dict so the .items() can be called.

But during _replace_field_names_case_insensitively the recursive call:

if lenient_issubclass(sub_model_field.annotation, BaseModel):
    values[sub_model_field_name] = self._replace_field_names_case_insensitively(sub_model_field, value)
else:
    values[sub_model_field_name] = value

does not check for the type to be a dict. I.e. this can raise an AttributeError when the BaseModel is represented in any other way than a dict value.

This is a plausible scenario since field validators can extract complex info from a flat entity (e.g. a string with a specific format). One could argue that this can be provided in the decode_complex_value.

However, if this parsing is universal, it would mean that this logic must be provided multiple times.

Selected Reviewer: @dmontagu

Make recursive `PydanticBaseEnvSettingsSource._replace_field_names_case_insensitivelyz
behave similarly to the check in `PydanticBaseEnvSettingsSource.__call__`.

Use in __call__:

```
if field_value is not None:
    if (
        not self.case_sensitive
        and lenient_issubclass(field.annotation, BaseModel)
        and isinstance(field_value, dict)
    ):
        data[field_key] = self._replace_field_names_case_insensitively(field, field_value)
    else:
        data[field_key] = field_value
```

this use-case checks if the `field_value` is of type dict so the
`.items()` can be called.

But during `_replace_field_names_case_insensitively` the recursive call:

```
if lenient_issubclass(sub_model_field.annotation, BaseModel):
    values[sub_model_field_name] = self._replace_field_names_case_insensitively(sub_model_field, value)
else:
    values[sub_model_field_name] = value
```

does not check for the type to be a dict. I.e. this can raise an
AttributeError when the BaseModel is represented in any other way than a
dict value.

This is a plausible scenario since field validators can extract complex
info from a flat entity (e.g. a string with a specific format). One
could argue that this can be provided in the `decode_complex_value`.

However, if this parsing is universal, it would mean that this logic
must be provided multiple times.
@codecov
Copy link

codecov bot commented Jul 18, 2023

Codecov Report

Patch coverage: 100.00% and no project coverage change.

Comparison is base (04ec4c7) 97.46% compared to head (00c864e) 97.46%.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #130   +/-   ##
=======================================
  Coverage   97.46%   97.46%           
=======================================
  Files           5        5           
  Lines         315      315           
  Branches       68       68           
=======================================
  Hits          307      307           
  Misses          6        6           
  Partials        2        2           
Impacted Files Coverage Δ
pydantic_settings/sources.py 97.71% <100.00%> (ø)

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@AlexVndnblcke
Copy link
Contributor Author

please review

@hramezani hramezani merged commit e6417b4 into pydantic:main Jul 19, 2023
20 checks passed
@hramezani
Copy link
Member

Thanks @AlexVndnblcke

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

Successfully merging this pull request may close these issues.

3 participants