Skip to content

Commit 49a9eea

Browse files
author
newellm
committed
Improve error handling. Mostly for the python side but also a few minor fixes for the maxscript side.
git-svn-id: svn://svn.blur.com/blurdev/trunk/code/cpp/plugins/max/src/blurPython@11595 896c8824-d3f5-0310-9c61-ac502b9a79dc
1 parent 380fa83 commit 49a9eea

5 files changed

Lines changed: 61 additions & 26 deletions

File tree

blurPython_msvc2010.vcxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@
160160
<Command>subwcrev $(SolutionDir) $(SolutionDir)version_h_template.txt $(SolutionDir)version.h</Command>
161161
</PreBuildEvent>
162162
<ClCompile>
163-
<AdditionalIncludeDirectories>$(PYTHON26_64)\include;$(MAX2012SDK)\include\maxscript;$(MAX2012SDK)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
163+
<AdditionalIncludeDirectories>c:\python26_64\include;c:\program files (x86)\Autodesk\3ds Max 2012 SDK\maxsdk\include\maxscript;c:\program files (x86)\Autodesk\3ds Max 2012 SDK\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
164164
<PreprocessorDefinitions>__MAXSCRIPT_2012__;WIN32;NDEBUG;_WINDOWS;_CRD_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
165165
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
166166
<WarningLevel>Level3</WarningLevel>
@@ -170,7 +170,7 @@
170170
<AdditionalDependencies>maxscrpt.lib;core.lib;maxutil.lib;geom.lib;%(AdditionalDependencies)</AdditionalDependencies>
171171
<ShowProgress>LinkVerboseLib</ShowProgress>
172172
<OutputFile>x64\blurPython26.dlx</OutputFile>
173-
<AdditionalLibraryDirectories>$(MAX2012SDK)\x64\lib;$(PYTHON26_64)\libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
173+
<AdditionalLibraryDirectories>c:\program files (x86)\Autodesk\3ds Max 2012 SDK\maxsdk\x64\lib;c:\python26_64\libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
174174
<IgnoreSpecificDefaultLibraries>python26_d.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
175175
<ModuleDefinitionFile>blurPython.def</ModuleDefinitionFile>
176176
<SubSystem>Windows</SubSystem>

macros.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,20 @@ class PyExcRuntimeError : public RuntimeError
6565

6666
// Call this macro to clean up any python errors that may have occurred
6767
// TODO: Test for quiet mode
68-
#define PY_CLEARERRORS() if ( PyErr_Occurred() ) { \
69-
/* PyErr_Print(); */ \
70-
throw PyExcRuntimeError( pythonExceptionTraceback() ); \
71-
/* throw RuntimeError( "Python Exception: Traceback printed in listener." ); */ \
72-
}
68+
#define PY_ERROR_PRINT_THROW() \
69+
char * exc_str = pythonExceptionTraceback( /*clearException=*/ false ); \
70+
PyErr_Print(); \
71+
throw PyExcRuntimeError( exc_str );
72+
73+
#define PY_ERROR_PROPAGATE() if ( PyErr_Occurred() ) { \
74+
PY_ERROR_PRINT_THROW(); \
75+
}
76+
77+
#define PY_ERROR_PROPAGATE_MXS_CLEANUP() \
78+
if ( PyErr_Occurred() ) { \
79+
MXS_CLEANUP(); \
80+
PY_ERROR_PRINT_THROW(); \
81+
}
7382

7483
#define PY_PROCESSERROR( PYEXC, MEXC ) MXS_CLEARERRORS(); \
7584
StringStream* buffer = new StringStream("MAXScript Error Has Occurred: \n"); \

