Allows custom signatures for #[getter] and #[setter] in order to provide type hints#5738
Conversation
Tpt
left a comment
There was a problem hiding this comment.
Thank you for this!
Allowing signature might be slightly confusing to the user: the getter/setter are not exposed as method to cpython so things like argument name do not exist outside of stub generation. But indeed, it would be very convenient for stubs.
It might be nice to have some testing:
- add a class with such custom signature in
pytests/src/pyclasses.rsto generate the stubs and check they are valid (runnox -s test-introspectionto run the introspection tests) - maybe make sure very wrong signatures (e.g. extra arguments) are still prevented by the macro with a compile error test in
pyo3/tests/test_compile_error.rs
| if let Some(text_signature) = text_signature { | ||
| match fn_type { | ||
| FnType::Getter(_) => { | ||
| bail_spanned!(text_signature.kw.span() => "`text_signature` not allowed with `getter`") |
There was a problem hiding this comment.
Do we have a use case for text_signature? I don't think it's even possible to expose them to cpython
There was a problem hiding this comment.
Reverted it! I didn't quite realize the difference between text_signature and signature.
A fair point, but I guess the alternative would be another attribute macro? I thought about it, but I reasoned that the tradeoff is the mental load of remembering more attribute names would be worse. I'll push up some tests when I get some more free time! |
Yes! Agreed.
Thank you! |
|
I'm not sure we should so this if we can not make it work the same as for other functions as well. I feel like it would be very surprising if one for example specifies a signature with a default value which is then not respected, or overwriting a text_signature which is then not exposed to Python. Additionally these do not accept arbitrary signatures, so we would to cover that as well. I feel like a general mechanism to override/adapt the type hints would be a better fit for this functionality. That would make it clear that it only affects type hint generation and not runtime behavior. |
|
@Icxolu that's also a fair point. But doesnt The cost of adding a new attribute would then be having multiple ways to specify the same thing, which I think is something python gets right in strongly recommending against. By this I mean that
|
It does that for normal functions, but it might not do it for these, because it currently can't be placed there. Also a setter does have a second argument, namely the value to be set.
I generally agree that we should not offer competing ways to do the same thing. These are all good questions and I don't have direct answer to which is best. I just think that we may need to explore some designs here first, especially since stub generation is still pretty experimental. |
|
What's the use case when this is needed? For types exposed by PyO3, the type hints should hopefully be good enough. For custom types, maybe a |
There is likely still a small need when the field type is something like An other option is to encourage users to use a "new type" approach, writing |
|
Agreed. For what it's worth, I think I'm ok with having |
My use case is exactly what @Tpt laid out. I'm returning a
Great! I'll work on some tests for this over the next few weeks when I get some free time to do so. |
…ub.com/varchasgopalaswamy/pyo3 into introspection-allow-property-signature
… and made the test for stub generation a little easier to look at
…etters and setters
|
@Tpt Could you take a look at the updates I've made when you have some time?
Let me know if you want anything else! |
Tpt
left a comment
There was a problem hiding this comment.
Thank you for this work.
It looks good to me. I just would like to get an approval from @davidhewitt if he is fine with having custom signatures on getter/setter and with the additional dev dependencies
pyo3-introspection/tests/test.rs
Outdated
| .strip_prefix(base_dir_path)? | ||
| .into(), | ||
| fs::read_to_string(entry.path())?, | ||
| format_with_ruff(&fs::read_to_string(entry.path())?)?, |
There was a problem hiding this comment.
All stubs file checked out in the repository should be already formatted with ruff (there is a CI job for that)
pyo3-introspection/tests/test.rs
Outdated
| similar::TextDiff::from_lines(&expected_file_content_fixed, &actual_file_content_fixed); | ||
| if diff | ||
| .iter_all_changes() | ||
| .any(|f| f.tag() == similar::ChangeTag::Delete || f.tag() == similar::ChangeTag::Insert) |
There was a problem hiding this comment.
I guess we can do it more simply with just expected_file_content_fixed == actual_file_content_fixed
pyo3-introspection/tests/test.rs
Outdated
| print!("{}{}", style.apply_to(sign).bold(), style.apply_to(change)); | ||
| } | ||
| } | ||
| panic!( |
There was a problem hiding this comment.
Sometime cargo test do not display what is written to stdout. What about inserting the diff in the panic message (line jump are fine there)
Without the automatic type stub generation, it makes sense that the signature of getters and setters should not be overriden. However, with stub generation there can be a need to provide custom type hints. This PR relaxes the requirement that custom signatures not be allowed for getters and setters to enable this use case.