-
Notifications
You must be signed in to change notification settings - Fork 760
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
Improving function "signatures" #2193
Comments
I agree that the syntax needs to be more explicit and consistent. Option 2, although attractive for DRY, is a non-starter IMO since tools other than rustc just that ignore attributes would choke on it. Individual attributes on arguments could be an alternative; I don't remember when they were stabilized though, and I suspect it wouldn't be more readable. |
Good points. For sake of sketching out, I guess individual attributes might look something like this: #[pyfunction]
fn foo(
a: i32,
#[pyo3(/)] b: i32,
#[pyo3(default = None)] c: Option<i32>,
#[pyo3(default = 5)] d: i32,
#[pyo3(**)] kwargs: Option<&PyDict>
) {
(a, b, c, d, kwargs)
} This would fit nicely with existing (Is there an argument we could allow |
I don't think the current situation is so bad. I'm inclined to do nothing with default arguments, and let users handle it themselves: fn foo(a: i32, b: i32, c: Option<i32>, d: Option<i32>, kwargs: Option<&PyDict>) {
let d = d.unwrap_or(5);
...
}
This is too magical and confusing IMO. I really don't want this. |
Using
|
I made at least three mistakes related to |
Yes, I'm leaning towards |
Anything left to do here? |
I need to rebase #2703 and I have a branch nearly ready for auto |
TLDR; I propose a
#[pyo3(signature)]
attribute for both#[pyfunction]
and#[pymethods]
which:text_signature
Option<T>
which implicitly has aNone
default in some cases at current).Something like:
I've been thinking for a while that there are a few ergonomics improvements we could make around
#[pyfunction]
signatures. By signatures I collectively mean:#[pyo3(text_signature)]
featureOption<T>
and explicitly.Option<T>
is really the right behaviour,#[pyfunction]
macro or via the#[pyo3(args)]
attribute for#[pymethods]
./
), or*args
and**kwargs
. These are again supported by the same syntaxes as the "explicit default arguments" above.There's a few problems with all of this stuff:
#[text_signature]
repeats a lot of information already present in the rest of the function definition.Option<T>
having aNone
default makes the possibility of going out of sync worse.Option<T>
implicitly defaulted toNone
if a required parameter follows it. This was to avoid a large breaking change on existing code, however it does also make the rules very confusing.#[args]
annotation such as Argument specification by function attribute can be ambiguous #794 .Here's an example which exhibits some of these problems:
In particular:
text_signature
has the wrong argument names, wrong defaults, and is missing c.#[pyfunction(a, "/", d = 5, kwargs = "**")]
spec is missingb
andc
, so it's incredibly unclear what the actual function behavior is. As it turns out, PyO3 will currently makea
positional only,b
,c
andd
positional or keyword (c
defaultNone
andd
default5
), and**kwargs
as expected.Fixing this
I don't think we can easily change much about the existing systems. They're widely used, so adding additional checks to the
#[args()]
system or changing implicit-defautOption<T>
will cause a lot of breakage. Validatingtext_signature
seems impractical.Instead, my ideal solution would be to adopt a new syntax, which we can migrate over to and deprecate the above. My ideal syntax:
None
an explicit opt-in choice.text_signature
content.Throwing ideas into the ring, I can think of two possible syntaxes to achieve this. See sketches below of the problematic
foo
from above rewritten in these.1. new
#[pyo3(signature)]
annotationWe could introduce a new attribute option which could meet these ideas. I think this is the better choice for Rust readers, although does lead to some repetition.
2. support Python-like syntax directly in the Rust function
We could support things like
/
,**kwargs
and default values directly in the Rust function definition. It's not legal Rust syntax however the proc macro can remove the illegal syntax so that this compiles correctly.Compared to the above
#[pyo3(signature)]
attribute, this leads to even less boilerplate and a very natural usage of PyO3 for users mostly writing Python code. However, it makes it much harder to understand how this function should be called from Rust.Of the two ideas above, I think I prefer the
#[pyo3(signature)]
attribute better. However I just wanted to throw all ideas I had out into the ring, and see you folks think as well as what else you might propose.I'm not sure I'll have a chance to work on this soon, so as the preferred design emerges, if anyone wants to implement this please feel free to claim it!
The text was updated successfully, but these errors were encountered: