Loading...
Searching...
No Matches
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 PXR_BASE_TF_PY_ERROR_H
25#define PXR_BASE_TF_PY_ERROR_H
26
29
30#include "pxr/pxr.h"
31
32#include "pxr/base/tf/api.h"
34
35#include <boost/python/default_call_policies.hpp>
36
37PXR_NAMESPACE_OPEN_SCOPE
38
42TF_API
43bool TfPyConvertTfErrorsToPythonException(TfErrorMark const &m);
44
48TF_API
49void TfPyConvertPythonExceptionToTfErrors();
50
62template <typename Base = boost::python::default_call_policies>
63struct 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
105struct 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
116PXR_NAMESPACE_CLOSE_SCOPE
117
118#endif // PXR_BASE_TF_PY_ERROR_H
Class used to record the end of the error-list.
Definition: errorMark.h:65
A boost.python call policy class which, when applied to a wrapped function, will create an error mark...
Definition: pyError.h:64
TfPyRaiseOnError()
Default constructor.
Definition: pyError.h:87