All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
pyError.h
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_PYERROR_H
25 #define TF_PYERROR_H
26 
29 
30 #include "pxr/pxr.h"
31 
32 #include "pxr/base/tf/api.h"
33 #include "pxr/base/tf/errorMark.h"
34 
35 #include <boost/python/default_call_policies.hpp>
36 
37 PXR_NAMESPACE_OPEN_SCOPE
38 
42 TF_API
43 bool TfPyConvertTfErrorsToPythonException(TfErrorMark const &m);
44 
48 TF_API
49 void TfPyConvertPythonExceptionToTfErrors();
50 
62 template <typename Base = boost::python::default_call_policies>
63 struct TfPyRaiseOnError : Base
64 {
65  public:
66 
67  // This call policy provides a customized argument_package. We need to do
68  // this to store the TfErrorMark that we use to collect TfErrors that
69  // occurred during the call and convert them to a python exception at the
70  // end. It doesn't work to do this in the precall() and postcall()
71  // because if the call itself throws a c++ exception, the postcall() isn't
72  // executed and we can't destroy the TfErrorMark, leaving it dangling.
73  // Using the argument_package solves this since it is a local variable it
74  // will be destroyed whether or not the call throws. This is not really a
75  // publicly documented boost.python feature, however. :-/
76  template <class BaseArgs>
77  struct ErrorMarkAndArgs {
78  /* implicit */ErrorMarkAndArgs(BaseArgs base_) : base(base_) {}
79  operator const BaseArgs &() const { return base; }
80  operator BaseArgs &() { return base; }
81  BaseArgs base;
82  TfErrorMark errorMark;
83  };
84  typedef ErrorMarkAndArgs<typename Base::argument_package> argument_package;
85 
88 
89  // Only accept our argument_package type, since we must ensure that we're
90  // using it so we track a TfErrorMark.
91  bool precall(argument_package const &a) { return Base::precall(a); }
92 
93  // Only accept our argument_package type, since we must ensure that we're
94  // using it so we track a TfErrorMark.
95  PyObject *postcall(argument_package const &a, PyObject *result) {
96  result = Base::postcall(a, result);
97  if (result && TfPyConvertTfErrorsToPythonException(a.errorMark)) {
98  Py_DECREF(result);
99  result = NULL;
100  }
101  return result;
102  }
103 };
104 
105 struct Tf_PyErrorClearer {
106  Tf_PyErrorClearer() : clearOnDestruction(true) {}
107  ~Tf_PyErrorClearer() {
108  if (clearOnDestruction)
109  mark.Clear();
110  }
111  void Dismiss() { clearOnDestruction = false; }
112  TfErrorMark mark;
113  bool clearOnDestruction;
114 };
115 
116 PXR_NAMESPACE_CLOSE_SCOPE
117 
118 #endif // TF_PYERROR_H
A boost.python call policy class which, when applied to a wrapped function, will create an error mark...
Definition: pyError.h:63
Class used to record the end of the error-list.
Definition: errorMark.h:66
TfPyRaiseOnError()
Default constructor.
Definition: pyError.h:87