-
Notifications
You must be signed in to change notification settings - Fork 770
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
RFC: remove default of None for trailing optional arguments #2935
Comments
IMO the current mode (with the warning elevated to error) is fine. With arguments that can be |
@ritchie46 - after reading #2925 I'd be interested in your comment as a user - you were either unaware of this default, or would prefer the change proposed here? |
#2932 sounds like another case of a user confused by this (maybe just because it wasn't documented). |
I'm generally against doing implicit things, so this sounds good. I've been mulling about how to communicate this behavior. The current api heavily relies on assuming that users read the documentation. I've been guilty of this myself - I have at times just used Option without really thinking about what behavior I actually wanted. What about just requiring the signature attribute if there is an Option anywhere in the function signature? |
Although "implicit" can mean a lot of different things. In this case, you could argue that any case of not using |
I was unaware of the defaults. I think having a well documented default makes sense. It can remove some boilerplate for the default case. |
Definitely true, though I'd make the argument that it's reasonable to assume that not using Because of the rule here which I propose we deprecate, at the moment the implicit signature is more like
Thanks. Good to know. From a user perspective, for some function like #[pyfunction]
fn my_function(arg1: Option<String>, arg2: Option<String>) { depending on the default we pick here, one of the following forms will always be necessary: // to take required `Option<String>` arguments, this is currently necessary
#[pyfunction(signature = (arg1, arg2))]
fn my_function(arg1: Option<String>, arg2: Option<String>) {
// to make optional arguments, this would be necessary if the proposal here were accepted
#[pyfunction(signature = (arg1=None, arg2=None))]
fn my_function(arg1: Option<String>, arg2: Option<String>) { The question is which of these would users be happier writing? Personally, I think it's more frustrating as a user to have to write the form
I think to action the change here, we would need to do exactly that for a couple of versions (maybe as a deprecation warning). In the long term, I'd prefer to not have to write the "no-op" signature (e.g. |
Add me to the "confused user" list (#3735 ). Rust does not have a concept of optional arguments, just arguments of type My particular case is that # python
def my_fn(a: Optional[int], b: int): ... has the obvious equivalent of // pyo3
pub fn my_fn(a: Option<i64>, b: i64) -> ... but the latter is a compile error. |
This was shipped in 0.22; I will add to 0.24 milestone as the next step (making a hard error temporarily) will come then. |
Jumping into this RFC to warn of a regression this behavior change would cause for libraries that are used similarly in Rust and Python. One example is my code, ANISE, where several of the functions are available in both languages. Let's take the example of the Py03 version 0.22 warns the following:
Adding a
with #[pyo3(signature = (target_frame, observer_frame, epoch, ab_corr=None))]
pub fn translate(
// ... Attempting to add a
with #[cfg_attr(feature ="python", pyo3(signature = (target_frame, observer_frame, epoch, ab_corr=None)))]
pub fn translate( Note that the ANISE crate and Python package are separate crates but part of the same cargo workspace. |
Thanks @ChristopherRabotin for raising the concern. A couple of thoughts here:
|
In #2934 I've documented a longstanding PyO3 behaviour to automatically add a default of
None
to all trailingOption<T>
arguments.I think that behaviour is a small footgun, as I don't think first-time users necessarily expect this. I see two downsides:
None
for these arguments when they wanted them to be requiredWe currently have the deprecation from #2703 which we can upgrade to an error in 0.20. This helps the situation, as it makes the refactoring in the second bullet fail nosily.
I'd be keen to remove the trailing default, with a deprecation warning for functions using this behaviour which don't currently have a
#[pyo3(signature = (...))]
annotation. I think it's a simpler API for users if PyO3 never adds an implicit default, and removes the need for the error on the refactoring case (which is purely a guard rail to avoid the current footgun).What do others think? I'd be keen to hear from folks who think the conveniences of the current behaviour (i.e. fewer macro annotations) outweigh the drawbacks listed above. (@mejrs - in #2193 I got the impression that you might hold this view.)
The text was updated successfully, but these errors were encountered: