pydantic / pydantic-extra-types

Extra Pydantic types.
MIT License
174 stars 47 forks source link

Truthy/Falsey Type #197

Open ollz272 opened 1 month ago

ollz272 commented 1 month ago

Initial Checks

Description

We have a situation where we'd like to validate against a string, or some truthy value. We thought we could do:

from typing import Literal

from pydantic import TypeAdapter

from typing import Literal

from pydantic import TypeAdapter

x = TypeAdapter(Literal["somevalue", True])

x.validate_python("somevalue")
x.validate_python(True)
x.validate_python("True")

However we get an error with x.validate_python("True"), as this seems to (correctly) validate only against the value True. What would be great for pydantic to provide is a type we could use which would accept all truthy/falsey values, like a type of bool would. For example:

from typing import Literal

from pydantic import TypeAdapter

x = TypeAdapter(Literal["somevalue", TruthyType])

x.validate_python("somevalue")
x.validate_python(True)
x.validate_python("True")
x.validate_python("true")
x.validate_python(1)

Affected Components

Viicos commented 1 month ago

Using bool should already work as a "truthy/falsey" type, at least in non strict mode (docs). However, Literal is also handled in a particular way (docs), that is it should match one of the provided literal values.

This makes the behavior inconsistent between bool and Literal[True/False], changing it would make it a really small breaking change, so I'm wondering which path to take here

ollz272 commented 1 month ago

Using bool should already work as a "truthy/falsey" type, at least in non strict mode (docs). However, Literal is also handled in a particular way (docs), that is it should match one of the provided literal values.

This makes the behavior inconsistent between bool and Literal[True/False], changing it would make it a really small breaking change, so I'm wondering which path to take here

I think the behaviour is currently correct for Literal[True/False], i just think it would be helpful to have a type that encapsulates the Truethy/Falsey nature thats captured in bool. We could just make our own type:

TruthyType = Literal[True, 1, '1', 'on', 't', 'true', 'y', 'yes']
FalseyType = Literal[False, 1, '0', 'off', 'f', 'false', 'n', 'no']

But having something in pydantic (or maybe pydantic_extra_types) would be extremely useful.

sydney-runkle commented 1 month ago

Feel free to add something to pydantic_extra_types. I don't think this is high demand enough to justify a change in pydantic. Thus, going to move this issue over there :).

Viicos commented 1 month ago

@sydney-runkle, do you think Literal[True] and Literal[False] should be special cased and allow truthy/falsey types, as it is for bool? Or should we stick to how literals are handled in Pydantic?

sydney-runkle commented 1 month ago

@Viicos,

I think we should stick to how literals are handled in Pydantic, just bc this would be a breaking change and I think Literal values intuitively should be handled pretty strictly (as they currently are).