Pydantic: [Question] how does pydantic differ from schema? Is it a good idea for me to use pydantic in this usecase?

Created on 6 May 2020  路  3Comments  路  Source: samuelcolvin/pydantic

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

question

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_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.

All 3 comments

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 馃憤

Was this page helpful?
0 / 5 - 0 ratings