Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions guide/src/function/signature.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,10 +265,9 @@ Type: builtin_function_or_method

### Type annotations in the signature

When the `experimental-inspect` Cargo feature is enabled, the `signature` attribute can also contain type hints:
The `signature` attribute can also contain type hints:

```rust
# #[cfg(feature = "experimental-inspect")] {
use pyo3::prelude::*;

#[pymodule]
Expand All @@ -281,21 +280,21 @@ pub mod example {
arg
}
}
# }
```

It enables the [work-in-progress capacity of PyO3 to autogenerate type stubs](../type-stub.md) to generate a file with the correct type hints:

```python
def list_of_int_identity(arg: list[int]) -> list[int]: ...
def list_of_int_identity(arg: "list[int]") -> "list[int]": ...
```

instead of the generic:

```python
import typing
from typing import Any

def list_of_int_identity(arg: typing.Any) -> typing.Any: ...
def list_of_int_identity(arg: Any) -> Any: ...
```

Note that currently type annotations must be written as Rust strings.
Note that currently type annotations must be written as strings.
Future enhancements of PyO3's typing support may include the ability to parse a limited subset of Python's type expression syntax.
4 changes: 2 additions & 2 deletions guide/src/type-stub.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ class Class:
def __eq__(self, other: Class) -> bool: ...
def __ne__(self, other: Class) -> bool: ...

def list_of_int_identity(arg: list[int]) -> list[int]: ...
def list_of_int_identity(arg: "list[int]") -> "list[int]": ...
```

The only piece of added syntax is that the `#[pyo3(signature = ...)]` attribute can now contain type annotations like `#[pyo3(signature = (arg: "list[int]") -> "list[int]")]` (note the `""` around type annotations).
The only piece of new syntax is that the `#[pyo3(signature = ...)]` attribute can contain type annotations like `#[pyo3(signature = (arg: "list[int]") -> "list[int]")]` (note the `""` around type annotations).
This is useful when PyO3 is not able to derive proper type annotations by itself.
Comment thread
tbates-redarc marked this conversation as resolved.

## Constraints and limitations
Expand Down
1 change: 1 addition & 0 deletions newsfragments/5999.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Removed errors when type annotations are used without `experimental-inspect` feature
49 changes: 12 additions & 37 deletions pyo3-macros-backend/src/pyfunction/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -474,13 +474,6 @@ impl<'a> FunctionSignature<'a> {
)
};

if let Some(returns) = &attribute.value.returns {
ensure_spanned!(
cfg!(feature = "experimental-inspect"),
returns.1.span() => "Return type annotation in the signature is only supported with the `experimental-inspect` feature"
);
}

for item in &attribute.value.items {
match item {
SignatureItem::Argument(arg) => {
Expand All @@ -503,15 +496,9 @@ impl<'a> FunctionSignature<'a> {
if let Some((_, default)) = &arg.eq_and_default {
fn_arg.default_value = Some(Box::new(default.clone()));
}
#[cfg(feature = "experimental-inspect")]
if let Some((_, annotation)) = &arg.colon_and_annotation {
ensure_spanned!(
cfg!(feature = "experimental-inspect"),
annotation.span() => "Type annotations in the signature is only supported with the `experimental-inspect` feature"
);
#[cfg(feature = "experimental-inspect")]
{
fn_arg.annotation = Some(annotation.as_type_hint());
}
fn_arg.annotation = Some(annotation.as_type_hint());
}
}
SignatureItem::VarargsSep(sep) => {
Expand All @@ -521,44 +508,32 @@ impl<'a> FunctionSignature<'a> {
let fn_arg = next_non_py_argument_checked(&varargs.ident)?;
fn_arg.to_varargs_mut()?;
parse_state.add_varargs(&mut python_signature, varargs)?;
#[cfg(feature = "experimental-inspect")]
if let Some((_, annotation)) = &varargs.colon_and_annotation {
ensure_spanned!(
cfg!(feature = "experimental-inspect"),
annotation.span() => "Type annotations in the signature is only supported with the `experimental-inspect` feature"
);
#[cfg(feature = "experimental-inspect")]
{
let FnArg::VarArgs(fn_arg) = fn_arg else {
unreachable!(
let FnArg::VarArgs(fn_arg) = fn_arg else {
unreachable!(
"`Python` and `CancelHandle` are already handled above and `*args`/`**kwargs` are \
parsed and transformed below. Because the have to come last and are only allowed \
once, this has to be a regular argument."
);
};
fn_arg.annotation = Some(annotation.as_type_hint());
}
};
fn_arg.annotation = Some(annotation.as_type_hint());
}
}
SignatureItem::Kwargs(kwargs) => {
let fn_arg = next_non_py_argument_checked(&kwargs.ident)?;
fn_arg.to_kwargs_mut()?;
parse_state.add_kwargs(&mut python_signature, kwargs)?;
#[cfg(feature = "experimental-inspect")]
if let Some((_, annotation)) = &kwargs.colon_and_annotation {
ensure_spanned!(
cfg!(feature = "experimental-inspect"),
annotation.span() => "Type annotations in the signature is only supported with the `experimental-inspect` feature"
);
#[cfg(feature = "experimental-inspect")]
{
let FnArg::KwArgs(fn_arg) = fn_arg else {
unreachable!(
let FnArg::KwArgs(fn_arg) = fn_arg else {
unreachable!(
"`Python` and `CancelHandle` are already handled above and `*args`/`**kwargs` are \
parsed and transformed below. Because the have to come last and are only allowed \
once, this has to be a regular argument."
);
};
fn_arg.annotation = Some(annotation.as_type_hint());
}
};
fn_arg.annotation = Some(annotation.as_type_hint());
}
}
SignatureItem::PosargsSep(sep) => {
Expand Down
9 changes: 0 additions & 9 deletions tests/ui/invalid_annotation.rs

This file was deleted.

5 changes: 0 additions & 5 deletions tests/ui/invalid_annotation.stderr

This file was deleted.

9 changes: 0 additions & 9 deletions tests/ui/invalid_annotation_return.rs

This file was deleted.

5 changes: 0 additions & 5 deletions tests/ui/invalid_annotation_return.stderr

This file was deleted.

Loading