Removed the custom error messages from the macro api
This commit is contained in:
parent
416b1132b4
commit
973f0a5bae
|
@ -124,7 +124,6 @@ struct Container<'a> {
|
||||||
ty: ContainerType<'a>,
|
ty: ContainerType<'a>,
|
||||||
err_name: String,
|
err_name: String,
|
||||||
is_enum_variant: bool,
|
is_enum_variant: bool,
|
||||||
error_msg: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Container<'a> {
|
impl<'a> Container<'a> {
|
||||||
|
@ -184,14 +183,11 @@ impl<'a> Container<'a> {
|
||||||
|lit_str| lit_str.value(),
|
|lit_str| lit_str.value(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let error_msg = options.error_msg.map(|inner| inner.value());
|
|
||||||
|
|
||||||
let v = Container {
|
let v = Container {
|
||||||
path,
|
path,
|
||||||
ty: style,
|
ty: style,
|
||||||
err_name,
|
err_name,
|
||||||
is_enum_variant,
|
is_enum_variant,
|
||||||
error_msg,
|
|
||||||
};
|
};
|
||||||
Ok(v)
|
Ok(v)
|
||||||
}
|
}
|
||||||
|
@ -209,13 +205,10 @@ impl<'a> Container<'a> {
|
||||||
fn build_newtype_struct(&self, field_ident: Option<&Ident>) -> TokenStream {
|
fn build_newtype_struct(&self, field_ident: Option<&Ident>) -> TokenStream {
|
||||||
let self_ty = &self.path;
|
let self_ty = &self.path;
|
||||||
if let Some(ident) = field_ident {
|
if let Some(ident) = field_ident {
|
||||||
let error_msg = self.error_msg.as_ref().map_or(
|
let error_msg = format!(
|
||||||
format!(
|
|
||||||
"failed to extract field {}.{}",
|
"failed to extract field {}.{}",
|
||||||
quote!(#self_ty),
|
quote!(#self_ty),
|
||||||
quote!(#ident)
|
quote!(#ident)
|
||||||
),
|
|
||||||
|msg| msg.clone(),
|
|
||||||
);
|
);
|
||||||
quote!(
|
quote!(
|
||||||
Ok(#self_ty{#ident: obj.extract().map_err(|inner| {
|
Ok(#self_ty{#ident: obj.extract().map_err(|inner| {
|
||||||
|
@ -226,10 +219,7 @@ impl<'a> Container<'a> {
|
||||||
})?})
|
})?})
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let error_msg = self.error_msg.as_ref().map_or(
|
let error_msg = format!("failed to extract inner field of {}", quote!(#self_ty));
|
||||||
format!("failed to extract inner field of {}", quote!(#self_ty)),
|
|
||||||
|msg| msg.clone(),
|
|
||||||
);
|
|
||||||
quote!(Ok(#self_ty(obj.extract().map_err(|inner| {
|
quote!(Ok(#self_ty(obj.extract().map_err(|inner| {
|
||||||
let err_msg = format!("{}\n\nCaused by:\n {}\n",
|
let err_msg = format!("{}\n\nCaused by:\n {}\n",
|
||||||
#error_msg,
|
#error_msg,
|
||||||
|
@ -242,12 +232,8 @@ impl<'a> Container<'a> {
|
||||||
fn build_tuple_struct(&self, len: usize) -> TokenStream {
|
fn build_tuple_struct(&self, len: usize) -> TokenStream {
|
||||||
let self_ty = &self.path;
|
let self_ty = &self.path;
|
||||||
let mut fields: Punctuated<TokenStream, syn::Token![,]> = Punctuated::new();
|
let mut fields: Punctuated<TokenStream, syn::Token![,]> = Punctuated::new();
|
||||||
|
|
||||||
for i in 0..len {
|
for i in 0..len {
|
||||||
let error_msg = self.error_msg.as_ref().map_or(
|
let error_msg = format!("failed to extract field {}.{}", quote!(#self_ty), i);
|
||||||
format!("failed to extract field {}.{}", quote!(#self_ty), i),
|
|
||||||
|msg| msg.clone(),
|
|
||||||
);
|
|
||||||
fields.push(quote!(s.get_item(#i).extract().map_err(|inner| {
|
fields.push(quote!(s.get_item(#i).extract().map_err(|inner| {
|
||||||
let err_msg = format!("{}\n\nCaused by:\n {}\n",
|
let err_msg = format!("{}\n\nCaused by:\n {}\n",
|
||||||
#error_msg,
|
#error_msg,
|
||||||
|
@ -283,10 +269,7 @@ impl<'a> Container<'a> {
|
||||||
FieldGetter::GetItem(Some(key)) => quote!(get_item(#key)),
|
FieldGetter::GetItem(Some(key)) => quote!(get_item(#key)),
|
||||||
FieldGetter::GetItem(None) => quote!(get_item(stringify!(#ident))),
|
FieldGetter::GetItem(None) => quote!(get_item(stringify!(#ident))),
|
||||||
};
|
};
|
||||||
let conversion_error_msg = attrs.error_msg.as_ref().map_or(
|
let conversion_error_msg = format!("failed to extract field {}.{}", quote!(#self_ty), ident);
|
||||||
format!("failed to extract field {}.{}", quote!(#self_ty), ident),
|
|
||||||
|msg| msg.value(),
|
|
||||||
);
|
|
||||||
let get_field = quote!(obj.#getter?);
|
let get_field = quote!(obj.#getter?);
|
||||||
let extractor = match &attrs.from_py_with {
|
let extractor = match &attrs.from_py_with {
|
||||||
None => quote!(#get_field.extract().map_err(|inner| {
|
None => quote!(#get_field.extract().map_err(|inner| {
|
||||||
|
@ -315,8 +298,6 @@ struct ContainerOptions {
|
||||||
transparent: bool,
|
transparent: bool,
|
||||||
/// Change the name of an enum variant in the generated error message.
|
/// Change the name of an enum variant in the generated error message.
|
||||||
annotation: Option<syn::LitStr>,
|
annotation: Option<syn::LitStr>,
|
||||||
/// Change the error message displayed when extract fails
|
|
||||||
error_msg: Option<syn::LitStr>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attributes for deriving FromPyObject scoped on containers.
|
/// Attributes for deriving FromPyObject scoped on containers.
|
||||||
|
@ -326,8 +307,6 @@ enum ContainerPyO3Attribute {
|
||||||
Transparent(attributes::kw::transparent),
|
Transparent(attributes::kw::transparent),
|
||||||
/// Change the name of an enum variant in the generated error message.
|
/// Change the name of an enum variant in the generated error message.
|
||||||
ErrorAnnotation(LitStr),
|
ErrorAnnotation(LitStr),
|
||||||
/// Change the error message displayed when extract fails
|
|
||||||
ErrorMsg(LitStr),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for ContainerPyO3Attribute {
|
impl Parse for ContainerPyO3Attribute {
|
||||||
|
@ -340,10 +319,6 @@ impl Parse for ContainerPyO3Attribute {
|
||||||
let _: attributes::kw::annotation = input.parse()?;
|
let _: attributes::kw::annotation = input.parse()?;
|
||||||
let _: Token![=] = input.parse()?;
|
let _: Token![=] = input.parse()?;
|
||||||
input.parse().map(ContainerPyO3Attribute::ErrorAnnotation)
|
input.parse().map(ContainerPyO3Attribute::ErrorAnnotation)
|
||||||
} else if lookahead.peek(attributes::kw::error_message) {
|
|
||||||
let _: attributes::kw::error_message = input.parse()?;
|
|
||||||
let _: Token![=] = input.parse()?;
|
|
||||||
input.parse().map(ContainerPyO3Attribute::ErrorMsg)
|
|
||||||
} else {
|
} else {
|
||||||
Err(lookahead.error())
|
Err(lookahead.error())
|
||||||
}
|
}
|
||||||
|
@ -355,7 +330,6 @@ impl ContainerOptions {
|
||||||
let mut options = ContainerOptions {
|
let mut options = ContainerOptions {
|
||||||
transparent: false,
|
transparent: false,
|
||||||
annotation: None,
|
annotation: None,
|
||||||
error_msg: None,
|
|
||||||
};
|
};
|
||||||
for attr in attrs {
|
for attr in attrs {
|
||||||
if let Some(pyo3_attrs) = get_pyo3_attributes(attr)? {
|
if let Some(pyo3_attrs) = get_pyo3_attributes(attr)? {
|
||||||
|
@ -375,13 +349,6 @@ impl ContainerOptions {
|
||||||
);
|
);
|
||||||
options.annotation = Some(lit_str);
|
options.annotation = Some(lit_str);
|
||||||
}
|
}
|
||||||
ContainerPyO3Attribute::ErrorMsg(lit_str) => {
|
|
||||||
ensure_spanned!(
|
|
||||||
options.error_msg.is_none(),
|
|
||||||
lit_str.span() => "`error_message` may only be provided once"
|
|
||||||
);
|
|
||||||
options.error_msg = Some(lit_str);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -395,7 +362,6 @@ impl ContainerOptions {
|
||||||
struct FieldPyO3Attributes {
|
struct FieldPyO3Attributes {
|
||||||
getter: FieldGetter,
|
getter: FieldGetter,
|
||||||
from_py_with: Option<FromPyWithAttribute>,
|
from_py_with: Option<FromPyWithAttribute>,
|
||||||
error_msg: Option<LitStr>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -407,7 +373,6 @@ enum FieldGetter {
|
||||||
enum FieldPyO3Attribute {
|
enum FieldPyO3Attribute {
|
||||||
Getter(FieldGetter),
|
Getter(FieldGetter),
|
||||||
FromPyWith(FromPyWithAttribute),
|
FromPyWith(FromPyWithAttribute),
|
||||||
ErrorMsg(LitStr),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for FieldPyO3Attribute {
|
impl Parse for FieldPyO3Attribute {
|
||||||
|
@ -451,10 +416,6 @@ impl Parse for FieldPyO3Attribute {
|
||||||
}
|
}
|
||||||
} else if lookahead.peek(attributes::kw::from_py_with) {
|
} else if lookahead.peek(attributes::kw::from_py_with) {
|
||||||
input.parse().map(FieldPyO3Attribute::FromPyWith)
|
input.parse().map(FieldPyO3Attribute::FromPyWith)
|
||||||
} else if lookahead.peek(attributes::kw::error_message) {
|
|
||||||
let _: attributes::kw::error_message = input.parse()?;
|
|
||||||
let _: Token![=] = input.parse()?;
|
|
||||||
input.parse().map(FieldPyO3Attribute::ErrorMsg)
|
|
||||||
} else {
|
} else {
|
||||||
Err(lookahead.error())
|
Err(lookahead.error())
|
||||||
}
|
}
|
||||||
|
@ -467,7 +428,6 @@ impl FieldPyO3Attributes {
|
||||||
fn from_attrs(attrs: &[Attribute]) -> Result<Self> {
|
fn from_attrs(attrs: &[Attribute]) -> Result<Self> {
|
||||||
let mut getter = None;
|
let mut getter = None;
|
||||||
let mut from_py_with = None;
|
let mut from_py_with = None;
|
||||||
let mut error_msg = None;
|
|
||||||
|
|
||||||
for attr in attrs {
|
for attr in attrs {
|
||||||
if let Some(pyo3_attrs) = get_pyo3_attributes(attr)? {
|
if let Some(pyo3_attrs) = get_pyo3_attributes(attr)? {
|
||||||
|
@ -487,13 +447,6 @@ impl FieldPyO3Attributes {
|
||||||
);
|
);
|
||||||
from_py_with = Some(from_py_with_attr);
|
from_py_with = Some(from_py_with_attr);
|
||||||
}
|
}
|
||||||
FieldPyO3Attribute::ErrorMsg(err_msg) => {
|
|
||||||
ensure_spanned!(
|
|
||||||
error_msg.is_none(),
|
|
||||||
attr.span() => "`conversion_error` may only be provided once"
|
|
||||||
);
|
|
||||||
error_msg = Some(err_msg)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -502,7 +455,6 @@ impl FieldPyO3Attributes {
|
||||||
Ok(FieldPyO3Attributes {
|
Ok(FieldPyO3Attributes {
|
||||||
getter: getter.unwrap_or(FieldGetter::GetAttr(None)),
|
getter: getter.unwrap_or(FieldGetter::GetAttr(None)),
|
||||||
from_py_with,
|
from_py_with,
|
||||||
error_msg,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -230,70 +230,7 @@ fn test_struct_nested_type_errors_with_generics() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, FromPyObject)]
|
#[derive(Debug, FromPyObject)]
|
||||||
struct Custom<U, T> {
|
#[pyo3(transparent)]
|
||||||
e: E<U, T>,
|
|
||||||
#[pyo3(error_message = "Type 'Tuple' should be of the form (str, integer)")]
|
|
||||||
tup: Tuple,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_custom_error_message_struct() {
|
|
||||||
let gil = Python::acquire_gil();
|
|
||||||
let py = gil.python();
|
|
||||||
|
|
||||||
let pybaz = PyBaz {
|
|
||||||
tup: ("test".into(), "test".into()),
|
|
||||||
e: PyE {
|
|
||||||
test: "foo".into(),
|
|
||||||
test2: 0,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
.into_py(py);
|
|
||||||
|
|
||||||
let test: PyResult<Custom<String, usize>> = FromPyObject::extract(pybaz.as_ref(py));
|
|
||||||
assert!(test.is_err());
|
|
||||||
assert_eq!(
|
|
||||||
"TypeError: Type \'Tuple\' should be of the form (str, integer)\n\nCaused by:\n TypeError: failed to extract field Tuple.1\n\nCaused by:\n TypeError: \'str\' object cannot be interpreted as an integer\n\n",
|
|
||||||
test.unwrap_err().to_string()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, FromPyObject)]
|
|
||||||
#[pyo3(error_message = "Conversion failed: Tuple expects 'str', 'usize'")]
|
|
||||||
pub struct Tuple2(String, usize);
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_custom_error_message_tuple_struct() {
|
|
||||||
let gil = Python::acquire_gil();
|
|
||||||
let py = gil.python();
|
|
||||||
let pytup = PyTuple::new(py, &["test".into_py(py), "test".into_py(py)]);
|
|
||||||
let test: PyResult<Tuple2> = FromPyObject::extract(pytup);
|
|
||||||
assert!(test.is_err());
|
|
||||||
assert_eq!(
|
|
||||||
"TypeError: Conversion failed: Tuple expects \'str\', \'usize\'\n\nCaused by:\n TypeError: \'str\' object cannot be interpreted as an integer\n",
|
|
||||||
test.unwrap_err().to_string()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, FromPyObject)]
|
|
||||||
#[pyo3(error_message = "Expected type str")]
|
|
||||||
pub struct TransparentTuple2(String);
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_transparent_tuple_struct_error_message() {
|
|
||||||
let gil = Python::acquire_gil();
|
|
||||||
let py = gil.python();
|
|
||||||
let tup: PyObject = 1.into_py(py);
|
|
||||||
let tup = TransparentTuple2::extract(tup.as_ref(py));
|
|
||||||
assert!(tup.is_err());
|
|
||||||
assert_eq!(
|
|
||||||
"TypeError: Expected type str\n\nCaused by:\n TypeError: \'int\' object cannot be converted to \'PyString\'\n",
|
|
||||||
tup.unwrap_err().to_string()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, FromPyObject)]
|
|
||||||
#[pyo3(transparent, error_message = "Expected type str")]
|
|
||||||
pub struct TransparentStruct {
|
pub struct TransparentStruct {
|
||||||
a: String,
|
a: String,
|
||||||
}
|
}
|
||||||
|
@ -306,39 +243,11 @@ fn test_transparent_struct_error_message() {
|
||||||
let tup = TransparentStruct::extract(tup.as_ref(py));
|
let tup = TransparentStruct::extract(tup.as_ref(py));
|
||||||
assert!(tup.is_err());
|
assert!(tup.is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"TypeError: Expected type str\n\nCaused by:\n TypeError: \'int\' object cannot be converted to \'PyString\'\n",
|
"TypeError: failed to extract field TransparentStruct.a\n\nCaused by:\n TypeError: \'int\' object cannot be converted to \'PyString\'\n",
|
||||||
tup.unwrap_err().to_string()
|
tup.unwrap_err().to_string()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, FromPyObject)]
|
|
||||||
struct Custom2<U, T> {
|
|
||||||
e: E<U, T>,
|
|
||||||
#[pyo3(error_message = "Type 'Tuple' should be of the form (str, integer)")]
|
|
||||||
tup: Tuple2,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_nested_custom_errors() {
|
|
||||||
let gil = Python::acquire_gil();
|
|
||||||
let py = gil.python();
|
|
||||||
|
|
||||||
let pybaz = PyBaz {
|
|
||||||
tup: ("test".into(), "test".into()),
|
|
||||||
e: PyE {
|
|
||||||
test: "foo".into(),
|
|
||||||
test2: 0,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
.into_py(py);
|
|
||||||
|
|
||||||
let test: PyResult<Custom2<String, usize>> = FromPyObject::extract(pybaz.as_ref(py));
|
|
||||||
assert!(test.is_err());
|
|
||||||
assert_eq!(
|
|
||||||
"TypeError: Type \'Tuple\' should be of the form (str, integer)\n\nCaused by:\n TypeError: Conversion failed: Tuple expects \'str\', \'usize\'\n\nCaused by:\n TypeError: \'str\' object cannot be interpreted as an integer\n\n",
|
|
||||||
test.unwrap_err().to_string()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, FromPyObject)]
|
#[derive(Debug, FromPyObject)]
|
||||||
pub enum Foo<'a> {
|
pub enum Foo<'a> {
|
||||||
|
@ -453,11 +362,7 @@ pub enum Bar {
|
||||||
A(String),
|
A(String),
|
||||||
#[pyo3(annotation = "uint")]
|
#[pyo3(annotation = "uint")]
|
||||||
B(usize),
|
B(usize),
|
||||||
#[pyo3(
|
#[pyo3(annotation = "int", transparent)]
|
||||||
annotation = "int",
|
|
||||||
transparent,
|
|
||||||
error_message = "Bar::C expects an integer type"
|
|
||||||
)]
|
|
||||||
C(isize),
|
C(isize),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,7 +375,7 @@ fn test_err_rename() {
|
||||||
assert!(f.is_err());
|
assert!(f.is_err());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
f.unwrap_err().to_string(),
|
f.unwrap_err().to_string(),
|
||||||
"TypeError: Failed to extract type Bar\n\nCaused by:\n TypeError: \'dict\' object cannot be converted to \'Union[str, uint, int]\'\n\nTypeError: failed to extract inner field of Bar :: A\n\nCaused by:\n TypeError: \'dict\' object cannot be converted to \'PyString\'\n\nTypeError: failed to extract inner field of Bar :: B\n\nCaused by:\n TypeError: \'dict\' object cannot be interpreted as an integer\n\nTypeError: Bar::C expects an integer type\n\nCaused by:\n TypeError: \'dict\' object cannot be interpreted as an integer\n\n"
|
"TypeError: Failed to extract type Bar\n\nCaused by:\n TypeError: \'dict\' object cannot be converted to \'Union[str, uint, int]\'\n\nTypeError: failed to extract inner field of Bar :: A\n\nCaused by:\n TypeError: \'dict\' object cannot be converted to \'PyString\'\n\nTypeError: failed to extract inner field of Bar :: B\n\nCaused by:\n TypeError: \'dict\' object cannot be interpreted as an integer\n\nTypeError: failed to extract inner field of Bar :: C\n\nCaused by:\n TypeError: \'dict\' object cannot be interpreted as an integer\n\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ error: transparent structs and variants can only have 1 field
|
||||||
70 | | },
|
70 | | },
|
||||||
| |_____^
|
| |_____^
|
||||||
|
|
||||||
error: expected one of: `attribute`, `item`, `from_py_with`, `error_message`
|
error: expected one of: `attribute`, `item`, `from_py_with`
|
||||||
--> $DIR/invalid_frompy_derive.rs:76:12
|
--> $DIR/invalid_frompy_derive.rs:76:12
|
||||||
|
|
|
|
||||||
76 | #[pyo3(attr)]
|
76 | #[pyo3(attr)]
|
||||||
|
@ -132,7 +132,7 @@ error: only one of `attribute` or `item` can be provided
|
||||||
118 | #[pyo3(item, attribute)]
|
118 | #[pyo3(item, attribute)]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: expected one of: `transparent`, `annotation`, `error_message`
|
error: expected `transparent` or `annotation`
|
||||||
--> $DIR/invalid_frompy_derive.rs:123:8
|
--> $DIR/invalid_frompy_derive.rs:123:8
|
||||||
|
|
|
|
||||||
123 | #[pyo3(unknown = "should not work")]
|
123 | #[pyo3(unknown = "should not work")]
|
||||||
|
|
Loading…
Reference in New Issue