LvArray
pythonHelpers.hpp
Go to the documentation of this file.
1 /*
2  *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3  * Copyright (c) 2019, Lawrence Livermore National Security, LLC.
4  *
5  * Produced at the Lawrence Livermore National Laboratory
6  *
7  * LLNL-CODE-746361
8  *
9  * All rights reserved. See COPYRIGHT for details.
10  *
11  * This file is part of the GEOSX Simulation Framework.
12  *
13  * GEOSX is a free software; you can redistribute it and/or modify it under
14  * the terms of the GNU Lesser General Public License (as published by the
15  * Free Software Foundation) version 2.1 dated February 1999.
16  *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17  */
18 
19 #pragma once
20 
25 // Source includes
27 #include "../system.hpp"
28 #include "../Macros.hpp"
29 #include "../limits.hpp"
30 
31 // system includes
32 #include <vector>
33 #include <stdexcept>
34 
42 #if defined(PyObject_HEAD)
43 #define PYTHON_ERROR_IF( CONDITION, TYPE, MSG, RET ) \
44  do \
45  { \
46  if( CONDITION ) \
47  { \
48  std::ostringstream __oss; \
49  __oss << "***** ERROR\n"; \
50  __oss << "***** LOCATION: " LOCATION "\n"; \
51  __oss << "***** Controlling expression (should be false): " STRINGIZE( EXP ) "\n"; \
52  __oss << MSG << "\n"; \
53  __oss << LvArray::system::stackTrace( true ); \
54  PyErr_SetString( TYPE, __oss.str().c_str() ); \
55  return RET; \
56  } \
57  } while( false )
58 #else
59 #define PYTHON_ERROR_IF( CONDITION, TYPE, MSG, RET ) \
60  static_assert( false, "You are attempting to use PYTHON_ERROR_IF but haven't yet included Python.hpp" )
61 #endif
62 
64 // UNCRUSTIFY-OFF
66 
70 #if defined( __clang_version__ )
71  #if defined( __CUDACC__ )
72  #define BEGIN_ALLOW_DESIGNATED_INITIALIZERS \
73  _Pragma( "GCC diagnostic push" ) \
74  _Pragma( "GCC diagnostic ignored \"-Wc99-extensions\"") \
75  _Pragma( "GCC diagnostic ignored \"-Wgnu-designator\"")
76  #if __has_warning( "-Wc99-designator" )
77  _Pragma( "GCC diagnostic ignored \"-Wc99-designator\"")
78  #endif
79  #else
80  #define BEGIN_ALLOW_DESIGNATED_INITIALIZERS \
81  _Pragma( "GCC diagnostic push" ) \
82  _Pragma( "GCC diagnostic ignored \"-Wc99-designator\"")
83  #endif
84 #elif defined( __GNUC__ )
85  #define BEGIN_ALLOW_DESIGNATED_INITIALIZERS \
86  _Pragma( "GCC diagnostic push" ) \
87  _Pragma( "GCC diagnostic ignored \"-Wpedantic\"" ) \
88  _Pragma( "GCC diagnostic ignored \"-Wmissing-field-initializers\"" )
89  #if __GNUC__ > 8
90  _Pragma( "GCC diagnostic ignored \"-Wc++20-extensions\"")
91  #endif
92 #endif
93 
97 #define END_ALLOW_DESIGNATED_INITIALIZERS \
98  _Pragma( "GCC diagnostic pop" )
99 
100 // UNCRUSTIFY-ON
102 
103 namespace LvArray
104 {
105 namespace python
106 {
107 namespace internal
108 {
109 
114 void xincref( PyObject * const obj );
115 
120 void xdecref( PyObject * const obj );
121 
128 bool isInstanceOf( PyObject * const obj, PyTypeObject * type );
129 
130 } // namespace internal
131 
136 enum class PyModify
137 {
138  READ_ONLY = 0,
139  MODIFIABLE = 1,
140  RESIZEABLE = 2,
141 };
142 
148 template< typename T = PyObject >
150 {
151 public:
152 
156  PyObjectRef() = default;
157 
163  PyObjectRef( T * const src ):
164  m_object( src )
165  {}
166 
172  PyObjectRef( PyObjectRef const & src )
173  { *this = src; }
174 
181  { *this = std::move( src ); }
182 
187  { internal::xdecref( reinterpret_cast< PyObject * >( m_object ) ); }
188 
196  {
197  m_object = src.m_object;
198  internal::xincref( reinterpret_cast< PyObject * >( src.m_object ) );
199  return *this;
200  }
201 
209  {
210  m_object = src.m_object;
211  src.m_object = nullptr;
212  return *this;
213  }
214 
221  PyObjectRef & operator=( PyObject * src )
222  {
223  internal::xdecref( reinterpret_cast< PyObject * >( m_object ) );
224 
225  m_object = src;
226  return *this;
227  }
228 
233  operator T *()
234  { return m_object; }
235 
240  T * get() const
241  { return m_object; }
242 
249  T * * getAddress()
250  { return &m_object; }
251 
257  T * release()
258  {
259  T * const ret = m_object;
260  m_object = nullptr;
261  return ret;
262  }
263 
264 private:
266  T * m_object = nullptr;
267 };
268 
276 template< typename T >
277 T * convert( PyObject * const obj, PyTypeObject * const type )
278 {
279  if( internal::isInstanceOf( obj, type ) )
280  {
281  return reinterpret_cast< T * >( obj );
282  }
283 
284  return nullptr;
285 }
286 
294 bool addTypeToModule( PyObject * const module,
295  PyTypeObject * const type,
296  char const * const typeName );
297 
303 PyObject * create( std::string const & value );
304 
312 PyObject * createPyListOfStrings( std::string const * const strptr, long long const size );
313 
320 inline PyObject * create( std::vector< std::string > const & vec )
321 { return createPyListOfStrings( vec.data(), integerConversion< long long >( vec.size() ) ); }
322 
332 class PythonError : public std::runtime_error
333 {
334 public:
335  PythonError():
336  std::runtime_error( LvArray::system::stackTrace( true ) )
337  {}
338 };
339 
340 } // namespace python
341 } // namespace LvArray
T * release()
Return the address of the managed object and release ownership.
Definition: pythonHelpers.hpp:257
std::enable_if_t< internal::canExportToNumpy< T >, PyObject *> create(T &value)
Create a NumPy 1D array of length 1 containing the scalar value.
Definition: numpyHelpers.hpp:147
PyModify
An enumeration of the various access policies for Python objects.
Definition: pythonHelpers.hpp:136
PyObject * createPyListOfStrings(std::string const *const strptr, long long const size)
Create and return a Python list of strings from an array of std::strings. The Python strings will be ...
Definition: pythonHelpers.cpp:85
PyObjectRef & operator=(PyObject *src)
Decrease the reference count to the current object and take ownership of a new reference.
Definition: pythonHelpers.hpp:221
T * m_object
A pointer to the manged object.
Definition: pythonHelpers.hpp:266
PyObjectRef(PyObjectRef &&src)
Steal a reference from src.
Definition: pythonHelpers.hpp:180
std::string stackTrace(bool const location)
Return a demangled stack trace of the last 25 frames.
Definition: system.cpp:361
~PyObjectRef()
Destructor, decreases the reference count.
Definition: pythonHelpers.hpp:186
Base class for all C++ exceptions related to Python.
Definition: pythonHelpers.hpp:332
PyObjectRef & operator=(PyObjectRef const &src)
Create a new reference to src.
Definition: pythonHelpers.hpp:195
Forward declarations of Python Objects.
bool addTypeToModule(PyObject *const module, PyTypeObject *const type, char const *const typeName)
Add the Python type type to the module module.
Definition: pythonHelpers.cpp:61
A class that manages an owned Python reference with RAII semantics.
Definition: pythonHelpers.hpp:149
The top level namespace.
Definition: Array.hpp:24
T * convert(PyObject *const obj, PyTypeObject *const type)
Return obj casted to T if obj is an instance of type or nullptr if it is not.
Definition: pythonHelpers.hpp:277
PyObjectRef & operator=(PyObjectRef &&src)
Steal a reference from src.
Definition: pythonHelpers.hpp:208
PyObjectRef(T *const src)
Take ownership of a reference to src.
Definition: pythonHelpers.hpp:163
T ** getAddress()
Return the address of the pointer to the manged object.
Definition: pythonHelpers.hpp:249
PyObjectRef(PyObjectRef const &src)
Create a new reference to src.
Definition: pythonHelpers.hpp:172