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

Add support to chainable validations #472

Closed
likern opened this issue Apr 13, 2019 · 3 comments

Comments

Projects
None yet
2 participants
@likern
Copy link

commented Apr 13, 2019

Question | Feature Request | Bug

For bugs/questions:

  • OS: Ubuntu 18.04
  • Python version: 3.7.3 (default, Mar 26 2019, 00:55:50) [GCC 7.3.0]
  • Pydantic version: 0.23

Note: I asked this question on StackOverflow.

Now, BaseModel objects can only be constructed from dict. But it's very desirable to construct BaseModel object from another BaseModel objects.

This is my case:
I have a webhook which is used for whole protocol. All different data types are passed as json body.

@app.route("/", methods=['POST'])
async def telegram_webhook(request):
    update = Update.parse_obj(request.json)
    /* do something with update */

I use Update model for validation (which is used are base validation):

class Update(BaseModel):
    update_id: int
    message: Optional[Message]
    ...

class Message(BaseModel):
    message_id: int
    text: Optional[str]

But later, I want to apply additional validation to Message (so to check that it is TextMessage and to convert to it):

class TextMessage(Message):
    text: str # Now is required

    @validator('text')
    def check_text_length(cls, value):
        length = len(value)
        if length > 4096:
            raise ValueError(f'text length {length} is too large')
        return value

So I get Message object in function and get expection:

def process_text_message(message):
    text_message = TextMessage.parse_obj(message)

How to solve this?
It would be great, if I could get entry dict, convert it to BaseModel object and process all validation / conversions / etc through BaseModel, without conversions to dict. And at the end, as last step, to convert it back to dict (for example to insert into MongoDB)

@samuelcolvin

This comment has been minimized.

Copy link
Owner

commented Apr 15, 2019

I've given a quick and dirty answer on SO: use parse_obj(model.dict()).

But the real solution is to improve parse_obj to cope with dict-like objects.

Something like

        if not isinstance(obj, dict):
            exc = TypeError(f'{cls.__name__} expected dict not {type(obj).__name__}')
            raise ValidationError([ErrorWrapper(exc, loc='__obj__')])
        return cls(**obj)

Should be replaced with

try:
    cls(**dict(obj))
except (KeyError, ValueError) as e:
    raise ValidationError([ErrorWrapper(exc, loc='__obj__')]) from e

@samuelcolvin samuelcolvin added the bug label Apr 15, 2019

samuelcolvin added a commit that referenced this issue Apr 15, 2019

@samuelcolvin samuelcolvin referenced this issue Apr 15, 2019

Merged

fix parse_obj for dict-like object #476

3 of 4 tasks complete
@samuelcolvin

This comment has been minimized.

Copy link
Owner

commented Apr 15, 2019

should be fixed in #476

@likern

This comment has been minimized.

Copy link
Author

commented Apr 16, 2019

@samuelcolvin Thank you very much for answer and great support. I'll be eagerly await fix in new release.

samuelcolvin added a commit that referenced this issue Apr 17, 2019

fix parse_obj for dict-like object (#476)
* fix parse_obj for dict-like object, fix #472

* correct internal errors with parse_obj
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.