Merge pull request #3232 from davidhewitt/remove-0-18-deprecations
remove all functionality deprecated in PyO3 0.18
This commit is contained in:
commit
0b4187a672
|
@ -185,89 +185,6 @@ fn increment(x: u64, amount: Option<u64>) -> u64 {
|
||||||
|
|
||||||
To help avoid confusion, PyO3 requires `#[pyo3(signature = (...))]` when an `Option<T>` argument is surrounded by arguments which aren't `Option<T>`.
|
To help avoid confusion, PyO3 requires `#[pyo3(signature = (...))]` when an `Option<T>` argument is surrounded by arguments which aren't `Option<T>`.
|
||||||
|
|
||||||
## Deprecated form
|
|
||||||
|
|
||||||
The `#[pyfunction]` macro can take the argument specification directly, but this method is deprecated in PyO3 0.18 because the `#[pyo3(signature)]` option offers a simpler syntax and better validation.
|
|
||||||
|
|
||||||
The `#[pymethods]` macro has an `#[args]` attribute which accepts the deprecated form.
|
|
||||||
|
|
||||||
Below are the same examples as above, but using the deprecated syntax:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
# #![allow(deprecated)]
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
|
||||||
use pyo3::types::PyDict;
|
|
||||||
|
|
||||||
#[pyfunction(kwds = "**")]
|
|
||||||
fn num_kwds(kwds: Option<&PyDict>) -> usize {
|
|
||||||
kwds.map_or(0, |dict| dict.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pymodule]
|
|
||||||
fn module_with_functions(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
|
||||||
m.add_function(wrap_pyfunction!(num_kwds, m)?).unwrap();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The following parameters can be passed to the `#[pyfunction]` attribute:
|
|
||||||
|
|
||||||
* `"/"`: positional-only arguments separator, each parameter defined before `"/"` is a
|
|
||||||
positional-only parameter.
|
|
||||||
Corresponds to python's `def meth(arg1, arg2, ..., /, argN..)`.
|
|
||||||
* `"*"`: var arguments separator, each parameter defined after `"*"` is a keyword-only parameter.
|
|
||||||
Corresponds to python's `def meth(*, arg1.., arg2=..)`.
|
|
||||||
* `args="*"`: "args" is var args, corresponds to Python's `def meth(*args)`. Type of the `args`
|
|
||||||
parameter has to be `&PyTuple`.
|
|
||||||
* `kwargs="**"`: "kwargs" receives keyword arguments, corresponds to Python's `def meth(**kwargs)`.
|
|
||||||
The type of the `kwargs` parameter has to be `Option<&PyDict>`.
|
|
||||||
* `arg="Value"`: arguments with default value. Corresponds to Python's `def meth(arg=Value)`.
|
|
||||||
If the `arg` argument is defined after var arguments, it is treated as a keyword-only argument.
|
|
||||||
Note that `Value` has to be valid rust code, PyO3 just inserts it into the generated
|
|
||||||
code unmodified.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```rust
|
|
||||||
# #![allow(deprecated)]
|
|
||||||
# use pyo3::prelude::*;
|
|
||||||
use pyo3::types::{PyDict, PyTuple};
|
|
||||||
#
|
|
||||||
# #[pyclass]
|
|
||||||
# struct MyClass {
|
|
||||||
# num: i32,
|
|
||||||
# }
|
|
||||||
#[pymethods]
|
|
||||||
impl MyClass {
|
|
||||||
#[new]
|
|
||||||
#[args(num = "-1")]
|
|
||||||
fn new(num: i32) -> Self {
|
|
||||||
MyClass { num }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[args(num = "10", py_args = "*", name = "\"Hello\"", py_kwargs = "**")]
|
|
||||||
fn method(
|
|
||||||
&mut self,
|
|
||||||
num: i32,
|
|
||||||
py_args: &PyTuple,
|
|
||||||
name: &str,
|
|
||||||
py_kwargs: Option<&PyDict>,
|
|
||||||
) -> String {
|
|
||||||
let num_before = self.num;
|
|
||||||
self.num = num;
|
|
||||||
format!(
|
|
||||||
"num={} (was previously={}), py_args={:?}, name={}, py_kwargs={:?} ",
|
|
||||||
num, num_before, py_args, name, py_kwargs,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_change(&mut self, num: i32) -> PyResult<String> {
|
|
||||||
self.num = num;
|
|
||||||
Ok(format!("num={}", self.num))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Making the function signature available to Python
|
## Making the function signature available to Python
|
||||||
|
|
||||||
The function signature is exposed to Python via the `__text_signature__` attribute. PyO3 automatically generates this for every `#[pyfunction]` and all `#[pymethods]` directly from the Rust function, taking into account any override done with the `#[pyo3(signature = (...))]` option.
|
The function signature is exposed to Python via the `__text_signature__` attribute. PyO3 automatically generates this for every `#[pyfunction]` and all `#[pymethods]` directly from the Rust function, taking into account any override done with the `#[pyo3(signature = (...))]` option.
|
||||||
|
|
|
@ -9,6 +9,59 @@ For a detailed list of all changes, see the [CHANGELOG](changelog.md).
|
||||||
|
|
||||||
PyO3 0.20 has increased minimum Rust version to 1.56. This enables use of newer language features and simplifies maintenance of the project.
|
PyO3 0.20 has increased minimum Rust version to 1.56. This enables use of newer language features and simplifies maintenance of the project.
|
||||||
|
|
||||||
|
### Required arguments are no longer accepted after optional arguments
|
||||||
|
|
||||||
|
[Trailing `Option<T>` arguments](./function/signature.md#trailing-optional-arguments) have an automatic default of `None`. To avoid unwanted changes when modifying function signatures, in PyO3 0.18 it was deprecated to have a required argument after an `Option<T>` argument without using `#[pyo3(signature = (...))]` to specify the intended defaults. In PyO3 0.20, this becomes a hard error.
|
||||||
|
|
||||||
|
Before:
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
#[pyfunction]
|
||||||
|
fn x_or_y(x: Option<u64>, y: u64) -> u64 {
|
||||||
|
x.unwrap_or(y)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
After:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
# #![allow(dead_code)]
|
||||||
|
# use pyo3::prelude::*;
|
||||||
|
|
||||||
|
#[pyfunction]
|
||||||
|
#[pyo3(signature = (x, y))] // both x and y have no defaults and are required
|
||||||
|
fn x_or_y(x: Option<u64>, y: u64) -> u64 {
|
||||||
|
x.unwrap_or(y)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Remove deprecated function forms
|
||||||
|
|
||||||
|
In PyO3 0.18 the `#[args]` attribute for `#[pymethods]`, and directly specifying the function signature in `#[pyfunction]`, was deprecated. This functionality has been removed in PyO3 0.20.
|
||||||
|
|
||||||
|
Before:
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
#[pyfunction]
|
||||||
|
#[pyo3(a, b = "0", "/")]
|
||||||
|
fn add(a: u64, b: u64) -> u64 {
|
||||||
|
a + b
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
After:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
# #![allow(dead_code)]
|
||||||
|
# use pyo3::prelude::*;
|
||||||
|
|
||||||
|
#[pyfunction]
|
||||||
|
#[pyo3(signature = (a, b=0, /))]
|
||||||
|
fn add(a: u64, b: u64) -> u64 {
|
||||||
|
a + b
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## from 0.18.* to 0.19
|
## from 0.18.* to 0.19
|
||||||
|
|
||||||
### Access to `Python` inside `__traverse__` implementations are now forbidden
|
### Access to `Python` inside `__traverse__` implementations are now forbidden
|
||||||
|
|
1
newsfragments/3232.removed.md
Normal file
1
newsfragments/3232.removed.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Remove all functionality deprecated in PyO3 0.18, including `#[args]` attribute for `#[pymethods]`.
|
|
@ -3,18 +3,12 @@ use quote::{quote_spanned, ToTokens};
|
||||||
|
|
||||||
pub enum Deprecation {
|
pub enum Deprecation {
|
||||||
PyClassTextSignature,
|
PyClassTextSignature,
|
||||||
PyFunctionArguments,
|
|
||||||
PyMethodArgsAttribute,
|
|
||||||
RequiredArgumentAfterOption,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deprecation {
|
impl Deprecation {
|
||||||
fn ident(&self, span: Span) -> syn::Ident {
|
fn ident(&self, span: Span) -> syn::Ident {
|
||||||
let string = match self {
|
let string = match self {
|
||||||
Deprecation::PyClassTextSignature => "PYCLASS_TEXT_SIGNATURE",
|
Deprecation::PyClassTextSignature => "PYCLASS_TEXT_SIGNATURE",
|
||||||
Deprecation::PyFunctionArguments => "PYFUNCTION_ARGUMENTS",
|
|
||||||
Deprecation::PyMethodArgsAttribute => "PYMETHODS_ARGS_ATTRIBUTE",
|
|
||||||
Deprecation::RequiredArgumentAfterOption => "REQUIRED_ARGUMENT_AFTER_OPTION",
|
|
||||||
};
|
};
|
||||||
syn::Ident::new(string, span)
|
syn::Ident::new(string, span)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::attributes::{TextSignatureAttribute, TextSignatureAttributeValue};
|
use crate::attributes::{TextSignatureAttribute, TextSignatureAttributeValue};
|
||||||
use crate::deprecations::{Deprecation, Deprecations};
|
|
||||||
use crate::params::impl_arg_params;
|
use crate::params::impl_arg_params;
|
||||||
use crate::pyfunction::{DeprecatedArgs, FunctionSignature, PyFunctionArgPyO3Attributes};
|
use crate::pyfunction::{FunctionSignature, PyFunctionArgPyO3Attributes};
|
||||||
use crate::pyfunction::{PyFunctionOptions, SignatureAttribute};
|
use crate::pyfunction::{PyFunctionOptions, SignatureAttribute};
|
||||||
use crate::utils::{self, PythonDoc};
|
use crate::utils::{self, PythonDoc};
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
|
@ -236,7 +235,6 @@ pub struct FnSpec<'a> {
|
||||||
pub python_name: syn::Ident,
|
pub python_name: syn::Ident,
|
||||||
pub signature: FunctionSignature<'a>,
|
pub signature: FunctionSignature<'a>,
|
||||||
pub output: syn::Type,
|
pub output: syn::Type,
|
||||||
pub deprecations: Deprecations,
|
|
||||||
pub convention: CallingConvention,
|
pub convention: CallingConvention,
|
||||||
pub text_signature: Option<TextSignatureAttribute>,
|
pub text_signature: Option<TextSignatureAttribute>,
|
||||||
pub unsafety: Option<syn::Token![unsafe]>,
|
pub unsafety: Option<syn::Token![unsafe]>,
|
||||||
|
@ -281,16 +279,14 @@ impl<'a> FnSpec<'a> {
|
||||||
let PyFunctionOptions {
|
let PyFunctionOptions {
|
||||||
text_signature,
|
text_signature,
|
||||||
name,
|
name,
|
||||||
mut deprecations,
|
|
||||||
signature,
|
signature,
|
||||||
..
|
..
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
let MethodAttributes {
|
let MethodAttributes {
|
||||||
ty: fn_type_attr,
|
ty: fn_type_attr,
|
||||||
deprecated_args,
|
|
||||||
mut python_name,
|
mut python_name,
|
||||||
} = parse_method_attributes(meth_attrs, name.map(|name| name.value.0), &mut deprecations)?;
|
} = parse_method_attributes(meth_attrs, name.map(|name| name.value.0))?;
|
||||||
|
|
||||||
let (fn_type, skip_first_arg, fixed_convention) =
|
let (fn_type, skip_first_arg, fixed_convention) =
|
||||||
Self::parse_fn_type(sig, fn_type_attr, &mut python_name)?;
|
Self::parse_fn_type(sig, fn_type_attr, &mut python_name)?;
|
||||||
|
@ -314,15 +310,9 @@ impl<'a> FnSpec<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let signature = if let Some(signature) = signature {
|
let signature = if let Some(signature) = signature {
|
||||||
ensure_spanned!(
|
|
||||||
deprecated_args.is_none(),
|
|
||||||
signature.kw.span() => "cannot define both function signature and legacy arguments"
|
|
||||||
);
|
|
||||||
FunctionSignature::from_arguments_and_attribute(arguments, signature)?
|
FunctionSignature::from_arguments_and_attribute(arguments, signature)?
|
||||||
} else if let Some(deprecated_args) = deprecated_args {
|
|
||||||
FunctionSignature::from_arguments_and_deprecated_args(arguments, deprecated_args)?
|
|
||||||
} else {
|
} else {
|
||||||
FunctionSignature::from_arguments(arguments, &mut deprecations)
|
FunctionSignature::from_arguments(arguments)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let convention =
|
let convention =
|
||||||
|
@ -335,7 +325,6 @@ impl<'a> FnSpec<'a> {
|
||||||
python_name,
|
python_name,
|
||||||
signature,
|
signature,
|
||||||
output: ty,
|
output: ty,
|
||||||
deprecations,
|
|
||||||
text_signature,
|
text_signature,
|
||||||
unsafety: sig.unsafety,
|
unsafety: sig.unsafety,
|
||||||
})
|
})
|
||||||
|
@ -423,7 +412,6 @@ impl<'a> FnSpec<'a> {
|
||||||
ident: &proc_macro2::Ident,
|
ident: &proc_macro2::Ident,
|
||||||
cls: Option<&syn::Type>,
|
cls: Option<&syn::Type>,
|
||||||
) -> Result<TokenStream> {
|
) -> Result<TokenStream> {
|
||||||
let deprecations = &self.deprecations;
|
|
||||||
let self_conversion = self.tp.self_conversion(cls, ExtractErrorMode::Raise);
|
let self_conversion = self.tp.self_conversion(cls, ExtractErrorMode::Raise);
|
||||||
let self_arg = self.tp.self_arg();
|
let self_arg = self.tp.self_arg();
|
||||||
let py = syn::Ident::new("_py", Span::call_site());
|
let py = syn::Ident::new("_py", Span::call_site());
|
||||||
|
@ -457,7 +445,6 @@ impl<'a> FnSpec<'a> {
|
||||||
_slf: *mut _pyo3::ffi::PyObject,
|
_slf: *mut _pyo3::ffi::PyObject,
|
||||||
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> {
|
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> {
|
||||||
let function = #rust_name; // Shadow the function name to avoid #3017
|
let function = #rust_name; // Shadow the function name to avoid #3017
|
||||||
#deprecations
|
|
||||||
#self_conversion
|
#self_conversion
|
||||||
#call
|
#call
|
||||||
}
|
}
|
||||||
|
@ -475,7 +462,6 @@ impl<'a> FnSpec<'a> {
|
||||||
_kwnames: *mut _pyo3::ffi::PyObject
|
_kwnames: *mut _pyo3::ffi::PyObject
|
||||||
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> {
|
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> {
|
||||||
let function = #rust_name; // Shadow the function name to avoid #3017
|
let function = #rust_name; // Shadow the function name to avoid #3017
|
||||||
#deprecations
|
|
||||||
#self_conversion
|
#self_conversion
|
||||||
#arg_convert
|
#arg_convert
|
||||||
#call
|
#call
|
||||||
|
@ -493,7 +479,6 @@ impl<'a> FnSpec<'a> {
|
||||||
_kwargs: *mut _pyo3::ffi::PyObject
|
_kwargs: *mut _pyo3::ffi::PyObject
|
||||||
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> {
|
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> {
|
||||||
let function = #rust_name; // Shadow the function name to avoid #3017
|
let function = #rust_name; // Shadow the function name to avoid #3017
|
||||||
#deprecations
|
|
||||||
#self_conversion
|
#self_conversion
|
||||||
#arg_convert
|
#arg_convert
|
||||||
#call
|
#call
|
||||||
|
@ -518,7 +503,6 @@ impl<'a> FnSpec<'a> {
|
||||||
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> {
|
) -> _pyo3::PyResult<*mut _pyo3::ffi::PyObject> {
|
||||||
use _pyo3::callback::IntoPyCallbackOutput;
|
use _pyo3::callback::IntoPyCallbackOutput;
|
||||||
let function = #rust_name; // Shadow the function name to avoid #3017
|
let function = #rust_name; // Shadow the function name to avoid #3017
|
||||||
#deprecations
|
|
||||||
#arg_convert
|
#arg_convert
|
||||||
let result = #call;
|
let result = #call;
|
||||||
let initializer: _pyo3::PyClassInitializer::<#cls> = result.convert(#py)?;
|
let initializer: _pyo3::PyClassInitializer::<#cls> = result.convert(#py)?;
|
||||||
|
@ -636,17 +620,14 @@ impl<'a> FnSpec<'a> {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct MethodAttributes {
|
struct MethodAttributes {
|
||||||
ty: Option<MethodTypeAttribute>,
|
ty: Option<MethodTypeAttribute>,
|
||||||
deprecated_args: Option<DeprecatedArgs>,
|
|
||||||
python_name: Option<syn::Ident>,
|
python_name: Option<syn::Ident>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_method_attributes(
|
fn parse_method_attributes(
|
||||||
attrs: &mut Vec<syn::Attribute>,
|
attrs: &mut Vec<syn::Attribute>,
|
||||||
mut python_name: Option<syn::Ident>,
|
mut python_name: Option<syn::Ident>,
|
||||||
deprecations: &mut Deprecations,
|
|
||||||
) -> Result<MethodAttributes> {
|
) -> Result<MethodAttributes> {
|
||||||
let mut new_attrs = Vec::new();
|
let mut new_attrs = Vec::new();
|
||||||
let mut deprecated_args = None;
|
|
||||||
let mut ty: Option<MethodTypeAttribute> = None;
|
let mut ty: Option<MethodTypeAttribute> = None;
|
||||||
|
|
||||||
macro_rules! set_compound_ty {
|
macro_rules! set_compound_ty {
|
||||||
|
@ -754,13 +735,6 @@ fn parse_method_attributes(
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else if path.is_ident("args") {
|
|
||||||
ensure_spanned!(
|
|
||||||
deprecated_args.is_none(),
|
|
||||||
nested.span() => "args may only be specified once"
|
|
||||||
);
|
|
||||||
deprecations.push(Deprecation::PyMethodArgsAttribute, path.span());
|
|
||||||
deprecated_args = Some(DeprecatedArgs::from_meta(&nested)?);
|
|
||||||
} else {
|
} else {
|
||||||
new_attrs.push(attr)
|
new_attrs.push(attr)
|
||||||
}
|
}
|
||||||
|
@ -771,11 +745,7 @@ fn parse_method_attributes(
|
||||||
|
|
||||||
*attrs = new_attrs;
|
*attrs = new_attrs;
|
||||||
|
|
||||||
Ok(MethodAttributes {
|
Ok(MethodAttributes { ty, python_name })
|
||||||
ty,
|
|
||||||
deprecated_args,
|
|
||||||
python_name,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const IMPL_TRAIT_ERR: &str = "Python functions cannot have `impl Trait` arguments";
|
const IMPL_TRAIT_ERR: &str = "Python functions cannot have `impl Trait` arguments";
|
||||||
|
|
|
@ -3,19 +3,17 @@ use crate::{
|
||||||
self, get_pyo3_options, take_attributes, take_pyo3_options, CrateAttribute,
|
self, get_pyo3_options, take_attributes, take_pyo3_options, CrateAttribute,
|
||||||
FromPyWithAttribute, NameAttribute, TextSignatureAttribute,
|
FromPyWithAttribute, NameAttribute, TextSignatureAttribute,
|
||||||
},
|
},
|
||||||
deprecations::{Deprecation, Deprecations},
|
|
||||||
method::{self, CallingConvention, FnArg},
|
method::{self, CallingConvention, FnArg},
|
||||||
pymethod::check_generic,
|
pymethod::check_generic,
|
||||||
utils::{ensure_not_async_fn, get_pyo3_crate},
|
utils::{ensure_not_async_fn, get_pyo3_crate},
|
||||||
};
|
};
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
use syn::{ext::IdentExt, spanned::Spanned, NestedMeta, Result};
|
use syn::{ext::IdentExt, spanned::Spanned, Result};
|
||||||
use syn::{
|
use syn::{
|
||||||
parse::{Parse, ParseBuffer, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
token::Comma,
|
token::Comma,
|
||||||
};
|
};
|
||||||
use syn::{punctuated::Punctuated, Path};
|
|
||||||
|
|
||||||
mod signature;
|
mod signature;
|
||||||
|
|
||||||
|
@ -67,181 +65,12 @@ impl PyFunctionArgPyO3Attributes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub enum Argument {
|
|
||||||
PosOnlyArgsSeparator,
|
|
||||||
VarArgsSeparator,
|
|
||||||
VarArgs(syn::Path),
|
|
||||||
KeywordArgs(syn::Path),
|
|
||||||
PosOnlyArg(syn::Path, Option<String>),
|
|
||||||
Arg(syn::Path, Option<String>),
|
|
||||||
Kwarg(syn::Path, Option<String>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
pub struct DeprecatedArgs {
|
|
||||||
pub arguments: Vec<Argument>,
|
|
||||||
has_kw: bool,
|
|
||||||
has_posonly_args: bool,
|
|
||||||
has_varargs: bool,
|
|
||||||
has_kwargs: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated parsing mode for the signature
|
|
||||||
impl syn::parse::Parse for DeprecatedArgs {
|
|
||||||
fn parse(input: &ParseBuffer<'_>) -> syn::Result<Self> {
|
|
||||||
let attr = Punctuated::<NestedMeta, syn::Token![,]>::parse_terminated(input)?;
|
|
||||||
Self::from_meta(&attr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DeprecatedArgs {
|
|
||||||
pub fn from_meta<'a>(iter: impl IntoIterator<Item = &'a NestedMeta>) -> syn::Result<Self> {
|
|
||||||
let mut slf = DeprecatedArgs::default();
|
|
||||||
|
|
||||||
for item in iter {
|
|
||||||
slf.add_item(item)?
|
|
||||||
}
|
|
||||||
Ok(slf)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_item(&mut self, item: &NestedMeta) -> syn::Result<()> {
|
|
||||||
match item {
|
|
||||||
NestedMeta::Meta(syn::Meta::Path(ident)) => self.add_work(item, ident)?,
|
|
||||||
NestedMeta::Meta(syn::Meta::NameValue(nv)) => {
|
|
||||||
self.add_name_value(item, nv)?;
|
|
||||||
}
|
|
||||||
NestedMeta::Lit(lit) => {
|
|
||||||
self.add_literal(item, lit)?;
|
|
||||||
}
|
|
||||||
NestedMeta::Meta(syn::Meta::List(list)) => bail_spanned!(
|
|
||||||
list.span() => "list is not supported as argument"
|
|
||||||
),
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_literal(&mut self, item: &NestedMeta, lit: &syn::Lit) -> syn::Result<()> {
|
|
||||||
match lit {
|
|
||||||
syn::Lit::Str(lits) if lits.value() == "*" => {
|
|
||||||
// "*"
|
|
||||||
self.vararg_is_ok(item)?;
|
|
||||||
self.has_varargs = true;
|
|
||||||
self.arguments.push(Argument::VarArgsSeparator);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
syn::Lit::Str(lits) if lits.value() == "/" => {
|
|
||||||
// "/"
|
|
||||||
self.posonly_arg_is_ok(item)?;
|
|
||||||
self.has_posonly_args = true;
|
|
||||||
// any arguments _before_ this become positional-only
|
|
||||||
self.arguments.iter_mut().for_each(|a| {
|
|
||||||
if let Argument::Arg(path, name) = a {
|
|
||||||
*a = Argument::PosOnlyArg(path.clone(), name.clone());
|
|
||||||
} else {
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
self.arguments.push(Argument::PosOnlyArgsSeparator);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
_ => bail_spanned!(item.span() => "expected \"/\" or \"*\""),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_work(&mut self, item: &NestedMeta, path: &Path) -> syn::Result<()> {
|
|
||||||
ensure_spanned!(
|
|
||||||
!(self.has_kw || self.has_kwargs),
|
|
||||||
item.span() => "positional argument or varargs(*) not allowed after keyword arguments"
|
|
||||||
);
|
|
||||||
if self.has_varargs {
|
|
||||||
self.arguments.push(Argument::Kwarg(path.clone(), None));
|
|
||||||
} else {
|
|
||||||
self.arguments.push(Argument::Arg(path.clone(), None));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn posonly_arg_is_ok(&self, item: &NestedMeta) -> syn::Result<()> {
|
|
||||||
ensure_spanned!(
|
|
||||||
!(self.has_posonly_args || self.has_kwargs || self.has_varargs),
|
|
||||||
item.span() => "/ is not allowed after /, varargs(*), or kwargs(**)"
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vararg_is_ok(&self, item: &NestedMeta) -> syn::Result<()> {
|
|
||||||
ensure_spanned!(
|
|
||||||
!(self.has_kwargs || self.has_varargs),
|
|
||||||
item.span() => "* is not allowed after varargs(*) or kwargs(**)"
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn kw_arg_is_ok(&self, item: &NestedMeta) -> syn::Result<()> {
|
|
||||||
ensure_spanned!(
|
|
||||||
!self.has_kwargs,
|
|
||||||
item.span() => "keyword argument or kwargs(**) is not allowed after kwargs(**)"
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_nv_common(
|
|
||||||
&mut self,
|
|
||||||
item: &NestedMeta,
|
|
||||||
name: &syn::Path,
|
|
||||||
value: String,
|
|
||||||
) -> syn::Result<()> {
|
|
||||||
self.kw_arg_is_ok(item)?;
|
|
||||||
if self.has_varargs {
|
|
||||||
// kw only
|
|
||||||
self.arguments
|
|
||||||
.push(Argument::Kwarg(name.clone(), Some(value)));
|
|
||||||
} else {
|
|
||||||
self.has_kw = true;
|
|
||||||
self.arguments
|
|
||||||
.push(Argument::Arg(name.clone(), Some(value)));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_name_value(&mut self, item: &NestedMeta, nv: &syn::MetaNameValue) -> syn::Result<()> {
|
|
||||||
match &nv.lit {
|
|
||||||
syn::Lit::Str(litstr) => {
|
|
||||||
if litstr.value() == "*" {
|
|
||||||
// args="*"
|
|
||||||
self.vararg_is_ok(item)?;
|
|
||||||
self.has_varargs = true;
|
|
||||||
self.arguments.push(Argument::VarArgs(nv.path.clone()));
|
|
||||||
} else if litstr.value() == "**" {
|
|
||||||
// kwargs="**"
|
|
||||||
self.kw_arg_is_ok(item)?;
|
|
||||||
self.has_kwargs = true;
|
|
||||||
self.arguments.push(Argument::KeywordArgs(nv.path.clone()));
|
|
||||||
} else {
|
|
||||||
self.add_nv_common(item, &nv.path, litstr.value())?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
syn::Lit::Int(litint) => {
|
|
||||||
self.add_nv_common(item, &nv.path, format!("{}", litint))?;
|
|
||||||
}
|
|
||||||
syn::Lit::Bool(litb) => {
|
|
||||||
self.add_nv_common(item, &nv.path, format!("{}", litb.value))?;
|
|
||||||
}
|
|
||||||
_ => bail_spanned!(nv.lit.span() => "expected a string literal"),
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct PyFunctionOptions {
|
pub struct PyFunctionOptions {
|
||||||
pub pass_module: Option<attributes::kw::pass_module>,
|
pub pass_module: Option<attributes::kw::pass_module>,
|
||||||
pub name: Option<NameAttribute>,
|
pub name: Option<NameAttribute>,
|
||||||
pub deprecated_args: Option<DeprecatedArgs>,
|
|
||||||
pub signature: Option<SignatureAttribute>,
|
pub signature: Option<SignatureAttribute>,
|
||||||
pub text_signature: Option<TextSignatureAttribute>,
|
pub text_signature: Option<TextSignatureAttribute>,
|
||||||
pub deprecations: Deprecations,
|
|
||||||
pub krate: Option<CrateAttribute>,
|
pub krate: Option<CrateAttribute>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,12 +93,7 @@ impl Parse for PyFunctionOptions {
|
||||||
// TODO needs duplicate check?
|
// TODO needs duplicate check?
|
||||||
options.krate = Some(input.parse()?);
|
options.krate = Some(input.parse()?);
|
||||||
} else {
|
} else {
|
||||||
// If not recognised attribute, this is "legacy" pyfunction syntax #[pyfunction(a, b)]
|
return Err(lookahead.error());
|
||||||
options
|
|
||||||
.deprecations
|
|
||||||
.push(Deprecation::PyFunctionArguments, input.span());
|
|
||||||
options.deprecated_args = Some(input.parse()?);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,10 +183,8 @@ pub fn impl_wrap_pyfunction(
|
||||||
let PyFunctionOptions {
|
let PyFunctionOptions {
|
||||||
pass_module,
|
pass_module,
|
||||||
name,
|
name,
|
||||||
deprecated_args,
|
|
||||||
signature,
|
signature,
|
||||||
text_signature,
|
text_signature,
|
||||||
mut deprecations,
|
|
||||||
krate,
|
krate,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
|
@ -392,15 +214,9 @@ pub fn impl_wrap_pyfunction(
|
||||||
};
|
};
|
||||||
|
|
||||||
let signature = if let Some(signature) = signature {
|
let signature = if let Some(signature) = signature {
|
||||||
ensure_spanned!(
|
|
||||||
deprecated_args.is_none(),
|
|
||||||
signature.kw.span() => "cannot define both function signature and legacy arguments"
|
|
||||||
);
|
|
||||||
FunctionSignature::from_arguments_and_attribute(arguments, signature)?
|
FunctionSignature::from_arguments_and_attribute(arguments, signature)?
|
||||||
} else if let Some(deprecated_args) = deprecated_args {
|
|
||||||
FunctionSignature::from_arguments_and_deprecated_args(arguments, deprecated_args)?
|
|
||||||
} else {
|
} else {
|
||||||
FunctionSignature::from_arguments(arguments, &mut deprecations)
|
FunctionSignature::from_arguments(arguments)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let ty = method::get_return_info(&func.sig.output);
|
let ty = method::get_return_info(&func.sig.output);
|
||||||
|
@ -412,7 +228,6 @@ pub fn impl_wrap_pyfunction(
|
||||||
python_name,
|
python_name,
|
||||||
signature,
|
signature,
|
||||||
output: ty,
|
output: ty,
|
||||||
deprecations,
|
|
||||||
text_signature,
|
text_signature,
|
||||||
unsafety: func.sig.unsafety,
|
unsafety: func.sig.unsafety,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use std::cmp::max;
|
|
||||||
|
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
use syn::{
|
use syn::{
|
||||||
|
@ -12,13 +10,9 @@ use syn::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
attributes::{kw, KeywordAttribute},
|
attributes::{kw, KeywordAttribute},
|
||||||
deprecations::{Deprecation, Deprecations},
|
|
||||||
method::FnArg,
|
method::FnArg,
|
||||||
pyfunction::Argument,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::DeprecatedArgs;
|
|
||||||
|
|
||||||
pub struct Signature {
|
pub struct Signature {
|
||||||
paren_token: syn::token::Paren,
|
paren_token: syn::token::Paren,
|
||||||
pub items: Punctuated<SignatureItem, Token![,]>,
|
pub items: Punctuated<SignatureItem, Token![,]>,
|
||||||
|
@ -430,121 +424,8 @@ impl<'a> FunctionSignature<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The difference to `from_arguments_and_signature` is that deprecated args allowed entries to be:
|
|
||||||
/// - missing
|
|
||||||
/// - out of order
|
|
||||||
pub fn from_arguments_and_deprecated_args(
|
|
||||||
mut arguments: Vec<FnArg<'a>>,
|
|
||||||
deprecated_args: DeprecatedArgs,
|
|
||||||
) -> syn::Result<Self> {
|
|
||||||
let mut varargs = None;
|
|
||||||
let mut kwargs = None;
|
|
||||||
let mut keyword_only_parameters = Vec::new();
|
|
||||||
|
|
||||||
fn first_n_argument_names(arguments: &[FnArg<'_>], count: usize) -> Vec<String> {
|
|
||||||
arguments
|
|
||||||
.iter()
|
|
||||||
.filter_map(|fn_arg| {
|
|
||||||
if fn_arg.py {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(fn_arg.name.unraw().to_string())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.take(count)
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Record highest counts observed based off argument positions
|
|
||||||
let mut positional_only_arguments_count = None;
|
|
||||||
let mut positional_arguments_count = None;
|
|
||||||
let mut required_positional_parameters = 0;
|
|
||||||
|
|
||||||
let args_iter = arguments.iter_mut().filter(|arg| !arg.py); // Python<'_> arguments don't show on the Python side.
|
|
||||||
|
|
||||||
for (i, fn_arg) in args_iter.enumerate() {
|
|
||||||
if let Some(argument) = deprecated_args
|
|
||||||
.arguments
|
|
||||||
.iter()
|
|
||||||
.find(|argument| match argument {
|
|
||||||
Argument::PosOnlyArg(path, _)
|
|
||||||
| Argument::Arg(path, _)
|
|
||||||
| Argument::Kwarg(path, _)
|
|
||||||
| Argument::VarArgs(path)
|
|
||||||
| Argument::KeywordArgs(path) => path.get_ident() == Some(fn_arg.name),
|
|
||||||
_ => false,
|
|
||||||
})
|
|
||||||
{
|
|
||||||
match argument {
|
|
||||||
Argument::PosOnlyArg(_, default) | Argument::Arg(_, default) => {
|
|
||||||
if let Some(default) = default {
|
|
||||||
fn_arg.default = Some(syn::parse_str(default)?);
|
|
||||||
} else if fn_arg.optional.is_none() {
|
|
||||||
// Option<_> arguments always have an implicit None default with the old
|
|
||||||
// `#[args]`
|
|
||||||
required_positional_parameters = i + 1;
|
|
||||||
}
|
|
||||||
if matches!(argument, Argument::PosOnlyArg(_, _)) {
|
|
||||||
positional_only_arguments_count = Some(i + 1);
|
|
||||||
}
|
|
||||||
positional_arguments_count = Some(i + 1);
|
|
||||||
}
|
|
||||||
Argument::Kwarg(_, default) => {
|
|
||||||
fn_arg.default = default.as_deref().map(syn::parse_str).transpose()?;
|
|
||||||
keyword_only_parameters.push((fn_arg.name.to_string(), default.is_none()));
|
|
||||||
}
|
|
||||||
Argument::PosOnlyArgsSeparator => {}
|
|
||||||
Argument::VarArgsSeparator => {}
|
|
||||||
Argument::VarArgs(path) => {
|
|
||||||
fn_arg.is_varargs = true;
|
|
||||||
if let Some(ident) = path.get_ident() {
|
|
||||||
varargs = Some(ident.to_string());
|
|
||||||
} else {
|
|
||||||
bail_spanned!(path.span() => "expected ident for *args");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Argument::KeywordArgs(path) => {
|
|
||||||
fn_arg.is_kwargs = true;
|
|
||||||
if let Some(ident) = path.get_ident() {
|
|
||||||
kwargs = Some(ident.to_string());
|
|
||||||
} else {
|
|
||||||
bail_spanned!(path.span() => "expected ident for **kwargs");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Assume this is a required positional parameter
|
|
||||||
required_positional_parameters = i + 1;
|
|
||||||
positional_arguments_count = Some(i + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fix up state based on observations above
|
|
||||||
let positional_only_parameters = positional_only_arguments_count.unwrap_or(0);
|
|
||||||
let positional_parameters = first_n_argument_names(
|
|
||||||
&arguments,
|
|
||||||
max(
|
|
||||||
positional_arguments_count.unwrap_or(0),
|
|
||||||
positional_only_arguments_count.unwrap_or(0),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(FunctionSignature {
|
|
||||||
arguments,
|
|
||||||
python_signature: PythonSignature {
|
|
||||||
positional_parameters,
|
|
||||||
positional_only_parameters,
|
|
||||||
required_positional_parameters,
|
|
||||||
varargs,
|
|
||||||
keyword_only_parameters,
|
|
||||||
kwargs,
|
|
||||||
},
|
|
||||||
attribute: None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Without `#[pyo3(signature)]` or `#[args]` - just take the Rust function arguments as positional.
|
/// Without `#[pyo3(signature)]` or `#[args]` - just take the Rust function arguments as positional.
|
||||||
pub fn from_arguments(mut arguments: Vec<FnArg<'a>>, deprecations: &mut Deprecations) -> Self {
|
pub fn from_arguments(arguments: Vec<FnArg<'a>>) -> syn::Result<Self> {
|
||||||
let mut python_signature = PythonSignature::default();
|
let mut python_signature = PythonSignature::default();
|
||||||
for arg in &arguments {
|
for arg in &arguments {
|
||||||
// Python<'_> arguments don't show in Python signature
|
// Python<'_> arguments don't show in Python signature
|
||||||
|
@ -553,13 +434,12 @@ impl<'a> FunctionSignature<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if arg.optional.is_none() {
|
if arg.optional.is_none() {
|
||||||
// This argument is required
|
// This argument is required, all previous arguments must also have been required
|
||||||
if python_signature.required_positional_parameters
|
ensure_spanned!(
|
||||||
!= python_signature.positional_parameters.len()
|
python_signature.required_positional_parameters == python_signature.positional_parameters.len(),
|
||||||
{
|
arg.ty.span() => "required arguments after an `Option<_>` argument are ambiguous\n\
|
||||||
// A previous argument was not required
|
= help: add a `#[pyo3(signature)]` annotation on this function to unambiguously specify the default values for all optional parameters"
|
||||||
deprecations.push(Deprecation::RequiredArgumentAfterOption, arg.name.span());
|
);
|
||||||
}
|
|
||||||
|
|
||||||
python_signature.required_positional_parameters =
|
python_signature.required_positional_parameters =
|
||||||
python_signature.positional_parameters.len() + 1;
|
python_signature.positional_parameters.len() + 1;
|
||||||
|
@ -570,20 +450,11 @@ impl<'a> FunctionSignature<'a> {
|
||||||
.push(arg.name.unraw().to_string());
|
.push(arg.name.unraw().to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fixup any `Option<_>` arguments that were made implicitly made required by the deprecated
|
Ok(Self {
|
||||||
// branch above
|
|
||||||
for arg in arguments
|
|
||||||
.iter_mut()
|
|
||||||
.take(python_signature.required_positional_parameters)
|
|
||||||
{
|
|
||||||
arg.optional = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Self {
|
|
||||||
arguments,
|
arguments,
|
||||||
python_signature,
|
python_signature,
|
||||||
attribute: None,
|
attribute: None,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_value_for_parameter(&self, parameter: &str) -> String {
|
fn default_value_for_parameter(&self, parameter: &str) -> String {
|
||||||
|
|
|
@ -2,8 +2,8 @@ use std::borrow::Cow;
|
||||||
|
|
||||||
use crate::attributes::NameAttribute;
|
use crate::attributes::NameAttribute;
|
||||||
use crate::method::{CallingConvention, ExtractErrorMode};
|
use crate::method::{CallingConvention, ExtractErrorMode};
|
||||||
|
use crate::utils;
|
||||||
use crate::utils::{ensure_not_async_fn, PythonDoc};
|
use crate::utils::{ensure_not_async_fn, PythonDoc};
|
||||||
use crate::{deprecations::Deprecations, utils};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
method::{FnArg, FnSpec, FnType, SelfType},
|
method::{FnArg, FnSpec, FnType, SelfType},
|
||||||
pyfunction::PyFunctionOptions,
|
pyfunction::PyFunctionOptions,
|
||||||
|
@ -441,13 +441,11 @@ fn impl_py_class_attribute(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Result<Me
|
||||||
};
|
};
|
||||||
|
|
||||||
let wrapper_ident = format_ident!("__pymethod_{}__", name);
|
let wrapper_ident = format_ident!("__pymethod_{}__", name);
|
||||||
let deprecations = &spec.deprecations;
|
|
||||||
let python_name = spec.null_terminated_python_name();
|
let python_name = spec.null_terminated_python_name();
|
||||||
|
|
||||||
let associated_method = quote! {
|
let associated_method = quote! {
|
||||||
fn #wrapper_ident(py: _pyo3::Python<'_>) -> _pyo3::PyResult<_pyo3::PyObject> {
|
fn #wrapper_ident(py: _pyo3::Python<'_>) -> _pyo3::PyResult<_pyo3::PyObject> {
|
||||||
let function = #cls::#name; // Shadow the method name to avoid #3017
|
let function = #cls::#name; // Shadow the method name to avoid #3017
|
||||||
#deprecations
|
|
||||||
_pyo3::impl_::pymethods::OkWrap::wrap(#fncall, py)
|
_pyo3::impl_::pymethods::OkWrap::wrap(#fncall, py)
|
||||||
.map_err(::core::convert::Into::into)
|
.map_err(::core::convert::Into::into)
|
||||||
}
|
}
|
||||||
|
@ -496,7 +494,6 @@ pub fn impl_py_setter_def(
|
||||||
property_type: PropertyType<'_>,
|
property_type: PropertyType<'_>,
|
||||||
) -> Result<MethodAndMethodDef> {
|
) -> Result<MethodAndMethodDef> {
|
||||||
let python_name = property_type.null_terminated_python_name()?;
|
let python_name = property_type.null_terminated_python_name()?;
|
||||||
let deprecations = property_type.deprecations();
|
|
||||||
let doc = property_type.doc();
|
let doc = property_type.doc();
|
||||||
let setter_impl = match property_type {
|
let setter_impl = match property_type {
|
||||||
PropertyType::Descriptor {
|
PropertyType::Descriptor {
|
||||||
|
@ -570,14 +567,13 @@ pub fn impl_py_setter_def(
|
||||||
|
|
||||||
let method_def = quote! {
|
let method_def = quote! {
|
||||||
#cfg_attrs
|
#cfg_attrs
|
||||||
_pyo3::class::PyMethodDefType::Setter({
|
_pyo3::class::PyMethodDefType::Setter(
|
||||||
#deprecations
|
|
||||||
_pyo3::class::PySetterDef::new(
|
_pyo3::class::PySetterDef::new(
|
||||||
#python_name,
|
#python_name,
|
||||||
_pyo3::impl_::pymethods::PySetter(#cls::#wrapper_ident),
|
_pyo3::impl_::pymethods::PySetter(#cls::#wrapper_ident),
|
||||||
#doc
|
#doc
|
||||||
)
|
)
|
||||||
})
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(MethodAndMethodDef {
|
Ok(MethodAndMethodDef {
|
||||||
|
@ -609,7 +605,6 @@ pub fn impl_py_getter_def(
|
||||||
property_type: PropertyType<'_>,
|
property_type: PropertyType<'_>,
|
||||||
) -> Result<MethodAndMethodDef> {
|
) -> Result<MethodAndMethodDef> {
|
||||||
let python_name = property_type.null_terminated_python_name()?;
|
let python_name = property_type.null_terminated_python_name()?;
|
||||||
let deprecations = property_type.deprecations();
|
|
||||||
let doc = property_type.doc();
|
let doc = property_type.doc();
|
||||||
let getter_impl = match property_type {
|
let getter_impl = match property_type {
|
||||||
PropertyType::Descriptor {
|
PropertyType::Descriptor {
|
||||||
|
@ -691,14 +686,13 @@ pub fn impl_py_getter_def(
|
||||||
|
|
||||||
let method_def = quote! {
|
let method_def = quote! {
|
||||||
#cfg_attrs
|
#cfg_attrs
|
||||||
_pyo3::class::PyMethodDefType::Getter({
|
_pyo3::class::PyMethodDefType::Getter(
|
||||||
#deprecations
|
|
||||||
_pyo3::class::PyGetterDef::new(
|
_pyo3::class::PyGetterDef::new(
|
||||||
#python_name,
|
#python_name,
|
||||||
_pyo3::impl_::pymethods::PyGetter(#cls::#wrapper_ident),
|
_pyo3::impl_::pymethods::PyGetter(#cls::#wrapper_ident),
|
||||||
#doc
|
#doc
|
||||||
)
|
)
|
||||||
})
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(MethodAndMethodDef {
|
Ok(MethodAndMethodDef {
|
||||||
|
@ -747,13 +741,6 @@ impl PropertyType<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deprecations(&self) -> Option<&Deprecations> {
|
|
||||||
match self {
|
|
||||||
PropertyType::Descriptor { .. } => None,
|
|
||||||
PropertyType::Function { spec, .. } => Some(&spec.deprecations),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn doc(&self) -> Cow<'_, PythonDoc> {
|
fn doc(&self) -> Cow<'_, PythonDoc> {
|
||||||
match self {
|
match self {
|
||||||
PropertyType::Descriptor { field, .. } => {
|
PropertyType::Descriptor { field, .. } => {
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
#![allow(deprecated)]
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
|
||||||
use pyo3::types::{PyDict, PyTuple};
|
|
||||||
|
|
||||||
#[pyfunction]
|
|
||||||
fn none() {}
|
|
||||||
|
|
||||||
#[pyfunction(b = "\"bar\"", "*", c = "None")]
|
|
||||||
fn simple<'a>(a: i32, b: &'a str, c: Option<&'a PyDict>) -> (i32, &'a str, Option<&'a PyDict>) {
|
|
||||||
(a, b, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pyfunction(b = "\"bar\"", args = "*", c = "None")]
|
|
||||||
fn simple_args<'a>(
|
|
||||||
a: i32,
|
|
||||||
b: &'a str,
|
|
||||||
c: Option<&'a PyDict>,
|
|
||||||
args: &'a PyTuple,
|
|
||||||
) -> (i32, &'a str, &'a PyTuple, Option<&'a PyDict>) {
|
|
||||||
(a, b, args, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pyfunction(b = "\"bar\"", c = "None", kwargs = "**")]
|
|
||||||
fn simple_kwargs<'a>(
|
|
||||||
a: i32,
|
|
||||||
b: &'a str,
|
|
||||||
c: Option<&'a PyDict>,
|
|
||||||
kwargs: Option<&'a PyDict>,
|
|
||||||
) -> (i32, &'a str, Option<&'a PyDict>, Option<&'a PyDict>) {
|
|
||||||
(a, b, c, kwargs)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pyfunction(a, b = "\"bar\"", args = "*", c = "None", kwargs = "**")]
|
|
||||||
fn simple_args_kwargs<'a>(
|
|
||||||
a: i32,
|
|
||||||
b: &'a str,
|
|
||||||
args: &'a PyTuple,
|
|
||||||
c: Option<&'a PyDict>,
|
|
||||||
kwargs: Option<&'a PyDict>,
|
|
||||||
) -> (
|
|
||||||
i32,
|
|
||||||
&'a str,
|
|
||||||
&'a PyTuple,
|
|
||||||
Option<&'a PyDict>,
|
|
||||||
Option<&'a PyDict>,
|
|
||||||
) {
|
|
||||||
(a, b, args, c, kwargs)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pyfunction(args = "*", kwargs = "**")]
|
|
||||||
fn args_kwargs<'a>(
|
|
||||||
args: &'a PyTuple,
|
|
||||||
kwargs: Option<&'a PyDict>,
|
|
||||||
) -> (&'a PyTuple, Option<&'a PyDict>) {
|
|
||||||
(args, kwargs)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pymodule]
|
|
||||||
pub fn deprecated_pyfunctions(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
|
||||||
m.add_function(wrap_pyfunction!(none, m)?)?;
|
|
||||||
m.add_function(wrap_pyfunction!(simple, m)?)?;
|
|
||||||
m.add_function(wrap_pyfunction!(simple_args, m)?)?;
|
|
||||||
m.add_function(wrap_pyfunction!(simple_kwargs, m)?)?;
|
|
||||||
m.add_function(wrap_pyfunction!(simple_args_kwargs, m)?)?;
|
|
||||||
m.add_function(wrap_pyfunction!(args_kwargs, m)?)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -5,7 +5,6 @@ use pyo3::wrap_pymodule;
|
||||||
pub mod buf_and_str;
|
pub mod buf_and_str;
|
||||||
pub mod comparisons;
|
pub mod comparisons;
|
||||||
pub mod datetime;
|
pub mod datetime;
|
||||||
pub mod deprecated_pyfunctions;
|
|
||||||
pub mod dict_iter;
|
pub mod dict_iter;
|
||||||
pub mod misc;
|
pub mod misc;
|
||||||
pub mod objstore;
|
pub mod objstore;
|
||||||
|
@ -23,9 +22,6 @@ fn pyo3_pytests(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||||
m.add_wrapped(wrap_pymodule!(comparisons::comparisons))?;
|
m.add_wrapped(wrap_pymodule!(comparisons::comparisons))?;
|
||||||
#[cfg(not(Py_LIMITED_API))]
|
#[cfg(not(Py_LIMITED_API))]
|
||||||
m.add_wrapped(wrap_pymodule!(datetime::datetime))?;
|
m.add_wrapped(wrap_pymodule!(datetime::datetime))?;
|
||||||
m.add_wrapped(wrap_pymodule!(
|
|
||||||
deprecated_pyfunctions::deprecated_pyfunctions
|
|
||||||
))?;
|
|
||||||
m.add_wrapped(wrap_pymodule!(dict_iter::dict_iter))?;
|
m.add_wrapped(wrap_pymodule!(dict_iter::dict_iter))?;
|
||||||
m.add_wrapped(wrap_pymodule!(misc::misc))?;
|
m.add_wrapped(wrap_pymodule!(misc::misc))?;
|
||||||
m.add_wrapped(wrap_pymodule!(objstore::objstore))?;
|
m.add_wrapped(wrap_pymodule!(objstore::objstore))?;
|
||||||
|
@ -44,10 +40,6 @@ fn pyo3_pytests(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||||
sys_modules.set_item("pyo3_pytests.buf_and_str", m.getattr("buf_and_str")?)?;
|
sys_modules.set_item("pyo3_pytests.buf_and_str", m.getattr("buf_and_str")?)?;
|
||||||
sys_modules.set_item("pyo3_pytests.comparisons", m.getattr("comparisons")?)?;
|
sys_modules.set_item("pyo3_pytests.comparisons", m.getattr("comparisons")?)?;
|
||||||
sys_modules.set_item("pyo3_pytests.datetime", m.getattr("datetime")?)?;
|
sys_modules.set_item("pyo3_pytests.datetime", m.getattr("datetime")?)?;
|
||||||
sys_modules.set_item(
|
|
||||||
"pyo3_pytests.deprecated_pyfunctions",
|
|
||||||
m.getattr("deprecated_pyfunctions")?,
|
|
||||||
)?;
|
|
||||||
sys_modules.set_item("pyo3_pytests.dict_iter", m.getattr("dict_iter")?)?;
|
sys_modules.set_item("pyo3_pytests.dict_iter", m.getattr("dict_iter")?)?;
|
||||||
sys_modules.set_item("pyo3_pytests.misc", m.getattr("misc")?)?;
|
sys_modules.set_item("pyo3_pytests.misc", m.getattr("misc")?)?;
|
||||||
sys_modules.set_item("pyo3_pytests.objstore", m.getattr("objstore")?)?;
|
sys_modules.set_item("pyo3_pytests.objstore", m.getattr("objstore")?)?;
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
from pyo3_pytests import deprecated_pyfunctions as pyfunctions
|
|
||||||
|
|
||||||
|
|
||||||
def none_py():
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def test_none_rs():
|
|
||||||
rust = pyfunctions.none()
|
|
||||||
py = none_py()
|
|
||||||
assert rust == py
|
|
||||||
|
|
||||||
|
|
||||||
def simple_py(a, b="bar", *, c=None):
|
|
||||||
return a, b, c
|
|
||||||
|
|
||||||
|
|
||||||
def test_simple_rs():
|
|
||||||
rust = pyfunctions.simple(1, "foo", c={1: 2})
|
|
||||||
py = simple_py(1, "foo", c={1: 2})
|
|
||||||
assert rust == py
|
|
||||||
|
|
||||||
|
|
||||||
def simple_args_py(a, b="bar", *args, c=None):
|
|
||||||
return a, b, args, c
|
|
||||||
|
|
||||||
|
|
||||||
def test_simple_args_rs():
|
|
||||||
rust = pyfunctions.simple_args(1, "foo", 4, 5, 6, c={1: 2})
|
|
||||||
py = simple_args_py(1, "foo", 4, 5, 6, c={1: 2})
|
|
||||||
assert rust == py
|
|
||||||
|
|
||||||
|
|
||||||
def simple_kwargs_py(a, b="bar", c=None, **kwargs):
|
|
||||||
return a, b, c, kwargs
|
|
||||||
|
|
||||||
|
|
||||||
def test_simple_kwargs_rs():
|
|
||||||
rust = pyfunctions.simple_kwargs(1, "foo", c={1: 2}, bar=4, foo=10)
|
|
||||||
py = simple_kwargs_py(1, "foo", c={1: 2}, bar=4, foo=10)
|
|
||||||
assert rust == py
|
|
||||||
|
|
||||||
|
|
||||||
def simple_args_kwargs_py(a, b="bar", *args, c=None, **kwargs):
|
|
||||||
return (a, b, args, c, kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def test_simple_args_kwargs_rs():
|
|
||||||
rust = pyfunctions.simple_args_kwargs(1, "foo", "baz", bar=4, foo=10)
|
|
||||||
py = simple_args_kwargs_py(1, "foo", "baz", bar=4, foo=10)
|
|
||||||
assert rust == py
|
|
||||||
|
|
||||||
|
|
||||||
def args_kwargs_py(*args, **kwargs):
|
|
||||||
return (args, kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def test_args_kwargs_rs():
|
|
||||||
rust = pyfunctions.args_kwargs(1, "foo", {1: 2}, bar=4, foo=10)
|
|
||||||
py = args_kwargs_py(1, "foo", {1: 2}, bar=4, foo=10)
|
|
||||||
assert rust == py
|
|
|
@ -1,23 +1,5 @@
|
||||||
//! Symbols used to denote deprecated usages of PyO3's proc macros.
|
//! Symbols used to denote deprecated usages of PyO3's proc macros.
|
||||||
|
|
||||||
#[deprecated(
|
|
||||||
since = "0.18.0",
|
|
||||||
note = "passing arbitrary arguments to `#[pyfunction()]` to specify the signature is being replaced by `#[pyo3(signature)]`"
|
|
||||||
)]
|
|
||||||
pub const PYFUNCTION_ARGUMENTS: () = ();
|
|
||||||
|
|
||||||
#[deprecated(
|
|
||||||
since = "0.18.0",
|
|
||||||
note = "the `#[args]` attribute for `#[methods]` is being replaced by `#[pyo3(signature)]`"
|
|
||||||
)]
|
|
||||||
pub const PYMETHODS_ARGS_ATTRIBUTE: () = ();
|
|
||||||
|
|
||||||
#[deprecated(
|
|
||||||
since = "0.18.0",
|
|
||||||
note = "required arguments after an `Option<_>` argument are ambiguous and being phased out\n= help: add a `#[pyo3(signature)]` annotation on this function to unambiguously specify the default values for all optional parameters"
|
|
||||||
)]
|
|
||||||
pub const REQUIRED_ARGUMENT_AFTER_OPTION: () = ();
|
|
||||||
|
|
||||||
#[deprecated(
|
#[deprecated(
|
||||||
since = "0.19.0",
|
since = "0.19.0",
|
||||||
note = "put `text_signature` on `#[new]` instead of `#[pyclass]`"
|
note = "put `text_signature` on `#[new]` instead of `#[pyclass]`"
|
||||||
|
|
|
@ -1106,15 +1106,6 @@ impl PyObject {
|
||||||
{
|
{
|
||||||
<T as PyTryFrom<'_>>::try_from_unchecked(self.as_ref(py))
|
<T as PyTryFrom<'_>>::try_from_unchecked(self.as_ref(py))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Casts the PyObject to a concrete Python object type.
|
|
||||||
#[deprecated(since = "0.18.0", note = "use downcast() instead")]
|
|
||||||
pub fn cast_as<'p, D>(&'p self, py: Python<'p>) -> Result<&'p D, PyDowncastError<'_>>
|
|
||||||
where
|
|
||||||
D: PyTryFrom<'p>,
|
|
||||||
{
|
|
||||||
self.downcast(py)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -799,15 +799,6 @@ impl PyAny {
|
||||||
unsafe { ffi::Py_TYPE(self.as_ptr()) }
|
unsafe { ffi::Py_TYPE(self.as_ptr()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts this `PyAny` to a concrete Python type.
|
|
||||||
#[deprecated(since = "0.18.0", note = "use the equivalent .downcast()")]
|
|
||||||
pub fn cast_as<'a, D>(&'a self) -> Result<&'a D, PyDowncastError<'_>>
|
|
||||||
where
|
|
||||||
D: PyTryFrom<'a>,
|
|
||||||
{
|
|
||||||
self.downcast()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Downcast this `PyAny` to a concrete Python type or pyclass.
|
/// Downcast this `PyAny` to a concrete Python type or pyclass.
|
||||||
///
|
///
|
||||||
/// Note that you can often avoid downcasting yourself by just specifying
|
/// Note that you can often avoid downcasting yourself by just specifying
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
fn test_compile_errors() {
|
fn test_compile_errors() {
|
||||||
let t = trybuild::TestCases::new();
|
let t = trybuild::TestCases::new();
|
||||||
|
|
||||||
t.compile_fail("tests/ui/invalid_macro_args.rs");
|
|
||||||
t.compile_fail("tests/ui/invalid_need_module_arg_position.rs");
|
t.compile_fail("tests/ui/invalid_need_module_arg_position.rs");
|
||||||
t.compile_fail("tests/ui/invalid_property_args.rs");
|
t.compile_fail("tests/ui/invalid_property_args.rs");
|
||||||
t.compile_fail("tests/ui/invalid_proto_pymethods.rs");
|
t.compile_fail("tests/ui/invalid_proto_pymethods.rs");
|
||||||
|
|
|
@ -162,464 +162,6 @@ fn static_method_with_args() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(deprecated)]
|
|
||||||
mod deprecated {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[pyclass]
|
|
||||||
struct MethArgs {}
|
|
||||||
|
|
||||||
#[pymethods]
|
|
||||||
impl MethArgs {
|
|
||||||
#[args(test)]
|
|
||||||
fn get_optional(&self, test: Option<i32>) -> i32 {
|
|
||||||
test.unwrap_or(10)
|
|
||||||
}
|
|
||||||
fn get_optional2(&self, test: Option<i32>) -> Option<i32> {
|
|
||||||
test
|
|
||||||
}
|
|
||||||
#[args(test = "None")]
|
|
||||||
fn get_optional3(&self, test: Option<i32>) -> Option<i32> {
|
|
||||||
test
|
|
||||||
}
|
|
||||||
fn get_optional_positional(
|
|
||||||
&self,
|
|
||||||
_t1: Option<i32>,
|
|
||||||
t2: Option<i32>,
|
|
||||||
_t3: Option<i32>,
|
|
||||||
) -> Option<i32> {
|
|
||||||
t2
|
|
||||||
}
|
|
||||||
|
|
||||||
#[args(test = "10")]
|
|
||||||
fn get_default(&self, test: i32) -> i32 {
|
|
||||||
test
|
|
||||||
}
|
|
||||||
#[args("*", test = 10)]
|
|
||||||
fn get_kwarg(&self, test: i32) -> i32 {
|
|
||||||
test
|
|
||||||
}
|
|
||||||
#[args(args = "*", kwargs = "**")]
|
|
||||||
fn get_kwargs(&self, py: Python<'_>, args: &PyTuple, kwargs: Option<&PyDict>) -> PyObject {
|
|
||||||
[args.into(), kwargs.to_object(py)].to_object(py)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[args(args = "*", kwargs = "**")]
|
|
||||||
fn get_pos_arg_kw(
|
|
||||||
&self,
|
|
||||||
py: Python<'_>,
|
|
||||||
a: i32,
|
|
||||||
args: &PyTuple,
|
|
||||||
kwargs: Option<&PyDict>,
|
|
||||||
) -> PyObject {
|
|
||||||
[a.to_object(py), args.into(), kwargs.to_object(py)].to_object(py)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[args(a, b, "/")]
|
|
||||||
fn get_pos_only(&self, a: i32, b: i32) -> i32 {
|
|
||||||
a + b
|
|
||||||
}
|
|
||||||
|
|
||||||
#[args(a, "/", b)]
|
|
||||||
fn get_pos_only_and_pos(&self, a: i32, b: i32) -> i32 {
|
|
||||||
a + b
|
|
||||||
}
|
|
||||||
|
|
||||||
#[args(a, "/", b, c = 5)]
|
|
||||||
fn get_pos_only_and_pos_and_kw(&self, a: i32, b: i32, c: i32) -> i32 {
|
|
||||||
a + b + c
|
|
||||||
}
|
|
||||||
|
|
||||||
#[args(a, "/", "*", b)]
|
|
||||||
fn get_pos_only_and_kw_only(&self, a: i32, b: i32) -> i32 {
|
|
||||||
a + b
|
|
||||||
}
|
|
||||||
|
|
||||||
#[args(a, "/", "*", b = 3)]
|
|
||||||
fn get_pos_only_and_kw_only_with_default(&self, a: i32, b: i32) -> i32 {
|
|
||||||
a + b
|
|
||||||
}
|
|
||||||
|
|
||||||
#[args(a, "/", b, "*", c, d = 5)]
|
|
||||||
fn get_all_arg_types_together(&self, a: i32, b: i32, c: i32, d: i32) -> i32 {
|
|
||||||
a + b + c + d
|
|
||||||
}
|
|
||||||
|
|
||||||
#[args(a, "/", args = "*")]
|
|
||||||
fn get_pos_only_with_varargs(&self, a: i32, args: Vec<i32>) -> i32 {
|
|
||||||
a + args.iter().sum::<i32>()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[args(a, "/", kwargs = "**")]
|
|
||||||
fn get_pos_only_with_kwargs(
|
|
||||||
&self,
|
|
||||||
py: Python<'_>,
|
|
||||||
a: i32,
|
|
||||||
kwargs: Option<&PyDict>,
|
|
||||||
) -> PyObject {
|
|
||||||
[a.to_object(py), kwargs.to_object(py)].to_object(py)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[args("*", a = 2, b = 3)]
|
|
||||||
fn get_kwargs_only_with_defaults(&self, a: i32, b: i32) -> i32 {
|
|
||||||
a + b
|
|
||||||
}
|
|
||||||
|
|
||||||
#[args("*", a, b)]
|
|
||||||
fn get_kwargs_only(&self, a: i32, b: i32) -> i32 {
|
|
||||||
a + b
|
|
||||||
}
|
|
||||||
|
|
||||||
#[args("*", a = 1, b)]
|
|
||||||
fn get_kwargs_only_with_some_default(&self, a: i32, b: i32) -> i32 {
|
|
||||||
a + b
|
|
||||||
}
|
|
||||||
|
|
||||||
#[args(args = "*", a)]
|
|
||||||
fn get_args_and_required_keyword(
|
|
||||||
&self,
|
|
||||||
py: Python<'_>,
|
|
||||||
args: &PyTuple,
|
|
||||||
a: i32,
|
|
||||||
) -> PyObject {
|
|
||||||
(args, a).to_object(py)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[args(a, b = 2, "*", c = 3)]
|
|
||||||
fn get_pos_arg_kw_sep1(&self, a: i32, b: i32, c: i32) -> i32 {
|
|
||||||
a + b + c
|
|
||||||
}
|
|
||||||
|
|
||||||
#[args(a, "*", b = 2, c = 3)]
|
|
||||||
fn get_pos_arg_kw_sep2(&self, a: i32, b: i32, c: i32) -> i32 {
|
|
||||||
a + b + c
|
|
||||||
}
|
|
||||||
|
|
||||||
#[args(kwargs = "**")]
|
|
||||||
fn get_pos_kw(&self, py: Python<'_>, a: i32, kwargs: Option<&PyDict>) -> PyObject {
|
|
||||||
[a.to_object(py), kwargs.to_object(py)].to_object(py)
|
|
||||||
}
|
|
||||||
// "args" can be anything that can be extracted from PyTuple
|
|
||||||
#[args(args = "*")]
|
|
||||||
fn args_as_vec(&self, args: Vec<i32>) -> i32 {
|
|
||||||
args.iter().sum()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn meth_args() {
|
|
||||||
Python::with_gil(|py| {
|
|
||||||
let inst = Py::new(py, MethArgs {}).unwrap();
|
|
||||||
|
|
||||||
py_run!(py, inst, "assert inst.get_optional() == 10");
|
|
||||||
py_run!(py, inst, "assert inst.get_optional(100) == 100");
|
|
||||||
py_run!(py, inst, "assert inst.get_optional2() == None");
|
|
||||||
py_run!(py, inst, "assert inst.get_optional2(100) == 100");
|
|
||||||
py_run!(py, inst, "assert inst.get_optional3() == None");
|
|
||||||
py_run!(py, inst, "assert inst.get_optional3(100) == 100");
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_optional_positional(1, 2, 3) == 2"
|
|
||||||
);
|
|
||||||
py_run!(py, inst, "assert inst.get_optional_positional(1) == None");
|
|
||||||
py_run!(py, inst, "assert inst.get_default() == 10");
|
|
||||||
py_run!(py, inst, "assert inst.get_default(100) == 100");
|
|
||||||
py_run!(py, inst, "assert inst.get_kwarg() == 10");
|
|
||||||
py_expect_exception!(py, inst, "inst.get_kwarg(100)", PyTypeError);
|
|
||||||
py_run!(py, inst, "assert inst.get_kwarg(test=100) == 100");
|
|
||||||
py_run!(py, inst, "assert inst.get_kwargs() == [(), None]");
|
|
||||||
py_run!(py, inst, "assert inst.get_kwargs(1,2,3) == [(1,2,3), None]");
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_kwargs(t=1,n=2) == [(), {'t': 1, 'n': 2}]"
|
|
||||||
);
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_kwargs(1,2,3,t=1,n=2) == [(1,2,3), {'t': 1, 'n': 2}]"
|
|
||||||
);
|
|
||||||
|
|
||||||
py_run!(py, inst, "assert inst.get_pos_arg_kw(1) == [1, (), None]");
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_pos_arg_kw(1, 2, 3) == [1, (2, 3), None]"
|
|
||||||
);
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_pos_arg_kw(1, b=2) == [1, (), {'b': 2}]"
|
|
||||||
);
|
|
||||||
py_run!(py, inst, "assert inst.get_pos_arg_kw(a=1) == [1, (), None]");
|
|
||||||
py_expect_exception!(py, inst, "inst.get_pos_arg_kw()", PyTypeError);
|
|
||||||
py_expect_exception!(py, inst, "inst.get_pos_arg_kw(1, a=1)", PyTypeError);
|
|
||||||
py_expect_exception!(py, inst, "inst.get_pos_arg_kw(b=2)", PyTypeError);
|
|
||||||
|
|
||||||
py_run!(py, inst, "assert inst.get_pos_only(10, 11) == 21");
|
|
||||||
py_expect_exception!(py, inst, "inst.get_pos_only(10, b = 11)", PyTypeError);
|
|
||||||
py_expect_exception!(py, inst, "inst.get_pos_only(a = 10, b = 11)", PyTypeError);
|
|
||||||
|
|
||||||
py_run!(py, inst, "assert inst.get_pos_only_and_pos(10, 11) == 21");
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_pos_only_and_pos(10, b = 11) == 21"
|
|
||||||
);
|
|
||||||
py_expect_exception!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"inst.get_pos_only_and_pos(a = 10, b = 11)",
|
|
||||||
PyTypeError
|
|
||||||
);
|
|
||||||
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_pos_only_and_pos_and_kw(10, 11) == 26"
|
|
||||||
);
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_pos_only_and_pos_and_kw(10, b = 11) == 26"
|
|
||||||
);
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_pos_only_and_pos_and_kw(10, 11, c = 0) == 21"
|
|
||||||
);
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_pos_only_and_pos_and_kw(10, b = 11, c = 0) == 21"
|
|
||||||
);
|
|
||||||
py_expect_exception!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"inst.get_pos_only_and_pos_and_kw(a = 10, b = 11)",
|
|
||||||
PyTypeError
|
|
||||||
);
|
|
||||||
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_pos_only_and_kw_only(10, b = 11) == 21"
|
|
||||||
);
|
|
||||||
py_expect_exception!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"inst.get_pos_only_and_kw_only(10, 11)",
|
|
||||||
PyTypeError
|
|
||||||
);
|
|
||||||
py_expect_exception!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"inst.get_pos_only_and_kw_only(a = 10, b = 11)",
|
|
||||||
PyTypeError
|
|
||||||
);
|
|
||||||
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_pos_only_and_kw_only_with_default(10) == 13"
|
|
||||||
);
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_pos_only_and_kw_only_with_default(10, b = 11) == 21"
|
|
||||||
);
|
|
||||||
py_expect_exception!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"inst.get_pos_only_and_kw_only_with_default(10, 11)",
|
|
||||||
PyTypeError
|
|
||||||
);
|
|
||||||
py_expect_exception!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"inst.get_pos_only_and_kw_only_with_default(a = 10, b = 11)",
|
|
||||||
PyTypeError
|
|
||||||
);
|
|
||||||
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_all_arg_types_together(10, 10, c = 10) == 35"
|
|
||||||
);
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_all_arg_types_together(10, 10, c = 10, d = 10) == 40"
|
|
||||||
);
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_all_arg_types_together(10, b = 10, c = 10, d = 10) == 40"
|
|
||||||
);
|
|
||||||
py_expect_exception!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"inst.get_all_arg_types_together(10, 10, 10)",
|
|
||||||
PyTypeError
|
|
||||||
);
|
|
||||||
py_expect_exception!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"inst.get_all_arg_types_together(a = 10, b = 10, c = 10)",
|
|
||||||
PyTypeError
|
|
||||||
);
|
|
||||||
|
|
||||||
py_run!(py, inst, "assert inst.get_pos_only_with_varargs(10) == 10");
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_pos_only_with_varargs(10, 10) == 20"
|
|
||||||
);
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_pos_only_with_varargs(10, 10, 10, 10, 10) == 50"
|
|
||||||
);
|
|
||||||
py_expect_exception!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"inst.get_pos_only_with_varargs(a = 10)",
|
|
||||||
PyTypeError
|
|
||||||
);
|
|
||||||
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_pos_only_with_kwargs(10) == [10, None]"
|
|
||||||
);
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_pos_only_with_kwargs(10, b = 10) == [10, {'b': 10}]"
|
|
||||||
);
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_pos_only_with_kwargs(10, b = 10, c = 10, d = 10, e = 10) == [10, {'b': 10, 'c': 10, 'd': 10, 'e': 10}]"
|
|
||||||
);
|
|
||||||
py_expect_exception!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"inst.get_pos_only_with_kwargs(a = 10)",
|
|
||||||
PyTypeError
|
|
||||||
);
|
|
||||||
py_expect_exception!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"inst.get_pos_only_with_kwargs(a = 10, b = 10)",
|
|
||||||
PyTypeError
|
|
||||||
);
|
|
||||||
|
|
||||||
py_run!(py, inst, "assert inst.get_kwargs_only_with_defaults() == 5");
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_kwargs_only_with_defaults(a = 8) == 11"
|
|
||||||
);
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_kwargs_only_with_defaults(b = 8) == 10"
|
|
||||||
);
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_kwargs_only_with_defaults(a = 1, b = 1) == 2"
|
|
||||||
);
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_kwargs_only_with_defaults(b = 1, a = 1) == 2"
|
|
||||||
);
|
|
||||||
|
|
||||||
py_run!(py, inst, "assert inst.get_kwargs_only(a = 1, b = 1) == 2");
|
|
||||||
py_run!(py, inst, "assert inst.get_kwargs_only(b = 1, a = 1) == 2");
|
|
||||||
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_kwargs_only_with_some_default(a = 2, b = 1) == 3"
|
|
||||||
);
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_kwargs_only_with_some_default(b = 1) == 2"
|
|
||||||
);
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_kwargs_only_with_some_default(b = 1, a = 2) == 3"
|
|
||||||
);
|
|
||||||
py_expect_exception!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"inst.get_kwargs_only_with_some_default()",
|
|
||||||
PyTypeError
|
|
||||||
);
|
|
||||||
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_args_and_required_keyword(1, 2, a=3) == ((1, 2), 3)"
|
|
||||||
);
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_args_and_required_keyword(a=1) == ((), 1)"
|
|
||||||
);
|
|
||||||
py_expect_exception!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"inst.get_args_and_required_keyword()",
|
|
||||||
PyTypeError
|
|
||||||
);
|
|
||||||
|
|
||||||
py_run!(py, inst, "assert inst.get_pos_arg_kw_sep1(1) == 6");
|
|
||||||
py_run!(py, inst, "assert inst.get_pos_arg_kw_sep1(1, 2) == 6");
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_pos_arg_kw_sep1(1, 2, c=13) == 16"
|
|
||||||
);
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_pos_arg_kw_sep1(a=1, b=2, c=13) == 16"
|
|
||||||
);
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_pos_arg_kw_sep1(b=2, c=13, a=1) == 16"
|
|
||||||
);
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_pos_arg_kw_sep1(c=13, b=2, a=1) == 16"
|
|
||||||
);
|
|
||||||
py_expect_exception!(py, inst, "inst.get_pos_arg_kw_sep1(1, 2, 3)", PyTypeError);
|
|
||||||
|
|
||||||
py_run!(py, inst, "assert inst.get_pos_arg_kw_sep2(1) == 6");
|
|
||||||
py_run!(
|
|
||||||
py,
|
|
||||||
inst,
|
|
||||||
"assert inst.get_pos_arg_kw_sep2(1, b=12, c=13) == 26"
|
|
||||||
);
|
|
||||||
py_expect_exception!(py, inst, "inst.get_pos_arg_kw_sep2(1, 2)", PyTypeError);
|
|
||||||
|
|
||||||
py_run!(py, inst, "assert inst.get_pos_kw(1, b=2) == [1, {'b': 2}]");
|
|
||||||
py_expect_exception!(py, inst, "inst.get_pos_kw(1,2)", PyTypeError);
|
|
||||||
|
|
||||||
py_run!(py, inst, "assert inst.args_as_vec(1,2,3) == 6");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct MethSignature {}
|
struct MethSignature {}
|
||||||
|
|
||||||
|
|
|
@ -478,43 +478,6 @@ fn use_pyfunction() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[allow(deprecated)]
|
|
||||||
fn required_argument_after_option() {
|
|
||||||
#[pyfunction]
|
|
||||||
pub fn foo(x: Option<i32>, y: i32) -> i32 {
|
|
||||||
y + x.unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
Python::with_gil(|py| {
|
|
||||||
let f = wrap_pyfunction!(foo, py).unwrap();
|
|
||||||
|
|
||||||
// it is an error to call this function with no arguments
|
|
||||||
py_expect_exception!(
|
|
||||||
py,
|
|
||||||
f,
|
|
||||||
"f()",
|
|
||||||
PyTypeError,
|
|
||||||
"foo() missing 2 required positional arguments: 'x' and 'y'"
|
|
||||||
);
|
|
||||||
|
|
||||||
// it is an error to call this function with one argument
|
|
||||||
py_expect_exception!(
|
|
||||||
py,
|
|
||||||
f,
|
|
||||||
"f(None)",
|
|
||||||
PyTypeError,
|
|
||||||
"foo() missing 1 required positional argument: 'y'"
|
|
||||||
);
|
|
||||||
|
|
||||||
// ok to call with two arguments
|
|
||||||
py_assert!(py, f, "f(None, 5) == 5");
|
|
||||||
|
|
||||||
// ok to call with keyword arguments
|
|
||||||
py_assert!(py, f, "f(x=None, y=5) == 5");
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct Key(String);
|
struct Key(String);
|
||||||
|
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
#![cfg(feature = "macros")]
|
|
||||||
#![allow(deprecated)]
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
|
||||||
use pyo3::types::{PyDict, PyTuple};
|
|
||||||
|
|
||||||
mod common;
|
|
||||||
|
|
||||||
#[pyclass]
|
|
||||||
struct MyClass {}
|
|
||||||
|
|
||||||
#[pymethods]
|
|
||||||
impl MyClass {
|
|
||||||
#[staticmethod]
|
|
||||||
#[args(args = "*")]
|
|
||||||
fn test_args(args: &PyTuple) -> &PyTuple {
|
|
||||||
args
|
|
||||||
}
|
|
||||||
|
|
||||||
#[staticmethod]
|
|
||||||
#[args(kwargs = "**")]
|
|
||||||
fn test_kwargs(kwargs: Option<&PyDict>) -> Option<&PyDict> {
|
|
||||||
kwargs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn variable_args() {
|
|
||||||
Python::with_gil(|py| {
|
|
||||||
let my_obj = py.get_type::<MyClass>();
|
|
||||||
py_assert!(py, my_obj, "my_obj.test_args() == ()");
|
|
||||||
py_assert!(py, my_obj, "my_obj.test_args(1) == (1,)");
|
|
||||||
py_assert!(py, my_obj, "my_obj.test_args(1, 2) == (1, 2)");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn variable_kwargs() {
|
|
||||||
Python::with_gil(|py| {
|
|
||||||
let my_obj = py.get_type::<MyClass>();
|
|
||||||
py_assert!(py, my_obj, "my_obj.test_kwargs() == None");
|
|
||||||
py_assert!(py, my_obj, "my_obj.test_kwargs(test=1) == {'test': 1}");
|
|
||||||
py_assert!(
|
|
||||||
py,
|
|
||||||
my_obj,
|
|
||||||
"my_obj.test_kwargs(test1=1, test2=2) == {'test1':1, 'test2':2}"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -2,25 +2,8 @@
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
#[pyfunction(_opt = "None", x = "5")]
|
|
||||||
fn function_with_args(_opt: Option<i32>, _x: i32) {}
|
|
||||||
|
|
||||||
#[pyfunction]
|
|
||||||
fn function_with_required_after_option(_opt: Option<i32>, _x: i32) {}
|
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
|
#[pyo3(text_signature = "()")]
|
||||||
struct MyClass;
|
struct MyClass;
|
||||||
|
|
||||||
#[pymethods]
|
fn main() {}
|
||||||
impl MyClass {
|
|
||||||
#[args(_opt = "None", x = "5")]
|
|
||||||
fn function_with_args(&self, _opt: Option<i32>, _x: i32) {}
|
|
||||||
|
|
||||||
#[args(_has_default = 1)]
|
|
||||||
fn default_arg_before_required_deprecated(&self, _has_default: isize, _required: isize) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
function_with_required_after_option(None, 0);
|
|
||||||
function_with_args(None, 0);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,30 +1,11 @@
|
||||||
error: use of deprecated constant `pyo3::impl_::deprecations::PYFUNCTION_ARGUMENTS`: passing arbitrary arguments to `#[pyfunction()]` to specify the signature is being replaced by `#[pyo3(signature)]`
|
error: use of deprecated constant `pyo3::impl_::deprecations::PYCLASS_TEXT_SIGNATURE`: put `text_signature` on `#[new]` instead of `#[pyclass]`
|
||||||
--> tests/ui/deprecations.rs:5:14
|
--> tests/ui/deprecations.rs:6:8
|
||||||
|
|
|
|
||||||
5 | #[pyfunction(_opt = "None", x = "5")]
|
6 | #[pyo3(text_signature = "()")]
|
||||||
| ^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> tests/ui/deprecations.rs:1:9
|
--> tests/ui/deprecations.rs:1:9
|
||||||
|
|
|
|
||||||
1 | #![deny(deprecated)]
|
1 | #![deny(deprecated)]
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
error: use of deprecated constant `pyo3::impl_::deprecations::REQUIRED_ARGUMENT_AFTER_OPTION`: required arguments after an `Option<_>` argument are ambiguous and being phased out
|
|
||||||
= help: add a `#[pyo3(signature)]` annotation on this function to unambiguously specify the default values for all optional parameters
|
|
||||||
--> tests/ui/deprecations.rs:9:59
|
|
||||||
|
|
|
||||||
9 | fn function_with_required_after_option(_opt: Option<i32>, _x: i32) {}
|
|
||||||
| ^^
|
|
||||||
|
|
||||||
error: use of deprecated constant `pyo3::impl_::deprecations::PYMETHODS_ARGS_ATTRIBUTE`: the `#[args]` attribute for `#[methods]` is being replaced by `#[pyo3(signature)]`
|
|
||||||
--> tests/ui/deprecations.rs:16:7
|
|
||||||
|
|
|
||||||
16 | #[args(_opt = "None", x = "5")]
|
|
||||||
| ^^^^
|
|
||||||
|
|
||||||
error: use of deprecated constant `pyo3::impl_::deprecations::PYMETHODS_ARGS_ATTRIBUTE`: the `#[args]` attribute for `#[methods]` is being replaced by `#[pyo3(signature)]`
|
|
||||||
--> tests/ui/deprecations.rs:19:7
|
|
||||||
|
|
|
||||||
19 | #[args(_has_default = 1)]
|
|
||||||
| ^^^^
|
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
use pyo3::prelude::*;
|
|
||||||
|
|
||||||
#[pyfunction(a = 5, b)]
|
|
||||||
fn pos_after_kw(py: Python<'_>, a: i32, b: i32) -> PyObject {
|
|
||||||
[a.to_object(py), vararg.into()].to_object(py)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pyfunction(kwargs = "**", a = 5)]
|
|
||||||
fn kw_after_kwargs(py: Python<'_>, kwargs: &PyDict, a: i32) -> PyObject {
|
|
||||||
[a.to_object(py), vararg.into()].to_object(py)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pyfunction(a, "*", b, "/", c)]
|
|
||||||
fn pos_only_after_kw_only(py: Python<'_>, a: i32, b: i32, c: i32) -> i32 {
|
|
||||||
a + b + c
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pyfunction(a, args="*", "/", b)]
|
|
||||||
fn pos_only_after_args(py: Python<'_>, a: i32, args: Vec<i32>, b: i32) -> i32 {
|
|
||||||
a + b + c
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pyfunction(a, kwargs="**", "/", b)]
|
|
||||||
fn pos_only_after_kwargs(py: Python<'_>, a: i32, args: Vec<i32>, b: i32) -> i32 {
|
|
||||||
a + b
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pyfunction(kwargs = "**", "*", a)]
|
|
||||||
fn kw_only_after_kwargs(py: Python<'_>, kwargs: &PyDict, a: i32) -> PyObject {
|
|
||||||
[a.to_object(py), vararg.into()].to_object(py)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
|
|
@ -1,35 +0,0 @@
|
||||||
error: positional argument or varargs(*) not allowed after keyword arguments
|
|
||||||
--> tests/ui/invalid_macro_args.rs:3:21
|
|
||||||
|
|
|
||||||
3 | #[pyfunction(a = 5, b)]
|
|
||||||
| ^
|
|
||||||
|
|
||||||
error: keyword argument or kwargs(**) is not allowed after kwargs(**)
|
|
||||||
--> tests/ui/invalid_macro_args.rs:8:29
|
|
||||||
|
|
|
||||||
8 | #[pyfunction(kwargs = "**", a = 5)]
|
|
||||||
| ^
|
|
||||||
|
|
||||||
error: / is not allowed after /, varargs(*), or kwargs(**)
|
|
||||||
--> tests/ui/invalid_macro_args.rs:13:25
|
|
||||||
|
|
|
||||||
13 | #[pyfunction(a, "*", b, "/", c)]
|
|
||||||
| ^^^
|
|
||||||
|
|
||||||
error: / is not allowed after /, varargs(*), or kwargs(**)
|
|
||||||
--> tests/ui/invalid_macro_args.rs:18:27
|
|
||||||
|
|
|
||||||
18 | #[pyfunction(a, args="*", "/", b)]
|
|
||||||
| ^^^
|
|
||||||
|
|
||||||
error: / is not allowed after /, varargs(*), or kwargs(**)
|
|
||||||
--> tests/ui/invalid_macro_args.rs:23:30
|
|
||||||
|
|
|
||||||
23 | #[pyfunction(a, kwargs="**", "/", b)]
|
|
||||||
| ^^^
|
|
||||||
|
|
||||||
error: * is not allowed after varargs(*) or kwargs(**)
|
|
||||||
--> tests/ui/invalid_macro_args.rs:28:29
|
|
||||||
|
|
|
||||||
28 | #[pyfunction(kwargs = "**", "*", a)]
|
|
||||||
| ^^^
|
|
|
@ -16,11 +16,11 @@ error: expected argument from function definition `y` but got argument `x`
|
||||||
13 | #[pyo3(signature = (x))]
|
13 | #[pyo3(signature = (x))]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: cannot define both function signature and legacy arguments
|
error: expected one of: `name`, `pass_module`, `signature`, `text_signature`, `crate`
|
||||||
--> tests/ui/invalid_pyfunction_signatures.rs:19:8
|
--> tests/ui/invalid_pyfunction_signatures.rs:18:14
|
||||||
|
|
|
|
||||||
19 | #[pyo3(signature = (x))]
|
18 | #[pyfunction(x)]
|
||||||
| ^^^^^^^^^
|
| ^
|
||||||
|
|
||||||
error: `*args` not allowed after `*`
|
error: `*args` not allowed after `*`
|
||||||
--> tests/ui/invalid_pyfunction_signatures.rs:25:24
|
--> tests/ui/invalid_pyfunction_signatures.rs:25:24
|
||||||
|
@ -52,8 +52,8 @@ error: arguments of type `Python` must not be part of the signature
|
||||||
47 | #[pyfunction(signature = (py))]
|
47 | #[pyfunction(signature = (py))]
|
||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
error: cannot define both function signature and legacy arguments
|
error: cannot find attribute `args` in this scope
|
||||||
--> tests/ui/invalid_pyfunction_signatures.rs:58:12
|
--> tests/ui/invalid_pyfunction_signatures.rs:57:7
|
||||||
|
|
|
|
||||||
58 | #[pyo3(signature = (x))]
|
57 | #[args(x)]
|
||||||
| ^^^^^^^^^
|
| ^^^^
|
||||||
|
|
|
@ -15,4 +15,7 @@ fn wildcard_argument(_: i32) {}
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn destructured_argument((a, b): (i32, i32)) {}
|
fn destructured_argument((a, b): (i32, i32)) {}
|
||||||
|
|
||||||
|
#[pyfunction]
|
||||||
|
fn function_with_required_after_option(_opt: Option<i32>, _x: i32) {}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -29,3 +29,10 @@ error: destructuring in arguments is not supported
|
||||||
|
|
|
|
||||||
16 | fn destructured_argument((a, b): (i32, i32)) {}
|
16 | fn destructured_argument((a, b): (i32, i32)) {}
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: required arguments after an `Option<_>` argument are ambiguous
|
||||||
|
= help: add a `#[pyo3(signature)]` annotation on this function to unambiguously specify the default values for all optional parameters
|
||||||
|
--> tests/ui/invalid_pyfunctions.rs:19:63
|
||||||
|
|
|
||||||
|
19 | fn function_with_required_after_option(_opt: Option<i32>, _x: i32) {}
|
||||||
|
| ^^^
|
||||||
|
|
Loading…
Reference in a new issue