python_struct.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ import_cf( Value** arg_list, int count ) {
6363
// Step 5: import the module
6464
if ( module_name ) {
6565
PyObject* module = PyImport_ImportModule( module_name );
66-
PY_CLEARERRORS();
66+
PY_ERROR_PROPAGATE_MXS_CLEANUP();
6767

6868
vl.mxs_return = ( module ) ? ObjectWrapper::intern( module ) : &undefined;
6969
}
@@ -81,16 +81,17 @@ reload_cf( Value** arg_list, int count ) {
8181
check_arg_count( python.reload, 1, count );
8282

8383
// Step 2: evaluate the input item
84-
Value* mxs_check = NULL;
85-
MXS_EVAL( arg_list[0], mxs_check );
84+
MXS_PROTECT(one_value_local(mxs_check));
85+
MXS_EVAL( arg_list[0], vl.mxs_check );
8686

8787
// Step 3: make sure the item is a proper type
88-
if ( is_objectwrapper(mxs_check) ) {
89-
PyImport_ReloadModule( ((ObjectWrapper*) mxs_check)->object() );
90-
PY_CLEARERRORS();
88+
if ( is_objectwrapper(vl.mxs_check) ) {
89+
PyImport_ReloadModule( ((ObjectWrapper*) vl.mxs_check)->object() );
90+
PY_ERROR_PROPAGATE_MXS_CLEANUP();
9191
}
9292
else { mprintf( "python.reload() error: you need to supply a valid python module to reload\n" ); }
9393

94+
MXS_CLEANUP();
9495
return &ok;
9596
}
9697

@@ -116,7 +117,7 @@ run_cf( Value** arg_list, int count ) {
116117

117118
// Step 4: run the file
118119
PyRun_SimpleFile( PyFile_AsFile(py_file), filename );
119-
PY_CLEARERRORS();
120+
PY_ERROR_PROPAGATE_MXS_CLEANUP();
120121

121122
// Step 5: cleanup the memory
122123
Py_XDECREF( py_file );
@@ -148,7 +149,7 @@ exec_cf( Value** arg_list, int count ) {
148149

149150
// Step 4: run the command
150151
PyRun_SimpleString( command );
151-
PY_CLEARERRORS();
152+
PY_ERROR_PROPAGATE_MXS_CLEANUP();
152153

153154
// Step 5: cleanup the memory
154155
MXS_CLEANUP();
@@ -164,6 +165,8 @@ PyExcRuntimeError::PyExcRuntimeError( char * _error )
164165
PyExcRuntimeError::~PyExcRuntimeError()
165166
{
166167
delete error;
168+
// Hopefully this is safe and keeps RuntimeError from double deleting our copy of the string
169+
desc1 = 0;
167170
}
168171

169172
// Returns a new string

studiomax_module.cpp

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,14 @@ static PyObject*
4242
mxs_getattro( PyObject* self, PyObject* key ) {
4343
// Step 1: convert the key to a name
4444
char* keystr = PyString_AsString( key );
45-
Value* name = Name::intern( keystr );
45+
46+
MXS_PROTECT(one_value_local(name));
47+
vl.name = Name::intern( keystr );
4648

4749
// Step 2: collect the PyObject* instance
48-
PyObject* output = ObjectWrapper::py_intern( globals->get( name ) );
49-
50+
PyObject* output = ObjectWrapper::py_intern( globals->get( vl.name ) );
51+
MXS_CLEANUP();
52+
5053
return output;
5154
}
5255

@@ -186,11 +189,13 @@ studiomax_runScript( PyObject* self, PyObject* args ) {
186189

187190
// Step 3: run the file
188191
PyRun_SimpleFile( PyFile_AsFile(py_file), filename );
189-
PY_CLEARERRORS();
190192

191193
// Step 4: clear the memory
192194
Py_XDECREF( py_file );
193195

196+
if( PyErr_Occurred() )
197+
return 0;
198+
194199
// return true
195200
Py_INCREF( Py_True );
196201
return Py_True;
@@ -317,18 +322,27 @@ studiomax_runMaxscript( PyObject* self, PyObject* args ) {
317322
// Py3dsMax.getVisController() - get the visibility controller of a node
318323
static PyObject*
319324
studiomax_getVisController( PyObject* self, PyObject* args ) {
325+
PyObject * ret = 0;
320326
if ( PyTuple_Size(args) == 1 ) {
321327
// convert the input item to a maxscript value
322328
PyObject* item = PyTuple_GetItem(args,0);
323-
Value* obj = ObjectWrapper::intern(item);
329+
MXS_PROTECT(one_value_local(obj));
330+
vl.obj = ObjectWrapper::intern(item);
324331

325-
if ( is_node(obj) ) {
326-
return ObjectWrapper::py_intern( MAXControl::intern( ((MAXNode*)obj)->node->GetVisController() ) );
332+
if ( is_node(vl.obj) ) {
333+
ret = ObjectWrapper::py_intern( MAXControl::intern( ((MAXNode*)vl.obj)->node->GetVisController() ) );
327334
}
335+
MXS_CLEANUP();
336+
} else {
337+
PyErr_SetString( PyExc_AttributeError, "getVisController takes one argument, a max object." );
338+
return 0;
328339
}
329340

330-
Py_INCREF( Py_None );
331-
return Py_None;
341+
if( !ret ) {
342+
Py_INCREF( Py_None );
343+
ret = Py_None;
344+
}
345+
return ret;
332346
}
333347

334348
// Py3dsMax.setVisController() - set the visibility controller of a node
@@ -350,6 +364,9 @@ studiomax_setVisController( PyObject* self, PyObject* args ) {
350364
}
351365
catch ( ... ) {};
352366
}
367+
} else {
368+
PyErr_SetString( PyExc_AttributeError, "setVisController takes two arguments, a max object and a visibility controller." );
369+
return 0;
353370
}
354371
if ( success ) {
355372
Py_INCREF( Py_True );

wrapper.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -896,7 +896,13 @@ ObjectWrapper::apply( Value** arg_list, int count, CallContext* cc ) {
896896

897897
// Step 7: execture the python call
898898
py_result = PyObject_Call( this->mObject, args, kwds );
899-
PY_CLEARERRORS();
899+
if ( PyErr_Occurred() ) {
900+
MXS_CLEARERRORS();
901+
Py_XDECREF( args );
902+
Py_XDECREF( kwds );
903+
Py_XDECREF( py_result );
904+
PY_ERROR_PRINT_THROW();
905+
}
900906

901907
// Step 8: convert the result to a value
902908

@@ -1068,7 +1074,7 @@ ObjectWrapper::to_string() {
10681074
// Step 2: pull the python object string for this object
10691075
PyObject* py_string = PyObject_Str( this->mObject );
10701076
char* out = ( py_string ) ? PyString_AsString( py_string ) : "<<python: error converting value to string>>";
1071-
PY_CLEARERRORS();
1077+
PyErr_Clear();
10721078

10731079
// Step 3: release the python memory
10741080
Py_XDECREF( py_string );

0 commit comments

Comments
 (0)