1
- use crate :: attributes:: { self , get_pyo3_options, FromPyWithAttribute } ;
1
+ use crate :: {
2
+ attributes:: { self , get_pyo3_options, CrateAttribute , FromPyWithAttribute } ,
3
+ utils:: get_pyo3_crate,
4
+ } ;
2
5
use proc_macro2:: TokenStream ;
3
6
use quote:: quote;
4
7
use syn:: {
@@ -55,14 +58,14 @@ impl<'a> Enum<'a> {
55
58
for ( i, var) in self . variants . iter ( ) . enumerate ( ) {
56
59
let struct_derive = var. build ( ) ;
57
60
let ext = quote ! (
58
- let maybe_ret = || -> :: pyo3 :: PyResult <Self > {
61
+ let maybe_ret = || -> _pyo3 :: PyResult <Self > {
59
62
#struct_derive
60
63
} ( ) ;
61
64
62
65
match maybe_ret {
63
66
ok @ :: std:: result:: Result :: Ok ( _) => return ok,
64
67
:: std:: result:: Result :: Err ( err) => {
65
- let py = :: pyo3 :: PyNativeType :: py( obj) ;
68
+ let py = _pyo3 :: PyNativeType :: py( obj) ;
66
69
err_reasons. push_str( & :: std:: format!( "{}\n " , err. value( py) . str ( ) ?) ) ;
67
70
}
68
71
}
@@ -82,7 +85,7 @@ impl<'a> Enum<'a> {
82
85
#ty_name,
83
86
#error_names,
84
87
& err_reasons) ;
85
- :: std:: result:: Result :: Err ( :: pyo3 :: exceptions:: PyTypeError :: new_err( err_msg) )
88
+ :: std:: result:: Result :: Err ( _pyo3 :: exceptions:: PyTypeError :: new_err( err_msg) )
86
89
)
87
90
}
88
91
}
@@ -207,8 +210,8 @@ impl<'a> Container<'a> {
207
210
) ;
208
211
quote ! (
209
212
:: std:: result:: Result :: Ok ( #self_ty{ #ident: obj. extract( ) . map_err( |inner| {
210
- let py = :: pyo3 :: PyNativeType :: py( obj) ;
211
- let new_err = :: pyo3 :: exceptions:: PyTypeError :: new_err( #error_msg) ;
213
+ let py = _pyo3 :: PyNativeType :: py( obj) ;
214
+ let new_err = _pyo3 :: exceptions:: PyTypeError :: new_err( #error_msg) ;
212
215
new_err. set_cause( py, :: std:: option:: Option :: Some ( inner) ) ;
213
216
new_err
214
217
} ) ?} )
@@ -222,11 +225,11 @@ impl<'a> Container<'a> {
222
225
} ;
223
226
quote ! (
224
227
:: std:: result:: Result :: Ok ( #self_ty( obj. extract( ) . map_err( |err| {
225
- let py = :: pyo3 :: PyNativeType :: py( obj) ;
228
+ let py = _pyo3 :: PyNativeType :: py( obj) ;
226
229
let err_msg = :: std:: format!( "{}: {}" ,
227
230
#error_msg,
228
231
err. value( py) . str ( ) . unwrap( ) ) ;
229
- :: pyo3 :: exceptions:: PyTypeError :: new_err( err_msg)
232
+ _pyo3 :: exceptions:: PyTypeError :: new_err( err_msg)
230
233
} ) ?) )
231
234
)
232
235
}
@@ -238,9 +241,9 @@ impl<'a> Container<'a> {
238
241
for i in 0 ..len {
239
242
let error_msg = format ! ( "failed to extract field {}.{}" , quote!( #self_ty) , i) ;
240
243
fields. push ( quote ! (
241
- s. get_item( #i) . and_then( :: pyo3 :: types:: PyAny :: extract) . map_err( |inner| {
242
- let py = :: pyo3 :: PyNativeType :: py( obj) ;
243
- let new_err = :: pyo3 :: exceptions:: PyTypeError :: new_err( #error_msg) ;
244
+ s. get_item( #i) . and_then( _pyo3 :: types:: PyAny :: extract) . map_err( |inner| {
245
+ let py = _pyo3 :: PyNativeType :: py( obj) ;
246
+ let new_err = _pyo3 :: exceptions:: PyTypeError :: new_err( #error_msg) ;
244
247
new_err. set_cause( py, :: std:: option:: Option :: Some ( inner) ) ;
245
248
new_err
246
249
} ) ?) ) ;
@@ -255,9 +258,9 @@ impl<'a> Container<'a> {
255
258
quote ! ( "" )
256
259
} ;
257
260
quote ! (
258
- let s = <:: pyo3 :: types:: PyTuple as :: pyo3 :: conversion:: PyTryFrom >:: try_from( obj) ?;
261
+ let s = <_pyo3 :: types:: PyTuple as _pyo3 :: conversion:: PyTryFrom >:: try_from( obj) ?;
259
262
if s. len( ) != #len {
260
- return :: std:: result:: Result :: Err ( :: pyo3 :: exceptions:: PyValueError :: new_err( #msg) )
263
+ return :: std:: result:: Result :: Err ( _pyo3 :: exceptions:: PyValueError :: new_err( #msg) )
261
264
}
262
265
:: std:: result:: Result :: Ok ( #self_ty( #fields) )
263
266
)
@@ -279,15 +282,15 @@ impl<'a> Container<'a> {
279
282
let extractor = match & attrs. from_py_with {
280
283
None => quote ! (
281
284
#get_field. extract( ) . map_err( |inner| {
282
- let py = :: pyo3 :: PyNativeType :: py( obj) ;
283
- let new_err = :: pyo3 :: exceptions:: PyTypeError :: new_err( #conversion_error_msg) ;
285
+ let py = _pyo3 :: PyNativeType :: py( obj) ;
286
+ let new_err = _pyo3 :: exceptions:: PyTypeError :: new_err( #conversion_error_msg) ;
284
287
new_err. set_cause( py, :: std:: option:: Option :: Some ( inner) ) ;
285
288
new_err
286
289
} ) ?) ,
287
290
Some ( FromPyWithAttribute ( expr_path) ) => quote ! (
288
291
#expr_path( #get_field) . map_err( |inner| {
289
- let py = :: pyo3 :: PyNativeType :: py( obj) ;
290
- let new_err = :: pyo3 :: exceptions:: PyTypeError :: new_err( #conversion_error_msg) ;
292
+ let py = _pyo3 :: PyNativeType :: py( obj) ;
293
+ let new_err = _pyo3 :: exceptions:: PyTypeError :: new_err( #conversion_error_msg) ;
291
294
new_err. set_cause( py, :: std:: option:: Option :: Some ( inner) ) ;
292
295
new_err
293
296
} ) ?
@@ -300,20 +303,25 @@ impl<'a> Container<'a> {
300
303
}
301
304
}
302
305
306
+ #[ derive( Default ) ]
303
307
struct ContainerOptions {
304
308
/// Treat the Container as a Wrapper, directly extract its fields from the input object.
305
309
transparent : bool ,
306
310
/// Change the name of an enum variant in the generated error message.
307
311
annotation : Option < syn:: LitStr > ,
312
+ /// Change the path for the pyo3 crate
313
+ krate : Option < CrateAttribute > ,
308
314
}
309
315
310
316
/// Attributes for deriving FromPyObject scoped on containers.
311
- #[ derive( Clone , Debug , PartialEq ) ]
317
+ #[ derive( Debug ) ]
312
318
enum ContainerPyO3Attribute {
313
319
/// Treat the Container as a Wrapper, directly extract its fields from the input object.
314
320
Transparent ( attributes:: kw:: transparent ) ,
315
321
/// Change the name of an enum variant in the generated error message.
316
322
ErrorAnnotation ( LitStr ) ,
323
+ /// Change the path for the pyo3 crate
324
+ Crate ( CrateAttribute ) ,
317
325
}
318
326
319
327
impl Parse for ContainerPyO3Attribute {
@@ -326,6 +334,8 @@ impl Parse for ContainerPyO3Attribute {
326
334
let _: attributes:: kw:: annotation = input. parse ( ) ?;
327
335
let _: Token ! [ =] = input. parse ( ) ?;
328
336
input. parse ( ) . map ( ContainerPyO3Attribute :: ErrorAnnotation )
337
+ } else if lookahead. peek ( Token ! [ crate ] ) {
338
+ input. parse ( ) . map ( ContainerPyO3Attribute :: Crate )
329
339
} else {
330
340
Err ( lookahead. error ( ) )
331
341
}
@@ -334,10 +344,8 @@ impl Parse for ContainerPyO3Attribute {
334
344
335
345
impl ContainerOptions {
336
346
fn from_attrs ( attrs : & [ Attribute ] ) -> Result < Self > {
337
- let mut options = ContainerOptions {
338
- transparent : false ,
339
- annotation : None ,
340
- } ;
347
+ let mut options = ContainerOptions :: default ( ) ;
348
+
341
349
for attr in attrs {
342
350
if let Some ( pyo3_attrs) = get_pyo3_options ( attr) ? {
343
351
for pyo3_attr in pyo3_attrs {
@@ -356,6 +364,13 @@ impl ContainerOptions {
356
364
) ;
357
365
options. annotation = Some ( lit_str) ;
358
366
}
367
+ ContainerPyO3Attribute :: Crate ( path) => {
368
+ ensure_spanned ! (
369
+ options. krate. is_none( ) ,
370
+ path. 0 . span( ) => "`crate` may only be provided once"
371
+ ) ;
372
+ options. krate = Some ( path) ;
373
+ }
359
374
}
360
375
}
361
376
}
@@ -499,13 +514,18 @@ pub fn build_derive_from_pyobject(tokens: &DeriveInput) -> Result<TokenStream> {
499
514
. predicates
500
515
. push ( parse_quote ! ( #gen_ident: FromPyObject <#lt_param>) )
501
516
}
517
+ let options = ContainerOptions :: from_attrs ( & tokens. attrs ) ?;
518
+ let krate = get_pyo3_crate ( & options. krate ) ;
502
519
let derives = match & tokens. data {
503
520
syn:: Data :: Enum ( en) => {
521
+ if options. transparent || options. annotation . is_some ( ) {
522
+ bail_spanned ! ( tokens. span( ) => "`transparent` or `annotation` is not supported \
523
+ at top level for enums") ;
524
+ }
504
525
let en = Enum :: new ( en, & tokens. ident ) ?;
505
526
en. build ( )
506
527
}
507
528
syn:: Data :: Struct ( st) => {
508
- let options = ContainerOptions :: from_attrs ( & tokens. attrs ) ?;
509
529
if let Some ( lit_str) = & options. annotation {
510
530
bail_spanned ! ( lit_str. span( ) => "`annotation` is unsupported for structs" ) ;
511
531
}
@@ -520,11 +540,15 @@ pub fn build_derive_from_pyobject(tokens: &DeriveInput) -> Result<TokenStream> {
520
540
521
541
let ident = & tokens. ident ;
522
542
Ok ( quote ! (
523
- #[ automatically_derived]
524
- impl #trait_generics :: pyo3:: FromPyObject <#lt_param> for #ident#generics #where_clause {
525
- fn extract( obj: & #lt_param :: pyo3:: PyAny ) -> :: pyo3:: PyResult <Self > {
526
- #derives
543
+ const _: ( ) = {
544
+ use #krate as _pyo3;
545
+
546
+ #[ automatically_derived]
547
+ impl #trait_generics _pyo3:: FromPyObject <#lt_param> for #ident#generics #where_clause {
548
+ fn extract( obj: & #lt_param _pyo3:: PyAny ) -> _pyo3:: PyResult <Self > {
549
+ #derives
550
+ }
527
551
}
528
- }
552
+ } ;
529
553
) )
530
554
}
0 commit comments