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
Closed

Add support to chainable validations #472

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

Comments

@likern
Copy link

@likern likern 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
Copy link
Owner

@samuelcolvin samuelcolvin 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 added a commit that referenced this issue Apr 15, 2019
@samuelcolvin
Copy link
Owner

@samuelcolvin samuelcolvin commented Apr 15, 2019

should be fixed in #476

@likern
Copy link
Author

@likern likern 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, 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
Labels
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

2 participants