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  _Pragma( "GCC diagnostic ignored \"-Wc99-designator\"")
77  #else
78  #define BEGIN_ALLOW_DESIGNATED_INITIALIZERS \
79  _Pragma( "GCC diagnostic push" ) \
80  _Pragma( "GCC diagnostic ignored \"-Wc99-designator\"")
81  #endif
82 #else
83  #define BEGIN_ALLOW_DESIGNATED_INITIALIZERS \
84  _Pragma( "GCC diagnostic push" ) \
85  _Pragma( "GCC diagnostic ignored \"-Wpedantic\"" ) \
86  _Pragma( "GCC diagnostic ignored \"-Wmissing-field-initializers\"" )
87 #endif
88 
92 #define END_ALLOW_DESIGNATED_INITIALIZERS \
93  _Pragma( "GCC diagnostic pop" )
94 
95 // UNCRUSTIFY-ON
97 
98 namespace LvArray
99 {
100 namespace python
101 {
102 namespace internal
103 {
104 
109 void xincref( PyObject * const obj );
110 
115 void xdecref( PyObject * const obj );
116 
123 bool isInstanceOf( PyObject * const obj, PyTypeObject * type );
124 
125 } // namespace internal
126 
131 enum class PyModify
132 {
133  READ_ONLY = 0,
134  MODIFIABLE = 1,
135  RESIZEABLE = 2,
136 };
137 
143 template< typename T = PyObject >
145 {
146 public:
147 
151  PyObjectRef() = default;
152 
158  PyObjectRef( T * const src ):
159  m_object( src )
160  {}
161 
167  PyObjectRef( PyObjectRef const & src )
168  { *this = src; }
169 
176  { *this = std::move( src ); }
177 
182  { internal::xdecref( reinterpret_cast< PyObject * >( m_object ) ); }
183 
191  {
192  m_object = src.m_object;
193  internal::xincref( reinterpret_cast< PyObject * >( src.m_object ) );
194  return *this;
195  }
196 
204  {
205  m_object = src.m_object;
206  src.m_object = nullptr;
207  return *this;
208  }
209 
216  PyObjectRef & operator=( PyObject * src )
217  {
218  internal::xdecref( reinterpret_cast< PyObject * >( m_object ) );
219 
220  m_object = src;
221  return *this;
222  }
223 
228  operator T *()
229  { return m_object; }
230 
235  T * get() const
236  { return m_object; }
237 
244  T * * getAddress()
245  { return &m_object; }
246 
252  T * release()
253  {
254  T * const ret = m_object;
255  m_object = nullptr;
256  return ret;
257  }
258 
259 private:
261  T * m_object = nullptr;
262 };
263 
271 template< typename T >
272 T * convert( PyObject * const obj, PyTypeObject * const type )
273 {
274  if( internal::isInstanceOf( obj, type ) )
275  {
276  return reinterpret_cast< T * >( obj );
277  }
278 
279  return nullptr;
280 }
281 
289 bool addTypeToModule( PyObject * const module,
290  PyTypeObject * const type,
291  char const * const typeName );
292 
298 PyObject * create( std::string const & value );
299 
307 PyObject * createPyListOfStrings( std::string const * const strptr, long long const size );
308 
315 inline PyObject * create( std::vector< std::string > const & vec )
316 { return createPyListOfStrings( vec.data(), integerConversion< long long >( vec.size() ) ); }
317 
327 class PythonError : public std::runtime_error
328 {
329 public:
330  PythonError():
331  std::runtime_error( LvArray::system::stackTrace( true ) )
332  {}
333 };
334 
335 } // namespace python
336 } // namespace LvArray
T * release()
Return the address of the managed object and release ownership.
Definition: pythonHelpers.hpp:252
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:131
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:216
T * m_object
A pointer to the manged object.
Definition: pythonHelpers.hpp:261
PyObjectRef(PyObjectRef &&src)
Steal a reference from src.
Definition: pythonHelpers.hpp:175
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:181
Base class for all C++ exceptions related to Python.
Definition: pythonHelpers.hpp:327
PyObjectRef & operator=(PyObjectRef const &src)
Create a new reference to src.
Definition: pythonHelpers.hpp:190
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:144
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:272
PyObjectRef & operator=(PyObjectRef &&src)
Steal a reference from src.
Definition: pythonHelpers.hpp:203
PyObjectRef(T *const src)
Take ownership of a reference to src.
Definition: pythonHelpers.hpp:158
T ** getAddress()
Return the address of the pointer to the manged object.
Definition: pythonHelpers.hpp:244
PyObjectRef(PyObjectRef const &src)
Create a new reference to src.
Definition: pythonHelpers.hpp:167