All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
pyUtils.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef PXR_BASE_TF_PY_UTILS_H
25 #define PXR_BASE_TF_PY_UTILS_H
26 
29 
30 #include "pxr/pxr.h"
31 
32 #include "pxr/base/tf/refPtr.h"
33 #include "pxr/base/tf/weakPtr.h"
35 #include "pxr/base/tf/preprocessorUtilsLite.h"
36 #include "pxr/base/tf/py3Compat.h"
38 #include "pxr/base/tf/pyLock.h"
39 #include "pxr/base/tf/api.h"
40 
41 #include <functional>
42 #include <typeinfo>
43 #include <string>
44 #include <vector>
45 
46 #include <boost/python/dict.hpp>
47 #include <boost/python/extract.hpp>
48 #include <boost/python/handle.hpp>
49 #include <boost/python/object.hpp>
50 #include <boost/python/type_id.hpp>
51 
52 PXR_NAMESPACE_OPEN_SCOPE
53 
59 #define TF_PY_REPR_PREFIX \
60  std::string(TF_PP_STRINGIZE(MFB_PACKAGE_MODULE) ".")
61 
63 TF_API bool TfPyIsInitialized();
64 
67 TF_API void TfPyThrowIndexError(std::string const &msg);
68 
71 TF_API void TfPyThrowRuntimeError(std::string const &msg);
72 
75 TF_API void TfPyThrowStopIteration(std::string const &msg);
76 
79 TF_API void TfPyThrowKeyError(std::string const &msg);
80 
83 TF_API void TfPyThrowValueError(std::string const &msg);
84 
87 TF_API void TfPyThrowTypeError(std::string const &msg);
88 
90 TF_API bool TfPyIsNone(boost::python::object const &obj);
91 
93 TF_API bool TfPyIsNone(boost::python::handle<> const &obj);
94 
95 // Helper for \c TfPyObject().
96 TF_API void Tf_PyObjectError(bool printError);
97 
101 template <typename T>
102 boost::python::object TfPyObject(T const &t, bool complainOnFailure = true) {
103  // initialize python if it isn't already, so at least we can try to return
104  // an object
105  if (!TfPyIsInitialized()) {
106  TF_CODING_ERROR("Called TfPyObject without python being initialized!");
107  TfPyInitialize();
108  }
109 
110  TfPyLock pyLock;
111 
112  // Will only be able to return objects which have been wrapped.
113  // Returns None otherwise
114  try {
115  return boost::python::object(t);
116  } catch (boost::python::error_already_set const &) {
117  Tf_PyObjectError(complainOnFailure);
118  return boost::python::object();
119  }
120 }
121 
122 inline
123 boost::python::object TfPyObject(PyObject* t, bool complainOnFailure = true) {
124  TfPyLock pyLock;
125  return boost::python::object(boost::python::handle<>(t));
126 }
127 
131 TF_API std::string TfPyObjectRepr(boost::python::object const &t);
132 
137 template <typename T>
138 std::string TfPyRepr(T const &t) {
139  if (!TfPyIsInitialized())
140  return "<python not initialized>";
141  TfPyLock lock;
142  return TfPyObjectRepr(TfPyObject(t));
143 }
144 
146 template <typename T>
147 std::string TfPyRepr(const std::vector<T> &v) {
148  std::string result("[");
149  typename std::vector<T>::const_iterator i = v.begin();
150  if (i != v.end()) {
151  result += TfPyRepr(*i);
152  ++i;
153  }
154  while (i != v.end()) {
155  result += ", " + TfPyRepr(*i);
156  ++i;
157  }
158  result += "]";
159  return result;
160 }
161 
165 TF_API
166 boost::python::object
168  std::string const &expr,
169  boost::python::dict const &extraGlobals = boost::python::dict());
170 
173 TF_API
174 int64_t
175 TfPyNormalizeIndex(int64_t index, uint64_t size, bool throwError = false);
176 
178 TF_API std::string TfPyGetClassName(boost::python::object const &obj);
179 
180 
183 TF_API boost::python::object
184 TfPyGetClassObject(std::type_info const &type);
185 
188 template <typename T>
189 boost::python::object
191  return TfPyGetClassObject(typeid(T));
192 }
193 
194 TF_API
195 void
196 Tf_PyWrapOnceImpl(boost::python::type_info const &,
197  std::function<void()> const&,
198  bool *);
199 
207 template <typename T>
208 void
209 TfPyWrapOnce(std::function<void()> const &wrapFunc)
210 {
211  // Don't try to wrap if python isn't initialized.
213  return;
214  }
215 
216  static bool isTypeWrapped = false;
217  if (isTypeWrapped) {
218  return;
219  }
220 
221  Tf_PyWrapOnceImpl(boost::python::type_id<T>(), wrapFunc, &isTypeWrapped);
222 }
223 
228 TF_API
229 void Tf_PyLoadScriptModule(std::string const &name);
230 
232 template <class Map>
233 boost::python::dict TfPyCopyMapToDictionary(Map const &map) {
234  TfPyLock lock;
235  boost::python::dict d;
236  for (typename Map::const_iterator i = map.begin(); i != map.end(); ++i)
237  d[i->first] = i->second;
238  return d;
239 }
240 
241 template<class Seq>
242 boost::python::list TfPyCopySequenceToList(Seq const &seq) {
243  TfPyLock lock;
244  boost::python::list l;
245  for (typename Seq::const_iterator i = seq.begin();
246  i != seq.end(); ++i)
247  l.append(*i);
248  return l;
249 }
250 
255 template <class Seq>
256 boost::python::object TfPyCopySequenceToSet(Seq const &seq) {
257  TfPyLock lock;
258  boost::python::handle<> set{boost::python::allow_null(PySet_New(nullptr))};
259  if (!set) {
260  boost::python::throw_error_already_set();
261  }
262  for (auto const& item : seq) {
263  boost::python::object obj(item);
264  if (PySet_Add(set.get(), obj.ptr()) == -1) {
265  boost::python::throw_error_already_set();
266  }
267  }
268  return boost::python::object(set);
269 }
270 
271 template<class Seq>
272 boost::python::tuple TfPyCopySequenceToTuple(Seq const &seq) {
273  return boost::python::tuple(TfPyCopySequenceToList(seq));
274 }
275 
282 TF_API
283 boost::python::object TfPyCopyBufferToByteArray(const char* buffer, size_t size);
284 
289 TF_API
290 std::vector<std::string> TfPyGetTraceback();
291 
296 TF_API
297 void TfPyGetStackFrames(std::vector<uintptr_t> *frames);
298 
300 TF_API
301 void TfPyDumpTraceback();
302 
324 TF_API
325 bool TfPySetenv(const std::string & name, const std::string & value);
326 
349 TF_API
350 bool TfPyUnsetenv(const std::string & name);
351 
352 // Private helper method to TfPyEvaluateAndExtract.
353 //
354 TF_API bool Tf_PyEvaluateWithErrorCheck(
355  const std::string & expr, boost::python::object * obj);
356 
360 template <typename T>
361 bool TfPyEvaluateAndExtract(const std::string & expr, T * t)
362 {
363  if (expr.empty())
364  return false;
365 
366  // Take the lock before doing anything with boost::python.
367  TfPyLock lock;
368 
369  // Though TfPyEvaluate (called by Tf_PyEvaluateWithErroCheck) takes the
370  // python lock, it is important that we lock before we initialize the
371  // boost::python::object, since it will increment and decrement ref counts
372  // outside of the call to TfPyEvaluate.
373  boost::python::object obj;
374  if (!Tf_PyEvaluateWithErrorCheck(expr, &obj))
375  return false;
376 
377  boost::python::extract<T> extractor(obj);
378 
379  if (!extractor.check())
380  return false;
381 
382  *t = extractor();
383 
384  return true;
385 }
386 
390 TF_API
391 void TfPyPrintError();
392 
393 PXR_NAMESPACE_CLOSE_SCOPE
394 
395 #endif // PXR_BASE_TF_PY_UTILS_H
TF_API bool TfPyIsInitialized()
Returns true if python is initialized.
TF_API std::string TfPyGetClassName(boost::python::object const &obj)
Return the name of the class of obj.
Compatibility code for supporting python 2 and 3.
TF_API boost::python::object TfPyEvaluate(std::string const &expr, boost::python::dict const &extraGlobals=boost::python::dict())
Evaluate python expression expr with all the known script modules imported under their standard names...
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition: diagnostic.h:85
TF_API bool TfPyUnsetenv(const std::string &name)
Remove an environment variable from os.environ.
TF_API void TfPyThrowValueError(std::string const &msg)
Raises a python ValueError and throws a C++ exception.
TF_API void TfPyThrowKeyError(std::string const &msg)
Raises a python KeyError and throws a C++ exception.
TF_API void TfPyPrintError()
Print a standard traceback to sys.stderr and clear the error indicator.
boost::python::object TfPyObject(T const &t, bool complainOnFailure=true)
Return a python object for the given C++ object, loading the appropriate wrapper code if necessary...
Definition: pyUtils.h:102
Pointer storage with deletion detection.
TF_API void TfPyThrowIndexError(std::string const &msg)
Raises a python IndexError and throws a C++ exception.
std::string TfPyRepr(T const &t)
Return repr(t).
Definition: pyUtils.h:138
TF_API void TfPyDumpTraceback()
Print the current python traceback to stdout.
TF_API void TfPyGetStackFrames(std::vector< uintptr_t > *frames)
Populates the vector passed in with pointers to strings containing the python interpreter stack frame...
TF_API boost::python::object TfPyCopyBufferToByteArray(const char *buffer, size_t size)
Create a python bytearray from an input buffer and size.
TF_API void TfPyThrowStopIteration(std::string const &msg)
Raises a python StopIteration exception and throws a C++ exception.
TF_API bool TfPyIsNone(boost::python::object const &obj)
Return true iff obj is None.
bool TfPyEvaluateAndExtract(const std::string &expr, T *t)
Safely evaluates expr and extracts the return object of type T.
Definition: pyUtils.h:361
Reference counting.
TF_API std::string TfPyObjectRepr(boost::python::object const &t)
Return repr(t).
TF_API void TfPyThrowTypeError(std::string const &msg)
Raises a python TypeError and throws a C++ exception.
TF_API boost::python::object TfPyGetClassObject(std::type_info const &type)
Return the python class object for type if type has been wrapped.
Python runtime utilities.
TF_API int64_t TfPyNormalizeIndex(int64_t index, uint64_t size, bool throwError=false)
Return a positive index in the range [0,size).
TF_API void TfPyInitialize()
Starts up the python runtime.
TF_API bool TfPySetenv(const std::string &name, const std::string &value)
Set an environment variable in os.environ.
boost::python::object TfPyCopySequenceToSet(Seq const &seq)
Create a python set from an iterable sequence.
Definition: pyUtils.h:256
TF_API void TfPyThrowRuntimeError(std::string const &msg)
Raises a python RuntimError and throws a C++ exception.
TF_API std::vector< std::string > TfPyGetTraceback()
Return a vector of strings containing the current python traceback.
Stripped down version of diagnostic.h that doesn&#39;t define std::string.
boost::python::dict TfPyCopyMapToDictionary(Map const &map)
Creates a python dictionary from a std::map.
Definition: pyUtils.h:233