-
Notifications
You must be signed in to change notification settings - Fork 200
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
Support kwargs
with from_attributes
#306
Support kwargs
with from_attributes
#306
Conversation
As per the issue,
Basically Does that make sense? |
hi @samuelcolvin , maybe I should've clarified the impl before starting. I took some time to dig through the code base but still quite confused about the translation from pydantic to pyo3 to rust So based on my understanding - this is used by pydantic in by adding fn validate_typed_dict(
&'a self,
strict: bool,
from_attributes: bool,
+ additional_kwargs: Option<(&'a PyAny, Option<&'a PyDict>)>,
) -> ValResult<GenericMapping<'a>> {
if from_attributes { // <-- does from_attributes relate to this additional_kwargs?
if let Some((object, kwargs)) = additional_kwargs {
return Ok(GenericMapping::PyGetAttr(object, kwargs));
}
...
} and if that's correct, how would I get this |
Not your fault, I think the problem is me 1) not thinking it through enough before creating the issue 2) not giving a clear description of what I have thought of. Part of this is an in unavoidable result of "thinking by coding" - I often don't know how to do things until I'm half way through doing things. "from orm" will change a lot in V2, not just being renamed to
The way to allow a higher priority dict (aka So the signature of pydantic-core/src/input/input_python.rs Lines 345 to 346 in da0a6c7
to something like if from_attributes_applicable(self) {
Ok(self.into())
} else if let Ok((obj, kwargs)) = self.extract::<(&PyAny, &PyDict)>() {
if from_attributes_applicable(self) {
// return a generic mapping with the object and kwargs
} else {
// note the error here gives a hint about from_attributes
Err(ValError::new(ErrorKind::DictAttributesType, self))
} Then the logic in python will take care of passing Hope that makes sense? |
1f3c022
to
edef072
Compare
thanks for the explanation @samuelcolvin! that cleared it up for sure, I think I implemented most of it through your guidance but still learning to debug this locally - would the test case added to typed-dict here be an example of how the python api uses this new feature? so setting |
Sorry for the slow reply, somehow I missed this. Yes that looks right. Let me know when this is ready to review. |
Hi @jcsho when do you think you'll be able to finish this? Let me know if you have any questions. |
@samuelcolvin sorry also didn't see this notification - just got back from vacation so will try to continue tackling this this weekend. |
@samuelcolvin actually I took some time to debug the issue tonight and I found that I might still be confused about the usage. I pushed my current working code to this branch.
# validate_typed_dict()
if let Ok(dict) = self.cast_as::<PyDict>() { # always matches for any dict
return Ok(dict.into());
}
... strict checking
if let Ok((obj, kwargs)) = self.extract::<(&PyAny, &PyDict)>() { # doesn't reach here
if from_attributes_applicable(self) {
return Ok(GenericMapping::PyGetAttr(obj, Some(kwargs)));
} else {
return Err(ValError::new(ErrorType::DictAttributesType, self));
}
} so maybe I didn't quite understand how the current input can be parsed?
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as described below, I think the reason your println
isn't being called is that the input is wrong.
As for 2), I have no idea, I don't use debug breakpoints, I generally use the dbg!
macro.
tests/validators/test_typed_dict.py
Outdated
'from_attributes': True, | ||
} | ||
) | ||
test_input = dict(a=1, b=2, c='3', d=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
your input data passed is still a dict, not a tuple.
I think you need to pass something like
class Foobar:
def __init__(self):
self.a = 1
self.b = 2
self.c = 3
test_input = (Foobar(), dict(c=3)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated test cases thanks!
2a17625
to
fb9cd36
Compare
CodSpeed Performance ReportMerging #306 Summary
|
Codecov Report
Additional details and impacted files@@ Coverage Diff @@
## main #306 +/- ##
==========================================
- Coverage 96.51% 96.50% -0.01%
==========================================
Files 87 87
Lines 9447 9455 +8
Branches 4 4
==========================================
+ Hits 9118 9125 +7
- Misses 329 330 +1
Continue to review full report at Codecov.
|
Hi @samuelcolvin, took awhile but finally understood what the expected behaviour was. I added the corresponding test cases to the existing Just need a review on the Rust side - if the macros re-arrangements of the arguments to allow optional fields is an okay solution or any edge cases you want me to test |
bump @samuelcolvin in case you didn't get to see this is ready for review :) |
This is awesome, thank you so much @jcsho, I'm sorry I didn't see you had completed this until now - entirely my mistake 🙏. |
Draft PR based on the #223 details but got stuck on the actual usage in the python api side.
Would like some help defining the expected test cases and if the optional args in the macro_rules changes are expected?