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

SecretStr cannot be idempotently passed if annotated using Field #5088

Closed
5 of 15 tasks
Callum027 opened this issue Feb 21, 2023 · 6 comments
Closed
5 of 15 tasks

SecretStr cannot be idempotently passed if annotated using Field #5088

Callum027 opened this issue Feb 21, 2023 · 6 comments
Labels
bug V1 Bug related to Pydantic V1.X

Comments

@Callum027
Copy link

Initial Checks

  • I have searched GitHub for a duplicate issue and I'm sure this is something new
  • I have searched Google & StackOverflow for a solution and couldn't find anything
  • I have read and followed the docs and still think this is a bug
  • I am confident that the issue is with pydantic (not my code, or another library in the ecosystem like FastAPI or mypy)

Description

Pydantic previously had a bug where SecretStr objects were not able to be idempotently passed into a SecretStr field on a model.

I'm using SecretStr to implement an annotated API key type where the length of the key is known, and I found I am unable to pass SecretStr objects into a model if it has been annotated. Only regular strings will work.

>>> from typing_extensions import Annotated
>>> from pydantic import BaseModel, Field, SecretStr
>>> class Test(BaseModel):
...     api_key: Annotated[SecretStr, Field(min_length=4, max_length=4)]
...
>>> Test(api_key="abcd")
Test(api_key=SecretStr('**********'))
>>> Test(api_key=SecretStr("abcd"))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pydantic\main.py", line 342, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for Test
api_key
  str type expected (type=type_error.str)

Example Code

from typing_extensions import Annotated
from pydantic import BaseModel, Field, SecretStr

class Test(BaseModel):
    api_key: Annotated[SecretStr, Field(min_length=4, max_length=4)]

Test(api_key="abcd")
Test(api_key=SecretStr("abcd"))

Python, Pydantic & OS Version

$ poetry run python -c "import pydantic.utils; print(pydantic.utils.version_info())"
             pydantic version: 1.10.4
            pydantic compiled: True
                 install path: C:\Users\karam\dev\github.com\buildarr\buildarr\.venv\Lib\site-packages\pydantic
               python version: 3.8.3 (tags/v3.8.3:6f8c832, May 13 2020, 22:37:02) [MSC v.1924 64 bit (AMD64)]
                     platform: Windows-10-10.0.22621-SP0
     optional deps. installed: ['email-validator', 'typing-extensions']

Affected Components

@Callum027 Callum027 added bug V1 Bug related to Pydantic V1.X unconfirmed Bug not yet confirmed as valid/applicable labels Feb 21, 2023
@Callum027
Copy link
Author

Subclassing SecretStr instead of using Annotated appears to give better results.

This makes me think that it is related to the fact that the model is not expecting a regular SecretStr, and passing it a normal SecretStr doesn't satisfy the conditions.

from typing_extensions import Annotated
from pydantic import BaseModel, Field, SecretStr

class ApiKey(SecretStr):
    min_length = 4
    max_length = 4

class Test(BaseModel):
    api_key: ApiKey

Test(api_key=ApiKey("abcd"))

@samuelcolvin
Copy link
Member

Subclassing SecretStr instead of using Annotated appears to give better results.

but does this actually apply length validation?

I suspect that truth is we won't be able to make many changes to this in V1 at this point without risking breaking existing behaviour, but we should be able to get it right for V2 which is nearing completing at the moment.

@Callum027
Copy link
Author

but does this actually apply length validation?

Thanks for your comment. Just gave this a quick test and it appears to validate it correctly.

>>> from pydantic import BaseModel, SecretStr
>>> class ApiKey(SecretStr):
...     min_length = 4
...     max_length = 4
...
>>> class Test(BaseModel):
...     api_key: ApiKey
...
>>> Test(api_key=ApiKey("abcdef"))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pydantic\main.py", line 342, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for Test
api_key
  ensure this value has at most 4 characters (type=value_error.any_str.max_length; limit_value=4)

@samuelcolvin
Copy link
Member

Great, pleased you found a work around.

@hramezani hramezani removed the unconfirmed Bug not yet confirmed as valid/applicable label Feb 22, 2023
@Kludex
Copy link
Member

Kludex commented Apr 27, 2023

Since there is a work around, and it's already working on V2, I'll be closing this issue. 🙏

@Kludex Kludex closed this as not planned Won't fix, can't repro, duplicate, stale Apr 27, 2023
@JonathanDCohen
Copy link

JonathanDCohen commented Feb 7, 2024

This doesn't seem to work for regex patterns

class StringParam(SecretStr):
    pattern = r"a"

class Test(BaseModel):
    test: StringParam

Test(test="b")
#Test(test=StringParam('**********'))

My use case is validating config input with cloud credentials

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug V1 Bug related to Pydantic V1.X
Projects
None yet
Development

No branches or pull requests

5 participants