Skip to content

Commit 54cfaf2

Browse files
authored
derive(FromPyObject): support raw identifiers (#4814)
1 parent ea8c461 commit 54cfaf2

File tree

3 files changed

+44
-4
lines changed

3 files changed

+44
-4
lines changed

newsfragments/4814.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
`derive(FromPyObject)` support raw identifiers like `r#box`.

pyo3-macros-backend/src/frompyobject.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::utils::Ctx;
33
use proc_macro2::TokenStream;
44
use quote::{format_ident, quote};
55
use syn::{
6+
ext::IdentExt,
67
parenthesized,
78
parse::{Parse, ParseStream},
89
parse_quote,
@@ -323,11 +324,11 @@ impl<'a> Container<'a> {
323324
fn build_struct(&self, struct_fields: &[NamedStructField<'_>], ctx: &Ctx) -> TokenStream {
324325
let Ctx { pyo3_path, .. } = ctx;
325326
let self_ty = &self.path;
326-
let struct_name = &self.name();
327-
let mut fields: Punctuated<TokenStream, syn::Token![,]> = Punctuated::new();
327+
let struct_name = self.name();
328+
let mut fields: Punctuated<TokenStream, Token![,]> = Punctuated::new();
328329
for field in struct_fields {
329-
let ident = &field.ident;
330-
let field_name = ident.to_string();
330+
let ident = field.ident;
331+
let field_name = ident.unraw().to_string();
331332
let getter = match field.getter.as_ref().unwrap_or(&FieldGetter::GetAttr(None)) {
332333
FieldGetter::GetAttr(Some(name)) => {
333334
quote!(#pyo3_path::types::PyAnyMethods::getattr(obj, #pyo3_path::intern!(obj.py(), #name)))

tests/test_frompyobject.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,3 +648,41 @@ fn test_transparent_from_py_with() {
648648
assert_eq!(result, expected);
649649
});
650650
}
651+
652+
#[derive(Debug, FromPyObject, PartialEq, Eq)]
653+
pub struct WithKeywordAttr {
654+
r#box: usize,
655+
}
656+
657+
#[pyclass]
658+
pub struct WithKeywordAttrC {
659+
#[pyo3(get)]
660+
r#box: usize,
661+
}
662+
663+
#[test]
664+
fn test_with_keyword_attr() {
665+
Python::with_gil(|py| {
666+
let cls = WithKeywordAttrC { r#box: 3 }.into_pyobject(py).unwrap();
667+
let result = cls.extract::<WithKeywordAttr>().unwrap();
668+
let expected = WithKeywordAttr { r#box: 3 };
669+
assert_eq!(result, expected);
670+
});
671+
}
672+
673+
#[derive(Debug, FromPyObject, PartialEq, Eq)]
674+
pub struct WithKeywordItem {
675+
#[pyo3(item)]
676+
r#box: usize,
677+
}
678+
679+
#[test]
680+
fn test_with_keyword_item() {
681+
Python::with_gil(|py| {
682+
let dict = PyDict::new(py);
683+
dict.set_item("box", 3).unwrap();
684+
let result = dict.extract::<WithKeywordItem>().unwrap();
685+
let expected = WithKeywordItem { r#box: 3 };
686+
assert_eq!(result, expected);
687+
});
688+
}

0 commit comments

Comments
 (0)