NCBI C++ ToolKit
pythonpp_ext.hpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: pythonpp_ext.hpp 98959 2023-01-26 15:59:04Z ucko $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Sergey Sikorskiy
27 *
28 * File Description: Tiny Python API wrappers
29 *
30 * Status: *Initial*
31 *
32 * ===========================================================================
33 */
34 
35 #ifndef PYTHONPP_EXT_H
36 #define PYTHONPP_EXT_H
37 
38 #include "pythonpp_seq.hpp"
39 #include "pythonpp_dict.hpp"
40 
42 
43 // Per https://docs.python.org/3/whatsnew/3.11.html#porting-to-python-3-11
44 #if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_TYPE)
45 static inline void _Py_SET_TYPE(PyObject *ob, PyTypeObject *type)
46 { ob->ob_type = type; }
47 #define Py_SET_TYPE(ob, type) _Py_SET_TYPE((PyObject*)(ob), type)
48 #endif
49 
50 #if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_SIZE)
51 static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size)
52 { ob->ob_size = size; }
53 #define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject*)(ob), size)
54 #endif
55 
56 #if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_REFCNT)
57 static inline void _Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt)
58 { ob->ob_refcnt = refcnt; }
59 #define Py_SET_REFCNT(ob, refcnt) _Py_SET_REFCNT((PyObject*)(ob), refcnt)
60 #endif
61 
63 
64 namespace pythonpp
65 {
66 
67 #if PY_MAJOR_VERSION >= 3
68 inline
69 PyObject* Py_FindMethod(PyMethodDef table[], PyObject *ob, char *name)
70 {
71  for (size_t i = 0; table[i].ml_name != NULL; ++i) {
72  if (strcmp(table[i].ml_name, name) == 0) {
73  return PyCFunction_New(table + i, ob);
74  }
75  }
76  CAttributeError error(name);
77  return NULL;
78 }
79 #endif
80 
81 extern "C"
82 {
83  typedef PyObject* (*TMethodVarArgsHandler)( PyObject* self, PyObject* args );
84  typedef PyObject* (*TMethodKeywordHandler)( PyObject* self, PyObject* args, PyObject* dict );
85 }
86 
87 //////////////////////////////////////////////////////////////////////////
88 /// Introduces constructor methods for a python PyMethodDef structure ...
89 struct SMethodDef : public PyMethodDef
90 {
91 public:
92  SMethodDef(void)
93  {
94  ml_name = 0;
95  ml_meth = 0;
96  ml_flags = 0;
97  ml_doc = 0;
98  }
99  SMethodDef(const char* name, PyCFunction func, int flags = 1, const char* doc = NULL)
100  {
101  ml_name = const_cast<char*>( name );
102  ml_meth = func;
103  ml_flags = flags;
104  ml_doc = const_cast<char*>( doc );
105  }
106  SMethodDef(const char* name, PyCFunctionWithKeywords func,
107  int flags = METH_VARARGS | METH_KEYWORDS,
108  const char* doc = nullptr)
109  {
110  ml_name = const_cast<char*>(name);
111  ml_meth = reinterpret_cast<PyCFunction>(func);
112  ml_flags = flags;
113  ml_doc = const_cast<char*>(doc);
114  }
115  SMethodDef(const SMethodDef& other)
116  {
117  ml_name = other.ml_name;
118  ml_meth = other.ml_meth;
119  ml_flags = other.ml_flags;
120  ml_doc = other.ml_doc;
121  }
122 
124  {
125  if (this != &other) {
126  ml_name = other.ml_name;
127  ml_meth = other.ml_meth;
128  ml_flags = other.ml_flags;
129  ml_doc = other.ml_doc;
130  }
131  return *this;
132  }
133 };
134 
135 extern "C" void DoNotDeallocate( void* )
136 {
137 }
138 
139 //////////////////////////////////////////////////////////////////////////
140 extern "C"
141 void standard_dealloc( PyObject* obj )
142 {
143  PyMem_DEL( obj );
144 }
145 
146 //////////////////////////////////////////////////////////////////////////
147 class CExtObjectBase;
148 
149 // PyTypeObject is inherited from a PyVarObject (C-kind of inheritance) ...
150 class CExtType : public PyTypeObject
151 {
152 public:
154  size_t basic_size,
156  PyTypeObject* base = &PyBaseObject_Type)
157  {
158  BasicInit();
159 
160  Py_SET_TYPE(this, &PyType_Type);
161  tp_basicsize = basic_size;
162  tp_dealloc = dr;
163  // Py_TPFLAGS_BASETYPE - means that the type is subtypable ...
164  tp_flags = Py_TPFLAGS_DEFAULT;
165  tp_base = base;
166  // tp_bases = ??? // It should be NULL for statically defined types.
167 
168  // Finalize the type object including setting type of the new type
169  // object; doing it here is required for portability to Windows
170  // without requiring C++.
171  // !!! This code does not work currently !!!
172  // if ( PyType_Ready(this) == -1 ) {
173  // throw CError("Cannot initialyze a type object");
174  // }
175  }
176 
177 public:
178  PyTypeObject* GetObjType( void )
179  {
180  return this;
181  }
182  const PyTypeObject* GetObjType( void ) const
183  {
184  return this;
185  }
186  void SetName( const char* name )
187  {
188  tp_name = const_cast<char*>( name );
189  }
190  void SetDescription( const char* descr )
191  {
192  tp_doc = const_cast<char*>( descr );
193  }
194 
195 public:
196  void SupportGetAttr( getattrfunc func )
197  {
198  tp_getattr = func;
199  }
200 
201 private:
202  void BasicInit( void )
203  {
204 #ifdef Py_TRACE_REFS
205  _ob_next = NULL;
206  _ob_prev = NULL;
207 #endif
208  Py_SET_REFCNT(this, 1);
209  Py_SET_TYPE(this, NULL);
210  Py_SET_SIZE(this, 0);
211 
212  tp_name = NULL;
213 
214  tp_basicsize = 0;
215  tp_itemsize = 0;
216 
217  // Methods to implement standard operations
218  tp_dealloc = NULL;
219 #if PY_MAJOR_VERSION < 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 8)
220  tp_print = NULL;
221 #else
222  tp_vectorcall_offset = 0;
223 #endif
224 
225  tp_getattr = NULL; // This field is deprecated.
226  tp_setattr = NULL; // This field is deprecated.
227 
228 #if PY_MAJOR_VERSION < 3
229  tp_compare = NULL;
230 #elif PY_MINOR_VERSION >= 5
231  tp_as_async = NULL;
232 #else
233  tp_reserved = NULL;
234 #endif
235  tp_repr = NULL;
236 
237  // Method suites for standard classes
238  tp_as_number = NULL;
239  tp_as_sequence = NULL;
240  tp_as_mapping = NULL;
241 
242  // More standard operations (here for binary compatibility)
243  tp_hash = NULL;
244  tp_call = NULL;
245  tp_str = NULL;
246 
247  tp_getattro = NULL;
248  tp_setattro = NULL;
249 
250  // Functions to access object as input/output buffer
251  tp_as_buffer = NULL;
252 
253  // Flags to define presence of optional/expanded features
254  tp_flags = 0L;
255 
256  // Documentation string
257  tp_doc = NULL;
258 
259  // call function for all accessible objects
260  tp_traverse = 0L;
261 
262  // delete references to contained objects
263  tp_clear = 0L;
264 
265  // rich comparisons
266  tp_richcompare = 0L;
267 
268  // weak reference enabler
269  tp_weaklistoffset = 0L;
270 
271  // Iterators
272  tp_iter = 0L;
273  tp_iternext = 0L;
274 
275  // Attribute descriptor and subclassing stuff
276  tp_methods = NULL; // Object's method table ( same as retturned by GetMethodHndlList() )
277  tp_members = NULL;
278  tp_getset = NULL;
279  tp_base = NULL;
280 
281  tp_dict = NULL;
282  tp_descr_get = NULL;
283  tp_descr_set = NULL;
284 
285  tp_dictoffset = 0;
286 
287  tp_init = NULL;
288  tp_alloc = NULL;
289  tp_new = NULL;
290  tp_free = NULL; // Low-level free-memory routine
291  tp_is_gc = NULL; // For PyObject_IS_GC
292  tp_bases = NULL;
293  tp_mro = NULL; // method resolution order
294 #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 4
295  tp_finalize = NULL;
296 #endif
297  tp_cache = NULL;
298  tp_subclasses = NULL;
299  tp_weaklist = NULL;
300  tp_del = NULL;
301 
302  tp_version_tag = 0U;
303 
304 #ifdef COUNT_ALLOCS
305 # if PY_MAJOR_VERSION >= 3
306  tp_allocs = 0;
307  tp_frees = 0;
308 # else
309  tp_alloc = 0;
310  tp_free = 0;
311 # endif
312  tp_maxalloc = 0;
313  tp_next = 0;
314 #endif
315  }
316 };
317 
318 inline
319 bool operator ==(const CObject& l, const CExtType& r)
320 {
321  return l.GetObjType() == r.GetObjType();
322 }
323 
324 inline
325 bool operator ==(const CExtType& l, const CObject& r)
326 {
327  return l.GetObjType() == r.GetObjType();
328 }
329 
330 //////////////////////////////////////////////////////////////////////////
331 namespace bind
332 {
333 
335 
336 class CBase
337 {
338 public:
340  : m_Type( type )
341  {
342  }
343  virtual ~CBase(void)
344  {
345  }
346 
347 public:
348  bool IsReadOnly(void) const
349  {
350  return m_Type == eReadOnly;
351  }
352  virtual PyObject* Get(void) const = 0;
353  void Set( PyObject* value ) const
354  {
355  if ( IsReadOnly() ) {
356  throw CAttributeError("Read-only property");
357  }
358  SetInternal( value );
359  }
360 
361 protected:
362  virtual void SetInternal( PyObject* value ) const
363  {
364  }
365 
366 private:
368 };
369 
370 class CLong : public CBase
371 {
372 public:
374  : CBase( type )
375  , m_Value( &value )
376  {
377  }
378  virtual ~CLong(void)
379  {
380  }
381 
382 public:
383  virtual PyObject* Get(void) const
384  {
385  return PyLong_FromLong( *m_Value );
386  }
387 
388 protected:
389  virtual void SetInternal( PyObject* value ) const
390  {
391  long tmp_value = PyLong_AsLong( value );
392  CError::Check();
393  *m_Value = tmp_value;
394  }
395 
396 private:
397  long* const m_Value;
398 };
399 
400 class CString : public CBase
401 {
402 public:
404  : CBase( type )
405  , m_Value( &value )
406  {
407  }
408  virtual ~CString(void)
409  {
410  }
411 
412 public:
413  virtual PyObject* Get(void) const
414  {
415 #if PY_MAJOR_VERSION >= 3
416  return PyUnicode_FromStringAndSize(m_Value->data(), m_Value->size());
417 #else
418  return PyString_FromStringAndSize( m_Value->data(), m_Value->size() );
419 #endif
420  }
421 
422 protected:
423  virtual void SetInternal( PyObject* value ) const
424  {
425 #if PY_VERSION_HEX >= 0x03030000
426  Py_ssize_t size;
427  auto utf = PyUnicode_AsUTF8AndSize(Get(), &size);
428  string tmp_value(utf, size);
429 #elif PY_MAJOR_VERSION >= 3
430  string tmp_value
431  = CUtf8::AsUTF8(PyUnicode_AsUnicode(Get()),
432  static_cast<size_t>(PyUnicode_GetSize(Get())));
433 #else
434  string tmp_value = string( PyString_AsString( value ), static_cast<size_t>( PyString_Size( value ) ) );
435 #endif
436  CError::Check();
437  *m_Value = tmp_value;
438  }
439 
440 private:
441  string* const m_Value;
442 };
443 
444 template <class T>
445 class CObject : public CBase
446 {
447 public:
448  typedef PyObject* (T::*TGetFunc)( void ) const;
449  typedef void (T::*TSetFunc)( PyObject* value );
450 
451 public:
452  CObject( T& obj, TGetFunc get, TSetFunc set = NULL )
453  : CBase( set == NULL ? eReadOnly : eReadWrite )
454  , m_Obj( &obj )
455  , m_GetFunc( get )
456  , m_SetFunc( set )
457  {
458  }
459  virtual ~CObject(void)
460  {
461  }
462 
463 public:
464  virtual PyObject* Get(void) const
465  {
466  PyObject* obj = (m_Obj->*m_GetFunc)();
467  IncRefCount(obj);
468  return obj;
469  }
470 
471 protected:
472  virtual void SetInternal( PyObject* value ) const
473  {
474  (m_Obj->*m_SetFunc)( value );
475  }
476 
477 private:
478  T* const m_Obj;
481 };
482 
483 }
484 
485 //////////////////////////////////////////////////////////////////////////
486 template<size_t N>
487 inline
488 void resize(vector<SMethodDef>& container)
489 {
490  if (container.size() < N) {
491  container.resize(N);
492  }
493 }
494 
495 template<>
496 inline
497 void resize<0>(vector<SMethodDef>& /*container*/)
498 {
499  ;
500 }
501 
502 //////////////////////////////////////////////////////////////////////////
503 template <class T>
504 class CExtObject : public PyObject
505 {
506 public:
508  {
509  // This is not an appropriate place for initialization ....
510 // PyObject_INIT( this, &GetType() );
511  }
512 
514  {
515  }
516 
517 public:
518  typedef CObject (T::*TMethodVarArgsFunc)( const CTuple& args );
519  typedef CObject (T::*TMethodKWArgsFunc)(const CTuple& args,
520  const CDict& kwargs);
521  /// Workaround for GCC 2.95
522  struct SFunct
523  {
525  : m_Funct(funct)
526  {
527  }
528 
529  SFunct(const TMethodKWArgsFunc& funct)
530  : m_Funct(reinterpret_cast<TMethodVarArgsFunc>(funct))
531  {
532  }
533 
534  operator TMethodVarArgsFunc(void) const
535  {
536  return m_Funct;
537  }
538 
539  operator TMethodKWArgsFunc(void) const
540  {
541  return reinterpret_cast<TMethodKWArgsFunc>(m_Funct);
542  }
543 
545  };
546 
547  // A helper class for generating functions ...
548  template<size_t N = 0>
549  class CClass
550  {
551  public:
552  CClass(void)
553  {
554  // Finalyze a method definition ...
555  GetMethodHndlList().push_back( SMethodDef() );
556  }
557 
558  public:
559  CClass<N + 1> Def(const char* name, TMethodVarArgsFunc func, const char* doc = 0)
560  {
561  TMethodHndlList& hndl_list = GetMethodHndlList();
562 
563  // Prepare data for python ...
564  resize<N>(hndl_list);
565  hndl_list[ePosition] = SMethodDef(name, (PyCFunction)HandleMethodVarArgs, METH_VARARGS, doc);
566 
567  // Prepare data for our handler ...
568  GetMethodList().push_back(func);
569 
570  return CClass<N + 1>();
571  }
572 
573  CClass<N + 1> Def(const char* name, TMethodKWArgsFunc func,
574  const char* doc = nullptr)
575  {
576  TMethodHndlList& hndl_list = GetMethodHndlList();
577 
578  resize<N>(hndl_list);
579  hndl_list[ePosition]
580  = SMethodDef(name, (PyCFunctionWithKeywords)HandleMethodKWArgs,
581  METH_VARARGS | METH_KEYWORDS, doc);
582  GetMethodList().push_back(func);
583 
584  return CClass<N + 1>();
585  }
586 
587  static PyObject* HandleMethodVarArgs( PyObject* self, PyObject* args )
588  {
590  T* obj = static_cast<T*>(self);
591 
592  try {
593  const CTuple args_tuple( args );
594 
595  return IncRefCount((obj->*func)(args_tuple));
596  }
597  /* CException is not defined here. We must translate all CException
598  * to CError in user's code.
599  catch (const CException& e) {
600  CError::SetString(e.what());
601  }
602  */
603  catch(const CError&) {
604  // An error message is already set by a previosly raised exception ...
605  return NULL;
606  }
607  catch(...) {
608  CError::SetString("Unknown error during executing of a method");
609  }
610 
611  // NULL means "error".
612  return NULL;
613  }
614 
615  static PyObject* HandleMethodKWArgs(PyObject* self, PyObject* args,
616  PyObject* kwargs)
617  {
618  const TMethodKWArgsFunc func = GetMethodList()[ePosition];
619  T* obj = static_cast<T*>(self);
620 
621  try {
622  const CTuple args_tuple(args);
623  CDict kwargs_dict;
624  if (kwargs != nullptr) {
625  kwargs_dict = kwargs;
626  }
627 
628  return IncRefCount((obj->*func)(args_tuple, kwargs_dict));
629  } catch (const CError&) {
630  return NULL;
631  }
632  catch (...) {
634  ("Unknown error during execution of a method");
635  }
636 
637  return NULL;
638  }
639 
640  private:
642  };
643 
644 #ifndef NCBI_COMPILER_ICC
645  // ICC 10 considers this declaration to be an error, and previous
646  // versions warn about it; all versions are happy to do without it.
647  template <size_t N> friend class CClass;
648 #endif
649 
650  static void Declare(
651  const char* name,
652  const char* descr = 0,
653  PyTypeObject* base = &PyBaseObject_Type
654  )
655  {
656  _ASSERT(sm_Base == NULL);
657  sm_Base = base;
658 
659  CExtType& type = GetType();
660 
661  type.SetName(name);
662  if ( descr ) {
663  type.SetDescription(descr);
664  }
665  type.SupportGetAttr(GetAttrImpl);
666  if (GetMethodHndlList().size() <= GetMethodList().size())
667  GetMethodHndlList().resize(GetMethodList().size() + 1);
668  type.tp_methods = &GetMethodHndlList().front();
669  }
670 
671  static void Declare(
672  const string& name,
673  const char* descr = 0,
674  PyTypeObject* base = &PyBaseObject_Type
675  )
676  {
677  static CSafeStaticPtr<string> safe_name;
678  *safe_name = name;
679  Declare(safe_name->c_str(), descr, base);
680  }
681 
682  static CClass<1> Def(const char* name, TMethodVarArgsFunc func, const char* doc = 0)
683  {
684  return CClass<0>().Def(name, func, doc);
685  }
686  static CClass<1> Def(const char* name, TMethodKWArgsFunc func,
687  const char* doc = nullptr)
688  {
689  return CClass<0>().Def(name, func, doc);
690  }
691 
692 public:
693  // Return a python object type.
694  static CExtType& GetType(void)
695  {
696  _ASSERT(sm_Base != NULL);
697  static CExtType obj_type( sizeof(T), deallocator, sm_Base );
698 
699  return obj_type;
700  }
701 
702  static CObject& GetTypeObject(void)
703  {
704  static CObject obj((PyObject*)&GetType(), pythonpp::eAcquireOwnership); // NCBI_FAKE_WARNING
705 
706  return obj;
707  }
708 
709  // Just delete an object ...
710  static void deallocator ( PyObject* obj )
711  {
712  delete static_cast<T*>( obj );
713  }
714 
715 protected:
716  static void PrepareForPython(CExtObject<T>* self)
717  {
718  // Borrowed reference.
719  PyObject_Init( self, GetType().GetObjType() );
720  }
721 
722 protected:
725 
726  void ROAttr( const string& name, long& value )
727  {
728  m_AttrList[ name ] = new bind::CLong( value );
729  }
730  void ROAttr( const string& name, string& value )
731  {
732  m_AttrList[ name ] = new bind::CString( value );
733  }
734  void ROAttr( const string& name, CObject& value )
735  {
737  }
738 
739  void RWAttr( const string& name, long& value )
740  {
741  m_AttrList[ name ] = new bind::CLong( value, bind::eReadWrite );
742  }
743  void RWAttr( const string& name, string& value )
744  {
746  }
747 
748 private:
749  static PyTypeObject* sm_Base;
750 
751 private:
752  typedef vector<SMethodDef> TMethodHndlList;
754 
756  {
757  return sm_MethodHndlList;
758  }
759 
760  static PyObject* GetAttrImpl( PyObject* self, char* name )
761  {
762  _ASSERT( self != NULL );
763  CExtObject<T>* obj_ptr = static_cast<CExtObject<T>* >( self );
764  TAttrList::const_iterator citer = obj_ptr->m_AttrList.find( name );
765 
766  if ( citer != obj_ptr->m_AttrList.end() ) {
767  // Return an attribute value ...
768  return citer->second->Get();
769  }
770 
771  // Classic python implementation ...
772  // It will do a linear search within the m_MethodHndlList table ...
773  return Py_FindMethod( &GetMethodHndlList().front(), self, name );
774  }
775 
776 private:
777  typedef vector<SFunct> TMethodList;
779 
781  {
782  return sm_MethodList;
783  }
784 };
785 
786 template <class T> PyTypeObject* CExtObject<T>::sm_Base = NULL;
788 template <class T> typename CExtObject<T>::TMethodList CExtObject<T>::sm_MethodList;
789 
790 //////////////////////////////////////////////////////////////////////////
791 template <class T>
792 class CExtModule : public PyObject
793 {
794 public:
795  CExtModule(const char* name, const char* descr = 0)
796  : m_Module(NULL)
797  {
798  m_Module = Py_InitModule4(
799  const_cast<char*>(name),
801  const_cast<char*>(descr),
802  this,
803  PYTHON_API_VERSION);
804  if ( !m_Module ) {
805  throw CSystemError("Cannot initialize module");
806  }
807  }
809  {
810  }
811 
812 public:
813  typedef CObject (T::*TMethodVarArgsFunc)( const CTuple& args );
814  /// Workaround for GCC 2.95
815  struct SFunct
816  {
818  : m_Funct(funct)
819  {
820  }
821 
822  operator TMethodVarArgsFunc(void) const
823  {
824  return m_Funct;
825  }
826 
828  };
829 
830  // A helper class for generating functions ...
831  template<size_t N = 0>
832  class CClass
833  {
834  public:
835  CClass(void)
836  {
837  // Finalyze method definition ...
838  GetMethodHndlList().push_back( SMethodDef() );
839  }
840 
841  public:
842  CClass<N + 1> Def(const char* name, TMethodVarArgsFunc func, const char* doc = 0)
843  {
844  // Prepare data for python ...
845  GetMethodHndlList()[ePosition] = SMethodDef(name, HandleMethodVarArgs, METH_VARARGS, doc);
846 
847  // Prepare data for our handler ...
848  GetMethodList().push_back(func);
849 
850  return CClass<N + 1>();
851  }
852  static PyObject* HandleMethodVarArgs( PyObject* self, PyObject* args )
853  {
855  T* obj = static_cast<T*>(self);
856 
857  try {
858  const CTuple args_tuple( args );
859 
860  return IncRefCount((obj->*func)(args_tuple));
861  }
862  catch(const CError&) {
863  // An error message is already set by an exception ...
864  return NULL;
865  }
866  catch(...) {
867  CError::SetString("Unknown error during executing of a method");
868  }
869  // NULL means "error".
870  return NULL;
871  }
872 
873  private:
874  enum {ePosition = N};
875  };
876 
877  static CClass<1> Def(const char* name, TMethodVarArgsFunc func, const char* doc = 0)
878  {
879  return CClass<0>().Def(name, func, doc);
880  }
881 
882 public:
883  // Return a python object type.
884  static CExtType& GetType(void)
885  {
886  static CExtType obj_type( sizeof(T), deallocator );
887 
888  return obj_type;
889  }
890 
891  // Just delete an object ...
892  static void deallocator ( PyObject* obj )
893  {
894  delete static_cast<T*>( obj );
895  }
896 
897 private:
898  typedef vector<SMethodDef> TMethodHndlList;
900 
902  {
903  return sm_MethodHndlList;
904  }
905 
906  static PyObject* GetAttrImpl( PyObject* self, char* name )
907  {
908  // Classic python implementation ...
909  // It will do a linear search within the m_MethodHndlList table ...
910  return Py_FindMethod(&GetMethodHndlList().front(), self, name);
911  }
912 
913 private:
914  typedef vector<SFunct> TMethodList;
916 
918  {
919  return sm_MethodList;
920  }
921 
922 private:
923  PyObject* m_Module;
924 };
925 
927 template <class T> typename CExtModule<T>::TMethodList CExtModule<T>::sm_MethodList;
928 
929 
930 ///////////////////////////////////////////////////////////////////////////////
931 // New development
932 ///////////////////////////////////////////////////////////////////////////////
933 
934 // An attempt to wrap a module ...
936 {
937 public:
938  static void Declare(const string& name, PyMethodDef* methods,
939  inquiry cleanup_hook = NULL);
940 
941 public:
942  static const string& GetName(void)
943  {
944  return m_Name;
945  }
946  static PyObject* GetPyModule(void)
947  {
948  return m_Module;
949  }
950  static void AddConstValue( const string& name, PyObject* value );
951  static void AddConst( const string& name, const string& value );
952  static void AddConst( const string& name, long value );
953 
954 private:
955  static string m_Name;
956  static PyObject* m_Module;
957 #if PY_MAJOR_VERSION >= 3
958  static struct PyModuleDef m_ModuleDef;
959 #endif
960 };
961 
962 string CModuleExt::m_Name;
963 PyObject* CModuleExt::m_Module = NULL;
964 
965 #if PY_MAJOR_VERSION >= 3
966 struct PyModuleDef CModuleExt::m_ModuleDef = {
967  PyModuleDef_HEAD_INIT,
968  "", // m_name
969  "", // m_doc
970  -1, // m_size
971  NULL, // m_methods
972  NULL, // m_reload
973  NULL, // m_traverse
974  NULL, // m_clear
975  NULL // m_free
976 };
977 #endif
978 
979 void
980 CModuleExt::Declare(const string& name, PyMethodDef* methods,
981  inquiry cleanup_hook)
982 {
983  _ASSERT( m_Module == NULL );
984 
985  m_Name = name;
986 #if PY_MAJOR_VERSION >= 3
987  m_ModuleDef.m_name = strdup(name.c_str());
988  m_ModuleDef.m_methods = methods;
989  m_ModuleDef.m_clear = cleanup_hook;
990  m_Module = PyModule_Create(&m_ModuleDef);
991 #else
992  m_Module = Py_InitModule( const_cast<char*>( name.c_str() ), methods );
993 #endif
995 }
996 
997 void
998 CModuleExt::AddConstValue( const string& name, PyObject* value )
999 {
1000  CError::Check( value );
1001  if ( PyModule_AddObject(m_Module, const_cast<char*>(name.c_str()), value ) == -1 ) {
1002  throw CSystemError("Failed to add a constant value to a module");
1003  }
1004 }
1005 
1006 void
1007 CModuleExt::AddConst( const string& name, const string& value )
1008 {
1009 #if PY_MAJOR_VERSION >= 3
1010  PyObject* py_value
1011  = PyUnicode_FromStringAndSize(value.data(), value.size());
1012 #else
1013  PyObject* py_value
1014  = PyString_FromStringAndSize( value.data(), value.size() );
1015 #endif
1016  CError::Check( py_value );
1017  AddConstValue( name, py_value );
1018 }
1019 
1020 void
1021 CModuleExt::AddConst( const string& name, long value )
1022 {
1023  PyObject* py_value = PyLong_FromLong( value );
1024  CError::Check( py_value );
1025  AddConstValue( name, py_value );
1026 }
1027 
1028 ///////////////////////////////////
1029 // User-defined exceptions
1030 ///////////////////////////////////
1031 
1032 template <class T, class B = CStandardError>
1033 class CUserError : public B
1034 {
1035 public:
1037  {
1038  }
1039  CUserError(const string& msg)
1040  : B( msg, GetPyException() )
1041  {
1042  }
1043 
1044 protected:
1045  CUserError(const string& msg, PyObject* err_type)
1046  : B(msg, err_type)
1047  {
1048  }
1049 
1050 public:
1051  static void Declare(const string& name)
1052  {
1053  _ASSERT( m_Exception == NULL );
1055  const string full_name = CModuleExt::GetName() + "." + name;
1056  m_Exception = PyErr_NewException( const_cast<char*>(full_name.c_str()), B::GetPyException(), NULL );
1058  if ( PyModule_AddObject( CModuleExt::GetPyModule(), const_cast<char*>(name.c_str()), m_Exception ) == -1 ) {
1059  throw CSystemError( "Unable to add an object to a module" );
1060  }
1061  }
1062  static void Declare(const string& name, const pythonpp::CDict& dict)
1063  {
1064  _ASSERT( m_Exception == NULL );
1066  const string full_name = CModuleExt::GetName() + "." + name;
1067  m_Exception = PyErr_NewException(const_cast<char*>(full_name.c_str()), B::GetPyException(), dict);
1069  if ( PyModule_AddObject( CModuleExt::GetPyModule(), const_cast<char*>(name.c_str()), m_Exception ) == -1 ) {
1070  throw CSystemError( "Unable to add an object to a module" );
1071  }
1072  }
1073 
1074 public:
1075  static PyObject* GetPyException(void)
1076  {
1077  _ASSERT( m_Exception );
1078  return m_Exception;
1079  }
1080 
1081 private:
1082  static PyObject* m_Exception;
1083 };
1084 
1085 template <class T, class B> PyObject* CUserError<T, B>::m_Exception(NULL);
1086 
1087 
1088 /// CThreadingGuard -- "Anti-guard" for Python's global interpreter
1089 /// lock, which it temporarily releases to allow other threads to
1090 /// proceed in parallel with blocking operations that don't involve
1091 /// Python-specific state.
1092 /// @note Does NOT support recursive usage at present.
1094 public:
1095  CThreadingGuard() : m_State(sm_MayRelease ? PyEval_SaveThread() : NULL) { }
1096  ~CThreadingGuard() { if (m_State != NULL) PyEval_RestoreThread(m_State); }
1097 
1098  static void SetMayRelease(bool may_release)
1099  { sm_MayRelease = may_release; }
1100 
1101 private:
1102  static bool sm_MayRelease;
1103  PyThreadState* m_State;
1104 };
1105 
1106 #ifdef PYTHONPP_DEFINE_GLOBALS
1107 bool CThreadingGuard::sm_MayRelease = false;
1108 #endif
1109 
1110 
1112 public:
1113  CStateGuard() : m_State(PyGILState_Ensure()) { }
1114  ~CStateGuard() { PyGILState_Release(m_State); }
1115 
1116 private:
1117  PyGILState_STATE m_State;
1118 };
1119 
1120 } // namespace pythonpp
1121 
1123 
1124 #endif // PYTHONPP_EXT_H
1125 
CSafeStaticPtr<>::
const_iterator end() const
Definition: map.hpp:152
const_iterator find(const key_type &key) const
Definition: map.hpp:153
Definition: map.hpp:338
static void SetString(const string &msg)
static void Check(void)
static PyObject * HandleMethodVarArgs(PyObject *self, PyObject *args)
CClass< N+1 > Def(const char *name, TMethodVarArgsFunc func, const char *doc=0)
static TMethodHndlList sm_MethodHndlList
CExtModule(const char *name, const char *descr=0)
static TMethodList sm_MethodList
CObject(T::* TMethodVarArgsFunc)(const CTuple &args)
vector< SMethodDef > TMethodHndlList
static PyObject * GetAttrImpl(PyObject *self, char *name)
static void deallocator(PyObject *obj)
static CClass< 1 > Def(const char *name, TMethodVarArgsFunc func, const char *doc=0)
vector< SFunct > TMethodList
static TMethodList & GetMethodList(void)
static TMethodHndlList & GetMethodHndlList(void)
static CExtType & GetType(void)
CClass< N+1 > Def(const char *name, TMethodVarArgsFunc func, const char *doc=0)
static PyObject * HandleMethodKWArgs(PyObject *self, PyObject *args, PyObject *kwargs)
CClass< N+1 > Def(const char *name, TMethodKWArgsFunc func, const char *doc=nullptr)
static PyObject * HandleMethodVarArgs(PyObject *self, PyObject *args)
static CClass< 1 > Def(const char *name, TMethodKWArgsFunc func, const char *doc=nullptr)
vector< SFunct > TMethodList
static TMethodHndlList sm_MethodHndlList
static void Declare(const string &name, const char *descr=0, PyTypeObject *base=&PyBaseObject_Type)
void ROAttr(const string &name, CObject &value)
static TMethodHndlList & GetMethodHndlList(void)
void RWAttr(const string &name, long &value)
CObject(T::* TMethodKWArgsFunc)(const CTuple &args, const CDict &kwargs)
void RWAttr(const string &name, string &value)
map< string, AutoPtr< bind::CBase > > TAttrList
vector< SMethodDef > TMethodHndlList
static PyTypeObject * sm_Base
static PyObject * GetAttrImpl(PyObject *self, char *name)
static void Declare(const char *name, const char *descr=0, PyTypeObject *base=&PyBaseObject_Type)
static TMethodList sm_MethodList
void ROAttr(const string &name, long &value)
static TMethodList & GetMethodList(void)
static CExtType & GetType(void)
static void PrepareForPython(CExtObject< T > *self)
static CClass< 1 > Def(const char *name, TMethodVarArgsFunc func, const char *doc=0)
static void deallocator(PyObject *obj)
static CObject & GetTypeObject(void)
CObject(T::* TMethodVarArgsFunc)(const CTuple &args)
void ROAttr(const string &name, string &value)
void SetDescription(const char *descr)
void SetName(const char *name)
void SupportGetAttr(getattrfunc func)
CExtType(size_t basic_size, destructor dr=standard_dealloc, PyTypeObject *base=&PyBaseObject_Type)
PyTypeObject * GetObjType(void)
const PyTypeObject * GetObjType(void) const
static const string & GetName(void)
static void AddConst(const string &name, const string &value)
static void AddConstValue(const string &name, PyObject *value)
static PyObject * m_Module
static void Declare(const string &name, PyMethodDef *methods, inquiry cleanup_hook=NULL)
static string m_Name
static PyObject * GetPyModule(void)
PyObject * Get(void) const
PyGILState_STATE m_State
CThreadingGuard – "Anti-guard" for Python's global interpreter lock, which it temporarily releases to...
static void SetMayRelease(bool may_release)
static void Declare(const string &name)
static void Declare(const string &name, const pythonpp::CDict &dict)
static PyObject * m_Exception
static PyObject * GetPyException(void)
CUserError(const string &msg, PyObject *err_type)
CUserError(const string &msg)
bool IsReadOnly(void) const
CBase(EBindType type=eReadOnly)
virtual PyObject * Get(void) const =0
virtual void SetInternal(PyObject *value) const
void Set(PyObject *value) const
CLong(long &value, EBindType type=eReadOnly)
virtual PyObject * Get(void) const
virtual void SetInternal(PyObject *value) const
virtual PyObject * Get(void) const
CObject(T &obj, TGetFunc get, TSetFunc set=NULL)
void(T::* TSetFunc)(PyObject *value)
PyObject *(T::* TGetFunc)(void) const
virtual void SetInternal(PyObject *value) const
virtual void SetInternal(PyObject *value) const
CString(string &value, EBindType type=eReadOnly)
virtual PyObject * Get(void) const
Definition: set.hpp:45
static uch flags
#define T(s)
Definition: common.h:230
static int type
Definition: getdata.c:31
string
Definition: cgiapp.hpp:690
#define NULL
Definition: ncbistd.hpp:225
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
static CStringUTF8 AsUTF8(const CTempString &src, EEncoding encoding, EValidate validate=eNoValidate)
Convert into UTF8 from a C/C++ string.
Definition: ncbistr.hpp:3883
<!DOCTYPE HTML >< html > n< header > n< title > PubSeq Gateway Help Page</title > n< style > n table
int i
constexpr auto front(list< Head, As... >, T=T()) noexcept -> Head
void destructor(T1 *p)
Definition: tree_msvc7.hpp:72
const struct ncbi::grid::netcache::search::fields::SIZE size
void resize(vector< SMethodDef > &container)
PyObject * IncRefCount(PyObject *obj)
bool operator==(const CObject &l, const CExtType &r)
void standard_dealloc(PyObject *obj)
void DoNotDeallocate(void *)
void resize< 0 >(vector< SMethodDef > &)
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1227
int strcmp(const char *str1, const char *str2)
Definition: odbc_utils.hpp:160
#define strdup
Definition: ncbi_ansi_ext.h:70
Static variables safety - create on demand, destroy on application termination.
double r(size_t dimension_, const Int4 *score_, const double *prob_, double theta_)
#define U
static BOOL utf
Definition: pcre2grep.c:291
#define Py_SET_TYPE(ob, type)
static void _Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt)
static void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size)
#define Py_SET_REFCNT(ob, refcnt)
#define Py_SET_SIZE(ob, size)
static void _Py_SET_TYPE(PyObject *ob, PyTypeObject *type)
#define B
static SLJIT_INLINE sljit_ins l(sljit_gpr r, sljit_s32 d, sljit_gpr x, sljit_gpr b)
static SLJIT_INLINE sljit_ins msg(sljit_gpr r, sljit_s32 d, sljit_gpr x, sljit_gpr b)
Workaround for GCC 2.95.
SFunct(const TMethodVarArgsFunc &funct)
TMethodVarArgsFunc m_Funct
Workaround for GCC 2.95.
SFunct(const TMethodVarArgsFunc &funct)
TMethodVarArgsFunc m_Funct
SFunct(const TMethodKWArgsFunc &funct)
Introduces constructor methods for a python PyMethodDef structure ...
SMethodDef & operator=(const SMethodDef &other)
SMethodDef(const char *name, PyCFunctionWithKeywords func, int flags=METH_VARARGS|METH_KEYWORDS, const char *doc=nullptr)
SMethodDef(const char *name, PyCFunction func, int flags=1, const char *doc=NULL)
SMethodDef(const SMethodDef &other)
Definition: type.c:6
#define _ASSERT
#define N
Definition: crc32.c:57
Modified on Fri Sep 20 14:57:33 2024 by modify_doxy.py rev. 669887