1
1
/* DeferExpr core implementation */
2
2
3
3
#include "Python.h" // IWYU pragma: keep
4
+ #include "object.h"
4
5
#include "pycore_object.h"
5
6
#include "pyerrors.h"
6
7
#include "pytypedefs.h"
@@ -46,6 +47,17 @@ PyObject *PyDeferExpr_Observe(PyObject *obj)
46
47
if (self -> collapsible && self -> result != NULL )
47
48
return self -> result ;
48
49
50
+ if (!PyCallable_Check (self -> callable ))
51
+ {
52
+ PyErr_Format (PyExc_RuntimeError ,
53
+ "Failed to observe DeferExpr: "
54
+ "%s is not callable" ,
55
+ (self -> callable == NULL )
56
+ ? "<void>"
57
+ : Py_TYPE (self -> callable )-> tp_name );
58
+ return NULL ;
59
+ }
60
+
49
61
obj = PyObject_CallNoArgs (_Py_CAST (PyObject * , self -> callable ));
50
62
obj = PyDeferExpr_Observe (obj );
51
63
@@ -432,95 +444,60 @@ PyObject *builtin_snapshot(PyObject *unused, PyObject *obj)
432
444
433
445
/* =================== END: builtin methods for DeferExpr =================== */
434
446
435
- #define GETTER (NAME ) \
436
- static PyObject *defer_expr_exposed_get_##NAME( \
437
- PyDeferExprExposedObject *self, void *unused)
438
-
439
- #define SETTER (NAME ) \
440
- static int defer_expr_exposed_set_##NAME(PyDeferExprExposedObject *self, \
441
- PyObject *value, void *unused)
442
-
443
- GETTER (collapsible )
447
+ static PyObject * defer_expr_exposed_getattr (PyDeferExprExposedObject * self ,
448
+ char * attr )
444
449
{
445
- if (self -> ref -> collapsible )
446
- Py_RETURN_TRUE ;
447
- else
448
- Py_RETURN_FALSE ;
450
+ if (strcmp (attr , "collapsible" ) == 0 )
451
+ return (self -> ref -> collapsible ) ? (Py_True ) : (Py_False );
452
+ else if (strcmp (attr , "callable" ) == 0 && self -> ref -> callable != NULL )
453
+ return Py_NewRef (self -> ref -> callable );
454
+ else if (strcmp (attr , "result" ) == 0 && self -> ref -> result != NULL )
455
+ return Py_NewRef (self -> ref -> result );
456
+ // No such attribute
457
+ PyErr_Format (PyExc_AttributeError , "<%s object> has no attribute \"%s\"" ,
458
+ self -> ob_base .ob_type -> tp_name , attr );
459
+ return NULL ;
449
460
}
450
461
451
- SETTER (collapsible )
462
+ static int defer_expr_exposed_setattr (PyDeferExprExposedObject * self ,
463
+ char * attr , PyObject * value )
452
464
{
453
- if (Py_IsTrue (value ))
454
- self -> ref -> collapsible = 1 ;
455
- else
456
- self -> ref -> collapsible = 0 ;
457
- return 0 ;
458
- }
459
-
460
- GETTER (callable )
461
- {
462
- PyObject * res = Py_XNewRef (self -> ref -> callable );
463
- if (res == NULL )
465
+ if (strcmp (attr , "collapsible" ) == 0 )
466
+ self -> ref -> collapsible = Py_IsTrue (value ) ? 1 : 0 ;
467
+ else if (strcmp (attr , "callable" ) == 0 )
464
468
{
465
- PyErr_SetString (PyExc_AttributeError ,
466
- "attribute <callable> does not exist" );
467
- return NULL ;
469
+ // Allow deletion of the callable attribute as long as user knows what
470
+ // they are doing. Setting none-callable object is also allowed but will
471
+ // error out upon observation of the DeferExpr
472
+ Py_XDECREF (self -> ref -> callable );
473
+ self -> ref -> callable = Py_XNewRef (value );
468
474
}
469
- return res ;
470
- }
471
-
472
- SETTER (callable )
473
- {
474
- if (value != NULL && !PyCallable_Check (value ))
475
+ else if (strcmp (attr , "result" ) == 0 )
475
476
{
476
- PyErr_SetString (PyExc_TypeError , "value must be callable" );
477
- return -1 ;
477
+ // A frozen DeferExpr's result may be manually tweaked as long as user
478
+ // knows what they are doing
479
+ Py_XDECREF (self -> ref -> result );
480
+ self -> ref -> result = Py_XNewRef (value );
478
481
}
479
- Py_XDECREF (self -> ref -> callable );
480
- self -> ref -> callable = Py_XNewRef (value );
481
- return 0 ;
482
- }
483
-
484
- GETTER (result )
485
- {
486
- PyObject * res = self -> ref -> result ;
487
- if (res == NULL )
482
+ else // No such attribute
488
483
{
489
- PyErr_SetString (PyExc_AttributeError ,
490
- "attribute <result> does not exist" );
491
- return NULL ;
484
+ PyErr_Format (PyExc_AttributeError ,
485
+ "<%s object> has no attribute \"%s\"" ,
486
+ self -> ob_base .ob_type -> tp_name , attr );
487
+ return -1 ;
492
488
}
493
- return Py_NewRef (res );
494
- }
495
-
496
- SETTER (result )
497
- {
498
- // A frozen DeferExpr's result may be manually tweaked
499
- // as long as user knows what they are doing
500
- Py_XDECREF (self -> ref -> result );
501
- self -> ref -> result = Py_XNewRef (value );
502
489
return 0 ;
503
490
}
504
491
505
- static PyGetSetDef DeferExpr_getsetlist [] = {
506
- {"collapsible" , (getter )defer_expr_exposed_get_collapsible ,
507
- (setter )defer_expr_exposed_set_collapsible },
508
- {"callable" , (getter )defer_expr_exposed_get_callable ,
509
- (setter )defer_expr_exposed_set_callable },
510
- {"result" , (getter )defer_expr_exposed_get_result ,
511
- (setter )defer_expr_exposed_set_result },
512
- {NULL , NULL , NULL , NULL , NULL },
513
- };
514
-
515
492
PyTypeObject PyDeferExprExposed_Type = {
516
493
PyVarObject_HEAD_INIT (& PyType_Type , 0 ) //
517
494
"DeferExprExposed" ,
518
495
sizeof (PyDeferExprExposedObject ),
519
496
(Py_ssize_t )0 ,
520
497
(destructor )defer_expr_exposed_dealloc ,
521
498
(Py_ssize_t )0 ,
522
- (getattrfunc )0 ,
523
- (setattrfunc )0 ,
499
+ (getattrfunc )defer_expr_exposed_getattr ,
500
+ (setattrfunc )defer_expr_exposed_setattr ,
524
501
(PyAsyncMethods * )0 ,
525
502
(reprfunc )0 ,
526
503
(PyNumberMethods * )0 ,
@@ -542,7 +519,7 @@ PyTypeObject PyDeferExprExposed_Type = {
542
519
(iternextfunc )0 ,
543
520
(PyMethodDef * )0 ,
544
521
(PyMemberDef * )0 ,
545
- (PyGetSetDef * )DeferExpr_getsetlist ,
522
+ (PyGetSetDef * )0 ,
546
523
(PyTypeObject * )0 ,
547
524
(PyObject * )0 ,
548
525
(descrgetfunc )0 ,
0 commit comments