@@ -1279,7 +1279,6 @@ impl<ClassT: PyClass, FieldT: ToPyObject, Offset: OffsetCalculator<ClassT, Field
1279
1279
diagnostic:: on_unimplemented(
1280
1280
message = "`{Self}` cannot be converted to a Python object" ,
1281
1281
label = "required by `#[pyo3(get)]` to create a readable property from a field of type `{Self}`" ,
1282
- note = "`Py<T>` fields are always converible to Python objects" ,
1283
1282
note = "implement `ToPyObject` or `IntoPy<PyObject> + Clone` for `{Self}` to define the conversion" ,
1284
1283
)
1285
1284
) ]
@@ -1313,24 +1312,24 @@ impl<ClassT: PyClass, FieldT, Offset: OffsetCalculator<ClassT, FieldT>>
1313
1312
/// The true case is defined in the zero-sized type's impl block, which is
1314
1313
/// gated on some property like trait bound or only being implemented
1315
1314
/// for fixed concrete types.
1316
- pub trait Tester {
1315
+ pub trait Probe {
1317
1316
const VALUE : bool = false ;
1318
1317
}
1319
1318
1320
- macro_rules! tester {
1319
+ macro_rules! probe {
1321
1320
( $name: ident) => {
1322
1321
pub struct $name<T >( PhantomData <T >) ;
1323
- impl <T > Tester for $name<T > { }
1322
+ impl <T > Probe for $name<T > { }
1324
1323
} ;
1325
1324
}
1326
1325
1327
- tester ! ( IsPyT ) ;
1326
+ probe ! ( IsPyT ) ;
1328
1327
1329
1328
impl < T > IsPyT < Py < T > > {
1330
1329
pub const VALUE : bool = true ;
1331
1330
}
1332
1331
1333
- tester ! ( IsToPyObject ) ;
1332
+ probe ! ( IsToPyObject ) ;
1334
1333
1335
1334
impl < T : ToPyObject > IsToPyObject < T > {
1336
1335
pub const VALUE : bool = true ;
@@ -1379,3 +1378,79 @@ fn pyo3_get_value<
1379
1378
// _holder is preventing mutable aliasing
1380
1379
Ok ( ( unsafe { & * value } ) . clone ( ) . into_py ( py) . into_ptr ( ) )
1381
1380
}
1381
+
1382
+ #[ cfg( test) ]
1383
+ #[ cfg( feature = "macros" ) ]
1384
+ mod tests {
1385
+ use super :: * ;
1386
+
1387
+ #[ test]
1388
+ fn get_py_for_frozen_class ( ) {
1389
+ #[ crate :: pyclass( crate = "crate" , frozen) ]
1390
+ struct FrozenClass {
1391
+ #[ pyo3( get) ]
1392
+ value : Py < PyAny > ,
1393
+ }
1394
+
1395
+ let mut methods = Vec :: new ( ) ;
1396
+ let mut slots = Vec :: new ( ) ;
1397
+
1398
+ for items in FrozenClass :: items_iter ( ) {
1399
+ methods. extend ( items. methods . iter ( ) . map ( |m| match m {
1400
+ MaybeRuntimePyMethodDef :: Static ( m) => m. clone ( ) ,
1401
+ MaybeRuntimePyMethodDef :: Runtime ( r) => r ( ) ,
1402
+ } ) ) ;
1403
+ slots. extend_from_slice ( items. slots ) ;
1404
+ }
1405
+
1406
+ assert_eq ! ( methods. len( ) , 1 ) ;
1407
+ assert ! ( slots. is_empty( ) ) ;
1408
+
1409
+ match methods. first ( ) {
1410
+ Some ( PyMethodDefType :: StructMember ( member) ) => {
1411
+ assert_eq ! ( unsafe { CStr :: from_ptr( member. name) } , ffi:: c_str!( "value" ) ) ;
1412
+ assert_eq ! ( member. type_code, ffi:: Py_T_OBJECT_EX ) ;
1413
+ assert_eq ! (
1414
+ member. offset,
1415
+ ( memoffset:: offset_of!( PyClassObject <FrozenClass >, contents)
1416
+ + memoffset:: offset_of!( FrozenClass , value) )
1417
+ as ffi:: Py_ssize_t
1418
+ ) ;
1419
+ assert_eq ! ( member. flags, ffi:: Py_READONLY ) ;
1420
+ }
1421
+ _ => panic ! ( "Expected a StructMember" ) ,
1422
+ }
1423
+ }
1424
+
1425
+ #[ test]
1426
+ fn get_py_for_non_frozen_class ( ) {
1427
+ #[ crate :: pyclass( crate = "crate" ) ]
1428
+ struct FrozenClass {
1429
+ #[ pyo3( get) ]
1430
+ value : Py < PyAny > ,
1431
+ }
1432
+
1433
+ let mut methods = Vec :: new ( ) ;
1434
+ let mut slots = Vec :: new ( ) ;
1435
+
1436
+ for items in FrozenClass :: items_iter ( ) {
1437
+ methods. extend ( items. methods . iter ( ) . map ( |m| match m {
1438
+ MaybeRuntimePyMethodDef :: Static ( m) => m. clone ( ) ,
1439
+ MaybeRuntimePyMethodDef :: Runtime ( r) => r ( ) ,
1440
+ } ) ) ;
1441
+ slots. extend_from_slice ( items. slots ) ;
1442
+ }
1443
+
1444
+ assert_eq ! ( methods. len( ) , 1 ) ;
1445
+ assert ! ( slots. is_empty( ) ) ;
1446
+
1447
+ match methods. first ( ) {
1448
+ Some ( PyMethodDefType :: Getter ( getter) ) => {
1449
+ assert_eq ! ( getter. name, ffi:: c_str!( "value" ) ) ;
1450
+ assert_eq ! ( getter. doc, ffi:: c_str!( "" ) ) ;
1451
+ // tests for the function pointer are in test_getter_setter.py
1452
+ }
1453
+ _ => panic ! ( "Expected a StructMember" ) ,
1454
+ }
1455
+ }
1456
+ }
0 commit comments