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 TF_PYUTILS_H
25 #define TF_PYUTILS_H
26 
29 
30 #include "pxr/pxr.h"
31 
32 #include "pxr/base/tf/refPtr.h"
33 #include "pxr/base/tf/weakPtr.h"
34 #include "pxr/base/tf/diagnosticLite.h"
35 #include "pxr/base/tf/pyInterpreter.h"
36 #include "pxr/base/tf/pyLock.h"
37 #include "pxr/base/tf/api.h"
38 
39 #include <functional>
40 #include <typeinfo>
41 #include <string>
42 #include <vector>
43 
44 #include <boost/python/dict.hpp>
45 #include <boost/python/extract.hpp>
46 #include <boost/python/handle.hpp>
47 #include <boost/python/object.hpp>
48 #include <boost/python/type_id.hpp>
49 
50 PXR_NAMESPACE_OPEN_SCOPE
51 
57 #define TF_PY_REPR_PREFIX \
58  std::string(BOOST_PP_STRINGIZE(MFB_PACKAGE_MODULE) ".")
59 
61 TF_API bool TfPyIsInitialized();
62 
65 TF_API void TfPyThrowIndexError(std::string const &msg);
66 
69 TF_API void TfPyThrowRuntimeError(std::string const &msg);
70 
73 TF_API void TfPyThrowStopIteration(std::string const &msg);
74 
77 TF_API void TfPyThrowKeyError(std::string const &msg);
78 
81 TF_API void TfPyThrowValueError(std::string const &msg);
82 
85 TF_API void TfPyThrowTypeError(std::string const &msg);
86 
88 TF_API bool TfPyIsNone(boost::python::object const &obj);
89 
91 TF_API bool TfPyIsNone(boost::python::handle<> const &obj);
92 
93 // Helper for \c TfPyObject().
94 TF_API void Tf_PyObjectError(bool printError);
95 
99 template <typename T>
100 boost::python::object TfPyObject(T const &t, bool complainOnFailure = true) {
101  // initialize python if it isn't already, so at least we can try to return
102  // an object
103  if (!TfPyIsInitialized()) {
104  TF_CODING_ERROR("Called TfPyObject without python being initialized!");
105  TfPyInitialize();
106  }
107 
108  TfPyLock pyLock;
109 
110  // Will only be able to return objects which have been wrapped.
111  // Returns None otherwise
112  try {
113  return boost::python::object(t);
114  } catch (boost::python::error_already_set const &) {
115  Tf_PyObjectError(complainOnFailure);
116  return boost::python::object();
117  }
118 }
119 
120 inline
121 boost::python::object TfPyObject(PyObject* t, bool complainOnFailure = true) {
122  TfPyLock pyLock;
123  return boost::python::object(boost::python::handle<>(t));
124 }
125 
129 TF_API std::string TfPyObjectRepr(boost::python::object const &t);
130 
135 template <typename T>
136 std::string TfPyRepr(T const &t) {
137  if (!TfPyIsInitialized())
138  return "<python not initialized>";
139  TfPyLock lock;
140  return TfPyObjectRepr(TfPyObject(t));
141 }
142 
144 template <typename T>
145 std::string TfPyRepr(const std::vector<T> &v) {
146  std::string result("[");
147  typename std::vector<T>::const_iterator i = v.begin();
148  if (i != v.end()) {
149  result += TfPyRepr(*i);
150  ++i;
151  }
152  while (i != v.end()) {
153  result += ", " + TfPyRepr(*i);
154  ++i;
155  }
156  result += "]";
157  return result;
158 }
159 
163 TF_API
164 boost::python::object
166  std::string const &expr,
167  boost::python::dict const &extraGlobals = boost::python::dict());
168 
171 TF_API
172 int64_t
173 TfPyNormalizeIndex(int64_t index, uint64_t size, bool throwError = false);
174 
176 TF_API std::string TfPyGetClassName(boost::python::object const &obj);
177 
178 
181 TF_API boost::python::object
182 TfPyGetClassObject(std::type_info const &type);
183 
186 template <typename T>
187 boost::python::object
189  return TfPyGetClassObject(typeid(T));
190 }
191 
192 TF_API
193 void
194 Tf_PyWrapOnceImpl(boost::python::type_info const &,
195  std::function<void()> const&,
196  bool *);
197 
205 template <typename T>
206 void
207 TfPyWrapOnce(std::function<void()> const &wrapFunc)
208 {
209  // Don't try to wrap if python isn't initialized.
211  return;
212  }
213 
214  static bool isTypeWrapped = false;
215  if (isTypeWrapped) {
216  return;
217  }
218 
219  Tf_PyWrapOnceImpl(boost::python::type_id<T>(), wrapFunc, &isTypeWrapped);
220 }
221 
226 TF_API
227 void Tf_PyLoadScriptModule(std::string const &name);
228 
230 template <class Map>
231 boost::python::dict TfPyCopyMapToDictionary(Map const &map) {
232  TfPyLock lock;
233  boost::python::dict d;
234  for (typename Map::const_iterator i = map.begin(); i != map.end(); ++i)
235  d[i->first] = i->second;
236  return d;
237 }
238 
239 template<class Seq>
240 boost::python::list TfPyCopySequenceToList(Seq const &seq) {
241  TfPyLock lock;
242  boost::python::list l;
243  for (typename Seq::const_iterator i = seq.begin();
244  i != seq.end(); ++i)
245  l.append(*i);
246  return l;
247 }
248 
253 template <class Seq>
254 boost::python::object TfPyCopySequenceToSet(Seq const &seq) {
255  TfPyLock lock;
256  boost::python::handle<> set{boost::python::allow_null(PySet_New(nullptr))};
257  if (!set) {
258  boost::python::throw_error_already_set();
259  }
260  for (auto const& item : seq) {
261  boost::python::object obj(item);
262  if (PySet_Add(set.get(), obj.ptr()) == -1) {
263  boost::python::throw_error_already_set();
264  }
265  }
266  return boost::python::object(set);
267 }
268 
269 template<class Seq>
270 boost::python::tuple TfPyCopySequenceToTuple(Seq const &seq) {
271  return boost::python::tuple(TfPyCopySequenceToList(seq));
272 }
273 
278 TF_API
279 std::vector<std::string> TfPyGetTraceback();
280 
285 TF_API
286 void TfPyGetStackFrames(std::vector<uintptr_t> *frames);
287 
289 TF_API
290 void TfPyDumpTraceback();
291 
313 TF_API
314 bool TfPySetenv(const std::string & name, const std::string & value);
315 
338 TF_API
339 bool TfPyUnsetenv(const std::string & name);
340 
341 // Private helper method to TfPyEvaluateAndExtract.
342 //
343 TF_API bool Tf_PyEvaluateWithErrorCheck(
344  const std::string & expr, boost::python::object * obj);
345 
349 template <typename T>
350 bool TfPyEvaluateAndExtract(const std::string & expr, T * t)
351 {
352  if (expr.empty())
353  return false;
354 
355  // Take the lock before doing anything with boost::python.
356  TfPyLock lock;
357 
358  // Though TfPyEvaluate (called by Tf_PyEvaluateWithErroCheck) takes the
359  // python lock, it is important that we lock before we initialize the
360  // boost::python::object, since it will increment and decrement ref counts
361  // outside of the call to TfPyEvaluate.
362  boost::python::object obj;
363  if (!Tf_PyEvaluateWithErrorCheck(expr, &obj))
364  return false;
365 
366  boost::python::extract<T> extractor(obj);
367 
368  if (!extractor.check())
369  return false;
370 
371  *t = extractor();
372 
373  return true;
374 }
375 
379 TF_API
380 void TfPyPrintError();
381 
382 PXR_NAMESPACE_CLOSE_SCOPE
383 
384 #endif // TF_PYUTILS_H
TF_API void TfPyPrintError()
Print a standard traceback to sys.stderr and clear the error indicator.
boost::python::object TfPyCopySequenceToSet(Seq const &seq)
Create a python set from an iterable sequence.
Definition: pyUtils.h:254
TF_API bool TfPyIsInitialized()
Returns true if python is initialized.
TF_API std::vector< std::string > TfPyGetTraceback()
Return a vector of strings containing the current python traceback.
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition: diagnostic.h:87
TF_API boost::python::object TfPyGetClassObject(std::type_info const &type)
Return the python class object for type if type has been wrapped.
TF_API int64_t TfPyNormalizeIndex(int64_t index, uint64_t size, bool throwError=false)
Return a positive index in the range [0,size).
boost::python::dict TfPyCopyMapToDictionary(Map const &map)
Creates a python dictionary from a std::map.
Definition: pyUtils.h:231
TF_API bool TfPySetenv(const std::string &name, const std::string &value)
Set an environment variable in os.environ.
TF_API void TfPyThrowKeyError(std::string const &msg)
Raises a python KeyError and throws a C++ exception.
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 void TfPyThrowTypeError(std::string const &msg)
Raises a python TypeError and throws a C++ exception.
TF_API std::string TfPyObjectRepr(boost::python::object const &t)
Return repr(t).
TF_API void TfPyThrowRuntimeError(std::string const &msg)
Raises a python RuntimError and throws a C++ exception.
TF_API void TfPyDumpTraceback()
Print the current python traceback to stdout.
bool TfPyEvaluateAndExtract(const std::string &expr, T *t)
Safely evaluates expr and extracts the return object of type T.
Definition: pyUtils.h:350
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.
TF_API void TfPyThrowIndexError(std::string const &msg)
Raises a python IndexError and throws a C++ exception.
TF_API void TfPyInitialize()
Starts up the python runtime.
TF_API std::string TfPyGetClassName(boost::python::object const &obj)
Return the name of the class of obj.
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:100
TF_API bool TfPyUnsetenv(const std::string &name)
Remove an environment variable from os.environ.
std::string TfPyRepr(T const &t)
Return repr(t).
Definition: pyUtils.h:136
TF_API void TfPyThrowValueError(std::string const &msg)
Raises a python ValueError and throws a C++ exception.
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...