-
-
Notifications
You must be signed in to change notification settings - Fork 374
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
Allow converter.optional to take a Converter such as converter.pipe as its argument #1372
Conversation
2c43211
to
9b22892
Compare
def optional_converter(val, inst, field): | ||
if val is None: | ||
return None | ||
return converter(val, inst, field) |
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.
It's not guaranteed that the converter takes 3 arguments.
The root issue is that earlier versions of attrs had a "basic" converter that just took a single val
. But now with the Converter
class, Converter
callables may take one, two (self), two(field), or three parameters.
Some introspection here may be necessary.
Also, since converters now may be callables with one two or three params, the type signature ought to be updated as well
https://github.com/python-attrs/attrs/blob/main/src/attrs/__init__.pyi#L54
Something like Callable[[Any], Any] | Callable[[Any, Any], Any] | Callable[[Any, Any, Any], Any]
?
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.
Actually a Converter
instance always takes three arguments:
Lines 2712 to 2725 in 13e9a6a
if not (self.takes_self or self.takes_field): | |
self.__call__ = lambda value, _, __: self.converter(value) | |
elif self.takes_self and not self.takes_field: | |
self.__call__ = lambda value, instance, __: self.converter( | |
value, instance | |
) | |
elif not self.takes_self and self.takes_field: | |
self.__call__ = lambda value, __, field: self.converter( | |
value, field | |
) | |
else: | |
self.__call__ = lambda value, instance, field: self.converter( | |
value, instance, field | |
) |
The callable it takes as an argument can take one, two or three, but the Converter
class normalizes it to always take three arguments
So I believe this is correct
I think the typing information might need an update, to accept Callable[[Any], Any] | Converter
but I think that's a separate issue so maybe we should follow up on that on a separate PR?
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.
Thanks for starting on a fix!
The constructor consumes __annotations__, so move the constructor call to after those have been set on the optional_converter function
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.
Thanks for sorting it out yourself y'all! Feel free to open a PR re the typing issue you mentioned.
Thanks for merging @hynek ! I have a follow up on typing on #1373 but looks like that's still failing CI, looks like mypy on 3.10+ breaks with the error in the comments (even though I also posted #1374 to fix another issue I uncovered in converters, in a situation where they evaluate to False. Long story short, but doing an explicit comparison to None fixes that and I believe it makes sense here. Cheers! |
Summary
Allow
converter.optional
to take a Converter such asconverter.pipe
as its argument.Fixes #1348
Pull Request Check List
main
branch – use a separate branch!Our CI fails if coverage is not 100%.
.pyi
)..rst
and.md
files is written using semantic newlines.changelog.d
.