@@ -55,6 +55,7 @@ struct module_state {
55
55
PyObject * DatetimeMS ;
56
56
PyObject * _min_datetime_ms ;
57
57
PyObject * _max_datetime_ms ;
58
+ PyObject * _type_marker_str ;
58
59
};
59
60
60
61
#define GETSTATE (m ) ((struct module_state*)PyModule_GetState(m))
@@ -378,6 +379,9 @@ static int _load_python_objects(PyObject* module) {
378
379
PyObject * compiled = NULL ;
379
380
struct module_state * state = GETSTATE (module );
380
381
382
+ /* Python str for faster _type_marker check */
383
+ state -> _type_marker_str = PyUnicode_FromString ("_type_marker" );
384
+
381
385
if (_load_object (& state -> Binary , "bson.binary" , "Binary" ) ||
382
386
_load_object (& state -> Code , "bson.code" , "Code" ) ||
383
387
_load_object (& state -> ObjectId , "bson.objectid" , "ObjectId" ) ||
@@ -428,12 +432,12 @@ static int _load_python_objects(PyObject* module) {
428
432
*
429
433
* Return the type marker, 0 if there is no marker, or -1 on failure.
430
434
*/
431
- static long _type_marker (PyObject * object ) {
435
+ static long _type_marker (PyObject * object , PyObject * _type_marker_str ) {
432
436
PyObject * type_marker = NULL ;
433
437
long type = 0 ;
434
438
435
- if (PyObject_HasAttrString (object , "_type_marker" )) {
436
- type_marker = PyObject_GetAttrString (object , "_type_marker" );
439
+ if (PyObject_HasAttr (object , _type_marker_str )) {
440
+ type_marker = PyObject_GetAttr (object , _type_marker_str );
437
441
if (type_marker == NULL ) {
438
442
return -1 ;
439
443
}
@@ -450,13 +454,6 @@ static long _type_marker(PyObject* object) {
450
454
if (type_marker && PyLong_CheckExact (type_marker )) {
451
455
type = PyLong_AsLong (type_marker );
452
456
Py_DECREF (type_marker );
453
- /*
454
- * Py(Long|Int)_AsLong returns -1 for error but -1 is a valid value
455
- * so we call PyErr_Occurred to differentiate.
456
- */
457
- if (type == -1 && PyErr_Occurred ()) {
458
- return -1 ;
459
- }
460
457
} else {
461
458
Py_XDECREF (type_marker );
462
459
}
@@ -504,13 +501,12 @@ int cbson_convert_type_registry(PyObject* registry_obj, type_registry_t* registr
504
501
return 0 ;
505
502
}
506
503
507
- /* Fill out a codec_options_t* from a CodecOptions object. Use with the "O&"
508
- * format spec in PyArg_ParseTuple.
504
+ /* Fill out a codec_options_t* from a CodecOptions object.
509
505
*
510
506
* Return 1 on success. options->document_class is a new reference.
511
507
* Return 0 on failure.
512
508
*/
513
- int convert_codec_options (PyObject * options_obj , void * p ) {
509
+ int convert_codec_options (PyObject * self , PyObject * options_obj , void * p ) {
514
510
codec_options_t * options = (codec_options_t * )p ;
515
511
PyObject * type_registry_obj = NULL ;
516
512
long type_marker ;
@@ -527,7 +523,8 @@ int convert_codec_options(PyObject* options_obj, void* p) {
527
523
& options -> datetime_conversion ))
528
524
return 0 ;
529
525
530
- type_marker = _type_marker (options -> document_class );
526
+ type_marker = _type_marker (options -> document_class ,
527
+ GETSTATE (self )-> _type_marker_str );
531
528
if (type_marker < 0 ) {
532
529
return 0 ;
533
530
}
@@ -730,7 +727,7 @@ static int _write_element_to_buffer(PyObject* self, buffer_t buffer,
730
727
* problems with python sub interpreters. Our custom types should
731
728
* have a _type_marker attribute, which we can switch on instead.
732
729
*/
733
- long type = _type_marker (value );
730
+ long type = _type_marker (value , state -> _type_marker_str );
734
731
if (type < 0 ) {
735
732
return 0 ;
736
733
}
@@ -1382,7 +1379,7 @@ int write_dict(PyObject* self, buffer_t buffer,
1382
1379
long type_marker ;
1383
1380
1384
1381
/* check for RawBSONDocument */
1385
- type_marker = _type_marker (dict );
1382
+ type_marker = _type_marker (dict , state -> _type_marker_str );
1386
1383
if (type_marker < 0 ) {
1387
1384
return 0 ;
1388
1385
}
@@ -1504,18 +1501,20 @@ static PyObject* _cbson_dict_to_bson(PyObject* self, PyObject* args) {
1504
1501
PyObject * result ;
1505
1502
unsigned char check_keys ;
1506
1503
unsigned char top_level = 1 ;
1504
+ PyObject * options_obj ;
1507
1505
codec_options_t options ;
1508
1506
buffer_t buffer ;
1509
1507
PyObject * raw_bson_document_bytes_obj ;
1510
1508
long type_marker ;
1511
1509
1512
- if (!PyArg_ParseTuple (args , "ObO&|b" , & dict , & check_keys ,
1513
- convert_codec_options , & options , & top_level )) {
1510
+ if (!(PyArg_ParseTuple (args , "ObO|b" , & dict , & check_keys ,
1511
+ & options_obj , & top_level ) &&
1512
+ convert_codec_options (self , options_obj , & options ))) {
1514
1513
return NULL ;
1515
1514
}
1516
1515
1517
1516
/* check for RawBSONDocument */
1518
- type_marker = _type_marker (dict );
1517
+ type_marker = _type_marker (dict , GETSTATE ( self ) -> _type_marker_str );
1519
1518
if (type_marker < 0 ) {
1520
1519
destroy_codec_options (& options );
1521
1520
return NULL ;
@@ -2526,6 +2525,7 @@ static PyObject* _cbson_element_to_dict(PyObject* self, PyObject* args) {
2526
2525
/* TODO: Support buffer protocol */
2527
2526
char * string ;
2528
2527
PyObject * bson ;
2528
+ PyObject * options_obj ;
2529
2529
codec_options_t options ;
2530
2530
unsigned position ;
2531
2531
unsigned max ;
@@ -2535,8 +2535,9 @@ static PyObject* _cbson_element_to_dict(PyObject* self, PyObject* args) {
2535
2535
PyObject * value ;
2536
2536
PyObject * result_tuple ;
2537
2537
2538
- if (!PyArg_ParseTuple (args , "OIIO&p" , & bson , & position , & max ,
2539
- convert_codec_options , & options , & raw_array )) {
2538
+ if (!(PyArg_ParseTuple (args , "OIIOp" , & bson , & position , & max ,
2539
+ & options_obj , & raw_array ) &&
2540
+ convert_codec_options (self , options_obj , & options ))) {
2540
2541
return NULL ;
2541
2542
}
2542
2543
@@ -2638,7 +2639,7 @@ static PyObject* _cbson_bson_to_dict(PyObject* self, PyObject* args) {
2638
2639
Py_buffer view = {0 };
2639
2640
2640
2641
if (! (PyArg_ParseTuple (args , "OO" , & bson , & options_obj ) &&
2641
- convert_codec_options (options_obj , & options ))) {
2642
+ convert_codec_options (self , options_obj , & options ))) {
2642
2643
return result ;
2643
2644
}
2644
2645
@@ -2715,10 +2716,8 @@ static PyObject* _cbson_decode_all(PyObject* self, PyObject* args) {
2715
2716
PyObject * options_obj = NULL ;
2716
2717
Py_buffer view = {0 };
2717
2718
2718
- if (!PyArg_ParseTuple (args , "OO" , & bson , & options_obj )) {
2719
- return NULL ;
2720
- }
2721
- if (!convert_codec_options (options_obj , & options )) {
2719
+ if (!(PyArg_ParseTuple (args , "OO" , & bson , & options_obj ) &&
2720
+ convert_codec_options (self , options_obj , & options ))) {
2722
2721
return NULL ;
2723
2722
}
2724
2723
@@ -2966,6 +2965,7 @@ static int _cbson_clear(PyObject *m) {
2966
2965
Py_CLEAR (GETSTATE (m )-> MaxKey );
2967
2966
Py_CLEAR (GETSTATE (m )-> UTC );
2968
2967
Py_CLEAR (GETSTATE (m )-> REType );
2968
+ Py_CLEAR (GETSTATE (m )-> _type_marker_str );
2969
2969
return 0 ;
2970
2970
}
2971
2971
0 commit comments