Loading...
Searching...
No Matches
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"
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
52PXR_NAMESPACE_OPEN_SCOPE
53
59#define TF_PY_REPR_PREFIX \
60 std::string(TF_PP_STRINGIZE(MFB_PACKAGE_MODULE) ".")
61
63TF_API bool TfPyIsInitialized();
64
68TF_API void TfPyThrowIndexError(const char *msg);
69
71inline void TfPyThrowIndexError(std::string const &msg)
72{
73 TfPyThrowIndexError(msg.c_str());
74}
75
79TF_API void TfPyThrowRuntimeError(const char *msg);
80
82inline void TfPyThrowRuntimeError(std::string const &msg)
83{
84 TfPyThrowRuntimeError(msg.c_str());
85}
86
90TF_API void TfPyThrowStopIteration(const char *msg);
91
93inline void TfPyThrowStopIteration(std::string const &msg)
94{
95 TfPyThrowStopIteration(msg.c_str());
96}
97
101TF_API void TfPyThrowKeyError(const char *msg);
102
104inline void TfPyThrowKeyError(std::string const &msg)
105{
106 TfPyThrowKeyError(msg.c_str());
107}
108
112TF_API void TfPyThrowValueError(const char *msg);
113
115inline void TfPyThrowValueError(std::string const &msg)
116{
117 TfPyThrowValueError(msg.c_str());
118}
119
123TF_API void TfPyThrowTypeError(const char *msg);
124
126inline void TfPyThrowTypeError(std::string const &msg)
127{
128 TfPyThrowTypeError(msg.c_str());
129}
130
132TF_API bool TfPyIsNone(boost::python::object const &obj);
133
135TF_API bool TfPyIsNone(boost::python::handle<> const &obj);
136
137// Helper for \c TfPyObject().
138TF_API void Tf_PyObjectError(bool printError);
139
143template <typename T>
144boost::python::object TfPyObject(T const &t, bool complainOnFailure = true) {
145 // initialize python if it isn't already, so at least we can try to return
146 // an object
147 if (!TfPyIsInitialized()) {
148 TF_CODING_ERROR("Called TfPyObject without python being initialized!");
150 }
151
152 TfPyLock pyLock;
153
154 // Will only be able to return objects which have been wrapped.
155 // Returns None otherwise
156 try {
157 return boost::python::object(t);
158 } catch (boost::python::error_already_set const &) {
159 Tf_PyObjectError(complainOnFailure);
160 return boost::python::object();
161 }
162}
163
164inline
165boost::python::object TfPyObject(PyObject* t, bool complainOnFailure = true) {
166 TfPyLock pyLock;
167 return boost::python::object(boost::python::handle<>(t));
168}
169
173TF_API std::string TfPyObjectRepr(boost::python::object const &t);
174
179template <typename T>
180std::string TfPyRepr(T const &t) {
181 if (!TfPyIsInitialized())
182 return "<python not initialized>";
183 TfPyLock lock;
184 return TfPyObjectRepr(TfPyObject(t));
185}
186
188template <typename T>
189std::string TfPyRepr(const std::vector<T> &v) {
190 std::string result("[");
191 typename std::vector<T>::const_iterator i = v.begin();
192 if (i != v.end()) {
193 result += TfPyRepr(*i);
194 ++i;
195 }
196 while (i != v.end()) {
197 result += ", " + TfPyRepr(*i);
198 ++i;
199 }
200 result += "]";
201 return result;
202}
203
207TF_API
208boost::python::object
210 std::string const &expr,
211 boost::python::dict const &extraGlobals = boost::python::dict());
212
215TF_API
216int64_t
217TfPyNormalizeIndex(int64_t index, uint64_t size, bool throwError = false);
218
220TF_API std::string TfPyGetClassName(boost::python::object const &obj);
221
222
225TF_API boost::python::object
226TfPyGetClassObject(std::type_info const &type);
227
230template <typename T>
231boost::python::object
233 return TfPyGetClassObject(typeid(T));
234}
235
236TF_API
237void
238Tf_PyWrapOnceImpl(boost::python::type_info const &,
239 std::function<void()> const&,
240 bool *);
241
249template <typename T>
250void
251TfPyWrapOnce(std::function<void()> const &wrapFunc)
252{
253 // Don't try to wrap if python isn't initialized.
254 if (!TfPyIsInitialized()) {
255 return;
256 }
257
258 static bool isTypeWrapped = false;
259 if (isTypeWrapped) {
260 return;
261 }
262
263 Tf_PyWrapOnceImpl(boost::python::type_id<T>(), wrapFunc, &isTypeWrapped);
264}
265
270TF_API
271void Tf_PyLoadScriptModule(std::string const &name);
272
274template <class Map>
275boost::python::dict TfPyCopyMapToDictionary(Map const &map) {
276 TfPyLock lock;
277 boost::python::dict d;
278 for (typename Map::const_iterator i = map.begin(); i != map.end(); ++i)
279 d[i->first] = i->second;
280 return d;
281}
282
283template<class Seq>
284boost::python::list TfPyCopySequenceToList(Seq const &seq) {
285 TfPyLock lock;
286 boost::python::list l;
287 for (typename Seq::const_iterator i = seq.begin();
288 i != seq.end(); ++i)
289 l.append(*i);
290 return l;
291}
292
297template <class Seq>
298boost::python::object TfPyCopySequenceToSet(Seq const &seq) {
299 TfPyLock lock;
300 boost::python::handle<> set{boost::python::allow_null(PySet_New(nullptr))};
301 if (!set) {
302 boost::python::throw_error_already_set();
303 }
304 for (auto const& item : seq) {
305 boost::python::object obj(item);
306 if (PySet_Add(set.get(), obj.ptr()) == -1) {
307 boost::python::throw_error_already_set();
308 }
309 }
310 return boost::python::object(set);
311}
312
313template<class Seq>
314boost::python::tuple TfPyCopySequenceToTuple(Seq const &seq) {
315 return boost::python::tuple(TfPyCopySequenceToList(seq));
316}
317
324TF_API
325boost::python::object TfPyCopyBufferToByteArray(const char* buffer, size_t size);
326
331TF_API
332std::vector<std::string> TfPyGetTraceback();
333
338TF_API
339void TfPyGetStackFrames(std::vector<uintptr_t> *frames);
340
342TF_API
344
366TF_API
367bool TfPySetenv(const std::string & name, const std::string & value);
368
391TF_API
392bool TfPyUnsetenv(const std::string & name);
393
394// Private helper method to TfPyEvaluateAndExtract.
395//
396TF_API bool Tf_PyEvaluateWithErrorCheck(
397 const std::string & expr, boost::python::object * obj);
398
402template <typename T>
403bool TfPyEvaluateAndExtract(const std::string & expr, T * t)
404{
405 if (expr.empty())
406 return false;
407
408 // Take the lock before doing anything with boost::python.
409 TfPyLock lock;
410
411 // Though TfPyEvaluate (called by Tf_PyEvaluateWithErroCheck) takes the
412 // python lock, it is important that we lock before we initialize the
413 // boost::python::object, since it will increment and decrement ref counts
414 // outside of the call to TfPyEvaluate.
415 boost::python::object obj;
416 if (!Tf_PyEvaluateWithErrorCheck(expr, &obj))
417 return false;
418
419 boost::python::extract<T> extractor(obj);
420
421 if (!extractor.check())
422 return false;
423
424 *t = extractor();
425
426 return true;
427}
428
432TF_API
434
435PXR_NAMESPACE_CLOSE_SCOPE
436
437#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 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...
TF_API void TfPyThrowIndexError(const char *msg)
Raises a Python IndexError with the given error msg and throws a boost::python::error_already_set exc...
TF_API void TfPyThrowRuntimeError(const char *msg)
Raises a Python RuntimeError with the given error msg and throws a boost::python::error_already_set e...
TF_API void TfPyThrowStopIteration(const char *msg)
Raises a Python StopIteration with the given error msg and throws a boost::python::error_already_set ...
TF_API bool TfPyIsNone(boost::python::object const &obj)
Return true iff obj is None.
TF_API void TfPyThrowKeyError(const char *msg)
Raises a Python KeyError with the given error msg and throws a boost::python::error_already_set excep...
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...
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:144
TF_API bool TfPyUnsetenv(const std::string &name)
Remove an environment variable from os.environ.
bool TfPyEvaluateAndExtract(const std::string &expr, T *t)
Safely evaluates expr and extracts the return object of type T.
Definition: pyUtils.h:403
TF_API boost::python::object TfPyCopyBufferToByteArray(const char *buffer, size_t size)
Create a python bytearray from an input buffer and size.
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.
TF_API void TfPyThrowTypeError(const char *msg)
Raises a Python TypeError with the given error msg and throws a boost::python::error_already_set exce...
TF_API std::vector< std::string > TfPyGetTraceback()
Return a vector of strings containing the current python traceback.
boost::python::dict TfPyCopyMapToDictionary(Map const &map)
Creates a python dictionary from a std::map.
Definition: pyUtils.h:275
TF_API std::string TfPyObjectRepr(boost::python::object const &t)
Return repr(t).
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:251
TF_API void TfPyThrowValueError(const char *msg)
Raises a Python ValueError with the given error msg and throws a boost::python::error_already_set exc...
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::object TfPyCopySequenceToSet(Seq const &seq)
Create a python set from an iterable sequence.
Definition: pyUtils.h:298
std::string TfPyRepr(T const &t)
Return repr(t).
Definition: pyUtils.h:180
boost::python::object TfPyGetClassObject()
Return the python class object for T if T has been wrapped.
Definition: pyUtils.h:232
Convenience class for accessing the Python Global Interpreter Lock.
Definition: pyLock.h:122
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:85
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.