@validates accepts multiple field names#1965
Conversation
|
apologies for the long delay on this. i hesitated initially because i had the same concern as @deckar01 about this being a breaking change. now that we're closing to releasing the next major, i think this is one that we can get merged. i'll update this when i have some time |
|
should validator methods receive from marshmallow import Schema, fields, validates, ValidationError
class UserSchema(Schema):
name = fields.Str(required=True)
nickname = fields.Str(required=True)
@validates("name", "nickname")
def validate_names(self, value: str, field_name: str) -> str:
if len(value) < 3:
raise ValidationError(f"{field_name} too short")
return value |
|
looks like SQLAlchemy does pass a from sqlalchemy.orm import validates
class EmailAddress(Base):
__tablename__ = "address"
id = mapped_column(Integer, primary_key=True)
email = mapped_column(String)
@validates("email")
def validate_email(self, key, address):
if "@" not in address:
raise ValueError("failed simple email validation")
return address |
|
Updated to pass |
lafrech
left a comment
There was a problem hiding this comment.
No strong opinion about this. It adds a bit of API surface for a case that may not be so frequent, but addressing it with validates_schema is less convenient so this makes sense.
I'm not a fan of the "string or list of strings" pattern. In fact I didn't see where the magic operates but I suppose it does, otherwise all tests would be broken. And expecting a list of strings for a single field (99% case) would be a pity.
| @validates("name", "nickname") | ||
| def validate_names(self, value: str, data_key: str) -> None: | ||
| if len(value) < 3: | ||
| raise ValidationError("Too short") |
There was a problem hiding this comment.
This would be the right place to show the use of data_key like in the upgrading guide.
there's actually no special-casing here because def validates(*field_names: str)allows one or more field names to be passed positionally. |
|
But then in (I'm not talking about mypy / type checking but about runtime.) |
|
>>> def validates(*field_names: str):
... print(type(field_names))
...
>>> validates("foo")
<class 'tuple'> |
|
Oh sorry, I missed the obvious. The user never passes a tuple or list, just N positional args. |
|
I just rebased this but couldn't figure out how to (force) push into the original PR branch. Here's the rebase: https://github.com/marshmallow-code/marshmallow/compare/pr/1965 Is there anything else that needs to be done to merge this? |
|
no blockers to merging! |
|
Looks like we're done with milestone 4.0. Should we ship? Review open issues/PR to see if anything else should be crammed in before releasing? #2799 and #2810 are not breaking so they could be added later. |
|
nice! let's let |
|
Great. No rush on my side.
Enjoy your trip!
|
Fix for #1960