Loading...
Searching...
No Matches
pyUtils.h
Go to the documentation of this file.
1//
2// Copyright 2016 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://openusd.org/license.
6//
7#ifndef PXR_BASE_TF_PY_UTILS_H
8#define PXR_BASE_TF_PY_UTILS_H
9
12
13#include "pxr/pxr.h"
14
15#include "pxr/base/tf/refPtr.h"
16#include "pxr/base/tf/weakPtr.h"
18#include "pxr/base/tf/preprocessorUtilsLite.h"
21#include "pxr/base/tf/pyLock.h"
22#include "pxr/base/tf/api.h"
23
24#include <functional>
25#include <typeinfo>
26#include <string>
27#include <vector>
28
29#include "pxr/external/boost/python/dict.hpp"
30#include "pxr/external/boost/python/extract.hpp"
31#include "pxr/external/boost/python/handle.hpp"
32#include "pxr/external/boost/python/object.hpp"
33#include "pxr/external/boost/python/type_id.hpp"
34
35PXR_NAMESPACE_OPEN_SCOPE
36
42#define TF_PY_REPR_PREFIX \
43 std::string(TF_PP_STRINGIZE(MFB_PACKAGE_MODULE) ".")
44
46TF_API bool TfPyIsInitialized();
47
51TF_API void TfPyThrowIndexError(const char *msg);
52
54inline void TfPyThrowIndexError(std::string const &msg)
55{
56 TfPyThrowIndexError(msg.c_str());
57}
58
62TF_API void TfPyThrowRuntimeError(const char *msg);
63
65inline void TfPyThrowRuntimeError(std::string const &msg)
66{
67 TfPyThrowRuntimeError(msg.c_str());
68}
69
73TF_API void TfPyThrowStopIteration(const char *msg);
74
76inline void TfPyThrowStopIteration(std::string const &msg)
77{
78 TfPyThrowStopIteration(msg.c_str());
79}
80
84TF_API void TfPyThrowKeyError(const char *msg);
85
87inline void TfPyThrowKeyError(std::string const &msg)
88{
89 TfPyThrowKeyError(msg.c_str());
90}
91
95TF_API void TfPyThrowValueError(const char *msg);
96
98inline void TfPyThrowValueError(std::string const &msg)
99{
100 TfPyThrowValueError(msg.c_str());
101}
102
106TF_API void TfPyThrowTypeError(const char *msg);
107
109inline void TfPyThrowTypeError(std::string const &msg)
110{
111 TfPyThrowTypeError(msg.c_str());
112}
113
115TF_API bool TfPyIsNone(pxr_boost::python::object const &obj);
116
118TF_API bool TfPyIsNone(pxr_boost::python::handle<> const &obj);
119
137inline int
138Tf_PyWeakrefGetRef(PyObject *ref, PyObject **pobj)
139{
140#if PY_VERSION_HEX >= 0x030D0000
141 return PyWeakref_GetRef(ref, pobj);
142#else
143 PyObject *obj = PyWeakref_GetObject(ref);
144 if (!obj) {
145 // Not a weak reference; PyWeakref_GetObject has set an exception.
146 // Leave *pobj alone: PyWeakref_GetRef does not specify its value on
147 // error, so neither do we.
148 return -1;
149 }
150 if (obj == Py_None) {
151 // The referent has expired. None itself is not weak-referenceable, so
152 // this cannot be a live referent.
153 *pobj = nullptr;
154 return 0;
155 }
156 Py_INCREF(obj);
157 *pobj = obj;
158 return 1;
159#endif
160}
161
162// Helper for \c TfPyObject().
163TF_API void Tf_PyObjectError(bool printError);
164
168template <typename T>
169pxr_boost::python::object TfPyObject(T const &t, bool complainOnFailure = true) {
170 // initialize python if it isn't already, so at least we can try to return
171 // an object
172 if (!TfPyIsInitialized()) {
173 TF_CODING_ERROR("Called TfPyObject without python being initialized!");
175 }
176
177 TfPyLock pyLock;
178
179 // Will only be able to return objects which have been wrapped.
180 // Returns None otherwise
181 try {
182 return pxr_boost::python::object(t);
183 } catch (pxr_boost::python::error_already_set const &) {
184 Tf_PyObjectError(complainOnFailure);
185 return pxr_boost::python::object();
186 }
187}
188
189inline
190pxr_boost::python::object TfPyObject(PyObject* t, bool complainOnFailure = true) {
191 TfPyLock pyLock;
192 return pxr_boost::python::object(pxr_boost::python::handle<>(t));
193}
194
198TF_API std::string TfPyObjectRepr(pxr_boost::python::object const &t);
199
204template <typename T>
205std::string TfPyRepr(T const &t) {
206 if (!TfPyIsInitialized())
207 return "<python not initialized>";
208 TfPyLock lock;
209 return TfPyObjectRepr(TfPyObject(t));
210}
211
213template <typename T>
214std::string TfPyRepr(const std::vector<T> &v) {
215 std::string result("[");
216 typename std::vector<T>::const_iterator i = v.begin();
217 if (i != v.end()) {
218 result += TfPyRepr(*i);
219 ++i;
220 }
221 while (i != v.end()) {
222 result += ", " + TfPyRepr(*i);
223 ++i;
224 }
225 result += "]";
226 return result;
227}
228
232TF_API
233pxr_boost::python::object
235 std::string const &expr,
236 pxr_boost::python::dict const &extraGlobals = pxr_boost::python::dict());
237
240TF_API
241int64_t
242TfPyNormalizeIndex(int64_t index, uint64_t size, bool throwError = false);
243
245TF_API std::string TfPyGetClassName(pxr_boost::python::object const &obj);
246
247
250TF_API pxr_boost::python::object
251TfPyGetClassObject(std::type_info const &type);
252
255template <typename T>
256pxr_boost::python::object
258 return TfPyGetClassObject(typeid(T));
259}
260
261TF_API
262void
263Tf_PyWrapOnceImpl(pxr_boost::python::type_info const &,
264 std::function<void()> const&,
265 bool *);
266
274template <typename T>
275void
276TfPyWrapOnce(std::function<void()> const &wrapFunc)
277{
278 // Don't try to wrap if python isn't initialized.
279 if (!TfPyIsInitialized()) {
280 return;
281 }
282
283 static bool isTypeWrapped = false;
284 if (isTypeWrapped) {
285 return;
286 }
287
288 Tf_PyWrapOnceImpl(pxr_boost::python::type_id<T>(), wrapFunc, &isTypeWrapped);
289}
290
295TF_API
296void Tf_PyLoadScriptModule(std::string const &name);
297
299template <class Map>
300pxr_boost::python::dict TfPyCopyMapToDictionary(Map const &map) {
301 TfPyLock lock;
302 pxr_boost::python::dict d;
303 for (typename Map::const_iterator i = map.begin(); i != map.end(); ++i)
304 d[i->first] = i->second;
305 return d;
306}
307
308template<class Seq>
309pxr_boost::python::list TfPyCopySequenceToList(Seq const &seq) {
310 TfPyLock lock;
311 pxr_boost::python::list l;
312 for (typename Seq::const_iterator i = seq.begin();
313 i != seq.end(); ++i)
314 l.append(*i);
315 return l;
316}
317
322template <class Seq>
323pxr_boost::python::object TfPyCopySequenceToSet(Seq const &seq) {
324 TfPyLock lock;
325 pxr_boost::python::handle<> set{pxr_boost::python::allow_null(PySet_New(nullptr))};
326 if (!set) {
327 pxr_boost::python::throw_error_already_set();
328 }
329 for (auto const& item : seq) {
330 pxr_boost::python::object obj(item);
331 if (PySet_Add(set.get(), obj.ptr()) == -1) {
332 pxr_boost::python::throw_error_already_set();
333 }
334 }
335 return pxr_boost::python::object(set);
336}
337
338template<class Seq>
339pxr_boost::python::tuple TfPyCopySequenceToTuple(Seq const &seq) {
340 return pxr_boost::python::tuple(TfPyCopySequenceToList(seq));
341}
342
349TF_API
350pxr_boost::python::object TfPyCopyBufferToByteArray(const char* buffer, size_t size);
351
356TF_API
357std::vector<std::string> TfPyGetTraceback();
358
380TF_API
381bool TfPySetenv(const std::string & name, const std::string & value);
382
405TF_API
406bool TfPyUnsetenv(const std::string & name);
407
408// Private helper method to TfPyEvaluateAndExtract.
409//
410TF_API bool Tf_PyEvaluateWithErrorCheck(
411 const std::string & expr, pxr_boost::python::object * obj);
412
416template <typename T>
417bool TfPyEvaluateAndExtract(const std::string & expr, T * t)
418{
419 if (expr.empty())
420 return false;
421
422 // Take the lock before doing anything with pxr_boost::python.
423 TfPyLock lock;
424
425 // Though TfPyEvaluate (called by Tf_PyEvaluateWithErroCheck) takes the
426 // python lock, it is important that we lock before we initialize the
427 // pxr_boost::python::object, since it will increment and decrement ref counts
428 // outside of the call to TfPyEvaluate.
429 pxr_boost::python::object obj;
430 if (!Tf_PyEvaluateWithErrorCheck(expr, &obj))
431 return false;
432
433 pxr_boost::python::extract<T> extractor(obj);
434
435 if (!extractor.check())
436 return false;
437
438 *t = extractor();
439
440 return true;
441}
442
446TF_API
448
449PXR_NAMESPACE_CLOSE_SCOPE
450
451#endif // PXR_BASE_TF_PY_UTILS_H
TF_API void TfPyPrintError()
Print a standard traceback to sys.stderr and clear the error indicator.
TF_API std::string TfPyObjectRepr(pxr_boost::python::object const &t)
Return repr(t).
TF_API void TfPyThrowIndexError(const char *msg)
Raises a Python IndexError with the given error msg and throws a pxr_boost::python::error_already_set...
TF_API void TfPyThrowRuntimeError(const char *msg)
Raises a Python RuntimeError with the given error msg and throws a pxr_boost::python::error_already_s...
TF_API void TfPyThrowStopIteration(const char *msg)
Raises a Python StopIteration with the given error msg and throws a pxr_boost::python::error_already_...
TF_API bool TfPyIsNone(pxr_boost::python::object const &obj)
Return true iff obj is None.
pxr_boost::python::object TfPyCopySequenceToSet(Seq const &seq)
Create a python set from an iterable sequence.
Definition pyUtils.h:323
pxr_boost::python::object TfPyGetClassObject()
Return the python class object for T if T has been wrapped.
Definition pyUtils.h:257
TF_API void TfPyThrowKeyError(const char *msg)
Raises a Python KeyError with the given error msg and throws a pxr_boost::python::error_already_set e...
TF_API pxr_boost::python::object TfPyCopyBufferToByteArray(const char *buffer, size_t size)
Create a python bytearray from an input buffer and size.
pxr_boost::python::dict TfPyCopyMapToDictionary(Map const &map)
Creates a python dictionary from a std::map.
Definition pyUtils.h:300
TF_API bool TfPyUnsetenv(const std::string &name)
Remove an environment variable from os.environ.
TF_API std::string TfPyGetClassName(pxr_boost::python::object const &obj)
Return the name of the class of obj.
bool TfPyEvaluateAndExtract(const std::string &expr, T *t)
Safely evaluates expr and extracts the return object of type T.
Definition pyUtils.h:417
pxr_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:169
TF_API bool TfPyIsInitialized()
Returns true if python is initialized.
TF_API void TfPyThrowTypeError(const char *msg)
Raises a Python TypeError with the given error msg and throws a pxr_boost::python::error_already_set ...
TF_API std::vector< std::string > TfPyGetTraceback()
Return a vector of strings containing the current python traceback.
TF_API bool TfPySetenv(const std::string &name, const std::string &value)
Set an environment variable in os.environ.
void TfPyWrapOnce(std::function< void()> const &wrapFunc)
Invokes wrapFunc to wrap type T if T is not already wrapped.
Definition pyUtils.h:276
TF_API void TfPyThrowValueError(const char *msg)
Raises a Python ValueError with the given error msg and throws a pxr_boost::python::error_already_set...
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 pxr_boost::python::object TfPyEvaluate(std::string const &expr, pxr_boost::python::dict const &extraGlobals=pxr_boost::python::dict())
Evaluate python expression expr with all the known script modules imported under their standard names...
std::string TfPyRepr(T const &t)
Return repr(t).
Definition pyUtils.h:205
Convenience class for accessing the Python Global Interpreter Lock.
Definition pyLock.h:105
Stripped down version of diagnostic.h that doesn't define std::string.
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition diagnostic.h:69
Python runtime utilities.
TF_API void TfPyInitialize()
Starts up the python runtime.
Intended to replace a direct include of Python.h, which causes several build problems with certain co...
Reference counting.
Pointer storage with deletion detection.