Sorry it's another similar question to #1459
schema refers to https://github.com/keleshev/schema
I understand that pydantic primary purpose is for parsing and not validation as written here
pydantic is primarily a parsing library, not a validation library. Validation is a means to an end: building a model which conforms to the types and constraints provided.
In https://www.cosmicpython.com/book/appendix_validation.html#_validating_syntax
it recommends using schema to validate the json data that's meant to be converted into this class called Allocate
from schema import And, Schema, Use
@dataclass
class Allocate(Command):
_schema = Schema({ #(1)
'orderid': int,
sku: str,
qty: And(Use(int), lambda n: n > 0)
}, ignore_extra_keys=True)
orderid: str
sku: str
qty: int
@classmethod
def from_json(cls, data): #(2)
data = json.loads(data)
return cls(**_schema.validate(data))
def command(name, **fields): #(1)
schema = Schema(And(Use(json.loads), fields), ignore_extra_keys=True)
cls = make_dataclass(name, fields.keys()) #(2)
cls.from_json = lambda s: cls(**schema.validate(s)) #(3)
return cls
def greater_than_zero(x):
return x > 0
quantity = And(Use(int), greater_than_zero) #(4)
Allocate = command( #(5)
orderid=int,
sku=str,
qty=quantity
)
AddStock = command(
sku=str,
qty=quantity
I feel that actually I can use pydantic to parse the json into the Allocate class instead.
Am I right in my understanding
You can indeed, and Pydantic even has constrained types built in: https://pydantic-docs.helpmanual.io/usage/types/#constrained-types
ignore_extra_keys is controlled by the model Config, but is by default set to ignore. https://pydantic-docs.helpmanual.io/usage/model_config/
from pydantic import BaseModel, conint
class Allocate(BaseModel):
orderid: int
sku: str
qty: conint(gt=0)
class AddStock(BaseModel):
sku: str
qty: conint(gt=0)
And then you would use it like:
data = Allocate(**json.loads('{"orderid": 123, "sku": "abcde", "qty": 3}'))
or use the parse_raw helper function: https://pydantic-docs.helpmanual.io/usage/models/#helper-functions
data = Allocate.parse_raw('{"orderid": 123, "sku": "abcde", "qty": 3}')
If you're using them as function calls, you can use the validate_arguments decorator: https://pydantic-docs.helpmanual.io/usage/validation_decorator/
from pydantic import conint, validate_arguments, ValidationError
@validate_arguments
def allocate(orderid: int, sku: str, qty: conint(gt=0)):
print(f"{orderid=}")
print(f"{sku=}")
print(f"{qty=}")
try:
a = allocate('wrong', 'hello', 0)
except ValidationError as exc:
print(exc)
"""
2 validation errors for Allocate
orderid
value is not a valid integer (type=type_error.integer)
qty
ensure this value is greater than 0 (type=value_error.number.not_gt; limit_value=0)
"""
Successful run:
try:
a = allocate(123456, 'hello', 1)
except ValidationError as exc:
print(exc)
orderid=123456
sku='hello'
qty=1
And finally, Pydantic can be used in almost any context, but it appears that that document is building an API. You might want to take a look at FastAPI: https://fastapi.tiangolo.com which uses Pydantic as its base for input and output, and has some pretty great documentation on working with it, if you're not tied to Flask.
excellent answer @StephenBrown2, thank you.
Yes thank you, @StephenBrown2 great answer 馃憤
Most helpful comment
You can indeed, and Pydantic even has constrained types built in: https://pydantic-docs.helpmanual.io/usage/types/#constrained-types
ignore_extra_keysis controlled by the model Config, but is by default set to ignore. https://pydantic-docs.helpmanual.io/usage/model_config/And then you would use it like:
or use the
parse_rawhelper function: https://pydantic-docs.helpmanual.io/usage/models/#helper-functionsIf you're using them as function calls, you can use the validate_arguments decorator: https://pydantic-docs.helpmanual.io/usage/validation_decorator/
Successful run:
And finally, Pydantic can be used in almost any context, but it appears that that document is building an API. You might want to take a look at FastAPI: https://fastapi.tiangolo.com which uses Pydantic as its base for input and output, and has some pretty great documentation on working with it, if you're not tied to Flask.