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 failure to load SecretStr from JSON (regression in v2.4) #7729

Merged
merged 5 commits into from Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 14 additions & 10 deletions pydantic/types.py
Expand Up @@ -1448,16 +1448,20 @@ def get_json_schema(_core_schema: core_schema.CoreSchema, handler: GetJsonSchema
)
return json_schema

s = core_schema.union_schema(
[
core_schema.is_instance_schema(source),
core_schema.no_info_after_validator_function(
source, # construct the type
inner_schema,
),
],
strict=True,
custom_error_type=error_kind,
json_schema = core_schema.no_info_after_validator_function(
source, # construct the type
inner_schema,
)
s = core_schema.json_or_python_schema(
python_schema=core_schema.union_schema(
[
core_schema.is_instance_schema(source),
json_schema,
],
strict=True,
custom_error_type=error_kind,
),
json_schema=json_schema,
Copy link
Contributor

Choose a reason for hiding this comment

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

This might want to have a custom_error_schema and use custom_error_type in some form on this branch. Possibly worth testing the JSON validation error with the wrong type.

Copy link
Contributor

@dmontagu dmontagu Oct 3, 2023

Choose a reason for hiding this comment

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

(As discussed elsewhere,) I think given the specific format of the errors seems good (added to the test below), this isn't necessary.

serialization=core_schema.plain_serializer_function_ser_schema(
serialize,
info_arg=True,
Expand Down
36 changes: 19 additions & 17 deletions tests/test_types.py
Expand Up @@ -3927,23 +3927,25 @@ class Foobar(BaseModel):
empty_password: SecretStr

# Initialize the model.
f = Foobar(password='1234', empty_password='')

# Assert correct types.
assert f.password.__class__.__name__ == 'SecretStr'
assert f.empty_password.__class__.__name__ == 'SecretStr'

# Assert str and repr are correct.
assert str(f.password) == '**********'
assert str(f.empty_password) == ''
assert repr(f.password) == "SecretStr('**********')"
assert repr(f.empty_password) == "SecretStr('')"
assert len(f.password) == 4
assert len(f.empty_password) == 0

# Assert retrieval of secret value is correct
assert f.password.get_secret_value() == '1234'
assert f.empty_password.get_secret_value() == ''
f1 = Foobar(password='1234', empty_password='')
f2 = Foobar.model_validate_json('{"password": "1234", "empty_password": ""}')

for f in [f1, f2]:
Copy link
Contributor

Choose a reason for hiding this comment

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

It may be slightly nicer to turn this into a parameterized test rather than have one of f1 or f2 fail inside the loop

# Assert correct types.
assert f.password.__class__.__name__ == 'SecretStr'
assert f.empty_password.__class__.__name__ == 'SecretStr'

# Assert str and repr are correct.
assert str(f.password) == '**********'
assert str(f.empty_password) == ''
assert repr(f.password) == "SecretStr('**********')"
assert repr(f.empty_password) == "SecretStr('')"
assert len(f.password) == 4
assert len(f.empty_password) == 0

# Assert retrieval of secret value is correct
assert f.password.get_secret_value() == '1234'
assert f.empty_password.get_secret_value() == ''


def test_secretstr_subclass():
Expand Down