@@ -25,7 +25,7 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2525(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2626SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2727
28- $Id: //depot/main/p4-python/PythonClientUser.cpp#37 $
28+ $Id: //depot/main/p4-python/PythonClientUser.cpp#38 $
2929
3030*******************************************************************************/
3131
@@ -71,10 +71,10 @@ PythonClientUser::PythonClientUser( PythonDebug * dbg, p4py::SpecMgr *s )
7171 track = false ;
7272 alive = 1 ;
7373 apiLevel = atoi ( P4Tag::l_client );
74-
74+
7575 Py_INCREF (Py_None);
7676 input = Py_None;
77-
77+
7878 Py_INCREF (Py_None);
7979 resolver = Py_None;
8080
@@ -83,6 +83,10 @@ PythonClientUser::PythonClientUser( PythonDebug * dbg, p4py::SpecMgr *s )
8383
8484 Py_INCREF (Py_None);
8585 progress = Py_None;
86+
87+ pendingExcType = NULL ;
88+ pendingExcValue = NULL ;
89+ pendingExcTb = NULL ;
8690}
8791
8892PythonClientUser::~PythonClientUser ()
@@ -91,6 +95,9 @@ PythonClientUser::~PythonClientUser()
9195 Py_DECREF (resolver);
9296 Py_DECREF (handler);
9397 Py_DECREF (progress);
98+ Py_XDECREF (pendingExcType);
99+ Py_XDECREF (pendingExcValue);
100+ Py_XDECREF (pendingExcTb);
94101}
95102
96103void PythonClientUser::Reset ()
@@ -99,6 +106,49 @@ void PythonClientUser::Reset()
99106 // input data is untouched
100107
101108 alive = 1 ; // yes, we want data from the server
109+ ClearPendingException ();
110+ }
111+
112+ void PythonClientUser::SetPendingException (PyObject *type, PyObject *value, PyObject *tb)
113+ {
114+ // Clear any existing pending exception first
115+ Py_XDECREF (pendingExcType);
116+ Py_XDECREF (pendingExcValue);
117+ Py_XDECREF (pendingExcTb);
118+
119+ // Store new exception (PyErr_Fetch already gave us owned references)
120+ pendingExcType = type;
121+ pendingExcValue = value;
122+ pendingExcTb = tb;
123+ }
124+
125+ bool PythonClientUser::GetPendingException (PyObject **type, PyObject **value, PyObject **tb)
126+ {
127+ if (pendingExcType == NULL ) {
128+ return false ;
129+ }
130+
131+ *type = pendingExcType;
132+ *value = pendingExcValue;
133+ *tb = pendingExcTb;
134+
135+ // Transfer ownership - caller will use PyErr_Restore which steals references
136+ pendingExcType = NULL ;
137+ pendingExcValue = NULL ;
138+ pendingExcTb = NULL ;
139+
140+ return true ;
141+ }
142+
143+ void PythonClientUser::ClearPendingException ()
144+ {
145+ Py_XDECREF (pendingExcType);
146+ Py_XDECREF (pendingExcValue);
147+ Py_XDECREF (pendingExcTb);
148+
149+ pendingExcType = NULL ;
150+ pendingExcValue = NULL ;
151+ pendingExcTb = NULL ;
102152}
103153
104154void PythonClientUser::Finished ()
@@ -127,6 +177,9 @@ bool PythonClientUser::CallOutputMethod( const char * method, PyObject * data)
127177
128178 PyObject * result = PyObject_CallMethod ( this ->handler , (char *) method, (char *)" O" , data );
129179 if ( result == NULL ) { // exception thrown
180+ PyObject *excType, *excValue, *excTb;
181+ PyErr_Fetch (&excType, &excValue, &excTb);
182+ SetPendingException (excType, excValue, excTb);
130183 alive = 0 ;
131184 }
132185 else {
@@ -228,7 +281,7 @@ ClientProgress * PythonClientUser::CreateProgress( int type )
228281 return NULL ;
229282 }
230283
231- return new PythonClientProgress (progress, type);
284+ return new PythonClientProgress (this , progress, type);
232285}
233286
234287void PythonClientUser::HandleError ( Error *e )
@@ -588,14 +641,17 @@ int PythonClientUser::Resolve( ClientMerge *m, Error *e )
588641
589642 PyObject * result = PyObject_CallMethod ( this ->resolver , (char *)" resolve" , (char *)" (O)" , mergeData );
590643 if ( result == NULL ) { // exception thrown, bug out of here
644+ PyObject *excType, *excValue, *excTb;
645+ PyErr_Fetch (&excType, &excValue, &excTb);
646+ SetPendingException (excType, excValue, excTb);
647+ Py_DECREF (mergeData);
591648 return CMS_QUIT ;
592649 }
593- else {
594- Py_DECREF ( result );
595- }
596650
597651 if (IsString (result)) {
598652 StrBuf reply = GetPythonString ( result );
653+ Py_DECREF ( result );
654+ Py_DECREF (mergeData);
599655
600656 if ( reply == " ay" ) return CMS_YOURS ;
601657 else if ( reply == " at" ) return CMS_THEIRS ;
@@ -613,6 +669,8 @@ int PythonClientUser::Resolve( ClientMerge *m, Error *e )
613669 }
614670 }
615671 else {
672+ Py_DECREF ( result );
673+ Py_DECREF (mergeData);
616674 PyErr_WarnEx ( PyExc_UserWarning, " [P4::Resolve] Illegal response : Expected String" , 1 );
617675 return CMS_QUIT ;
618676 }
@@ -666,13 +724,16 @@ int PythonClientUser::Resolve( ClientResolveA *m, int preview, Error *e )
666724
667725 PyObject * result = PyObject_CallMethod ( this ->resolver , (char *)" actionResolve" , (char *)" (O)" , mergeData );
668726 if ( result == NULL ) { // exception thrown, bug out of here
727+ PyObject *excType, *excValue, *excTb;
728+ PyErr_Fetch (&excType, &excValue, &excTb);
729+ SetPendingException (excType, excValue, excTb);
730+ Py_DECREF (mergeData);
669731 return CMS_QUIT ;
670732 }
671- else {
672- Py_DECREF ( result );
673- }
674733
675734 StrBuf reply = GetPythonString ( result );
735+ Py_DECREF ( result );
736+ Py_DECREF (mergeData);
676737
677738 if ( reply == " ay" ) return CMS_YOURS ;
678739 else if ( reply == " at" ) return CMS_THEIRS ;
0 commit comments