diff --git a/guide/src/function/signature.md b/guide/src/function/signature.md index 9c4ca8c03f3..b791ae494f2 100644 --- a/guide/src/function/signature.md +++ b/guide/src/function/signature.md @@ -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] @@ -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. diff --git a/guide/src/type-stub.md b/guide/src/type-stub.md index 186225296b1..0ac11a54e5f 100644 --- a/guide/src/type-stub.md +++ b/guide/src/type-stub.md @@ -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. ## Constraints and limitations diff --git a/newsfragments/5999.changed.md b/newsfragments/5999.changed.md new file mode 100644 index 00000000000..2c2afc3bc18 --- /dev/null +++ b/newsfragments/5999.changed.md @@ -0,0 +1 @@ +Removed errors when type annotations are used without `experimental-inspect` feature diff --git a/pyo3-macros-backend/src/pyfunction/signature.rs b/pyo3-macros-backend/src/pyfunction/signature.rs index fff083c1fdb..b80247859b3 100644 --- a/pyo3-macros-backend/src/pyfunction/signature.rs +++ b/pyo3-macros-backend/src/pyfunction/signature.rs @@ -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) => { @@ -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) => { @@ -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) => { diff --git a/tests/ui/invalid_annotation.rs b/tests/ui/invalid_annotation.rs deleted file mode 100644 index d8b803550ca..00000000000 --- a/tests/ui/invalid_annotation.rs +++ /dev/null @@ -1,9 +0,0 @@ -use pyo3::prelude::*; - -#[pyfunction] -#[pyo3(signature = (a: "int"))] -fn check(a: usize) -> usize { - a -} - -fn main() {} diff --git a/tests/ui/invalid_annotation.stderr b/tests/ui/invalid_annotation.stderr deleted file mode 100644 index ff2981b4818..00000000000 --- a/tests/ui/invalid_annotation.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: Type annotations in the signature is only supported with the `experimental-inspect` feature - --> tests/ui/invalid_annotation.rs:4:24 - | -4 | #[pyo3(signature = (a: "int"))] - | ^^^^^ diff --git a/tests/ui/invalid_annotation_return.rs b/tests/ui/invalid_annotation_return.rs deleted file mode 100644 index 5cb4298ec8b..00000000000 --- a/tests/ui/invalid_annotation_return.rs +++ /dev/null @@ -1,9 +0,0 @@ -use pyo3::prelude::*; - -#[pyfunction] -#[pyo3(signature = (a) -> "int")] -fn check(a: usize) -> usize { - a -} - -fn main() {} diff --git a/tests/ui/invalid_annotation_return.stderr b/tests/ui/invalid_annotation_return.stderr deleted file mode 100644 index 2a70079f82d..00000000000 --- a/tests/ui/invalid_annotation_return.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: Return type annotation in the signature is only supported with the `experimental-inspect` feature - --> tests/ui/invalid_annotation_return.rs:4:27 - | -4 | #[pyo3(signature = (a) -> "int")] - | ^^^^^