| 
					
				 | 
			
			
				@@ -58,6 +58,17 @@ _STREAM_STREAM_INITIAL_DUE = ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 _CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE = ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     'Exception calling channel subscription callback!') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+_OK_RENDEZVOUS_REPR_FORMAT = ('<_Rendezvous of RPC that terminated with:\n' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              '\tstatus = {}\n' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              '\tdetails = "{}"\n' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              '>') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+_NON_OK_RENDEZVOUS_REPR_FORMAT = ('<_Rendezvous of RPC that terminated with:\n' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                  '\tstatus = {}\n' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                  '\tdetails = "{}"\n' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                  '\tdebug_error_string = "{}"\n' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                  '>') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 def _deadline(timeout): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return None if timeout is None else time.time() + timeout 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -91,6 +102,7 @@ class _RPCState(object): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.trailing_metadata = trailing_metadata 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.code = code 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.details = details 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.debug_error_string = None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         # The semantics of grpc.Future.cancel and grpc.Future.cancelled are 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         # slightly wonky, so they have to be tracked separately from the rest of the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         # result of the RPC. This field tracks whether cancellation was requested 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -137,6 +149,7 @@ def _handle_event(event, state, response_deserializer): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     state.code = code 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     state.details = batch_operation.details() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    state.debug_error_string = batch_operation.error_string() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             callbacks.extend(state.callbacks) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             state.callbacks = None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return callbacks 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -374,13 +387,23 @@ class _Rendezvous(grpc.RpcError, grpc.Future, grpc.Call): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 self._state.condition.wait() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return _common.decode(self._state.details) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def debug_error_string(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        with self._state.condition: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            while self._state.debug_error_string is None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                self._state.condition.wait() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return _common.decode(self._state.debug_error_string) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def _repr(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         with self._state.condition: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if self._state.code is None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return '<_Rendezvous object of in-flight RPC>' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            elif self._state.code is grpc.StatusCode.OK: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return _OK_RENDEZVOUS_REPR_FORMAT.format( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    self._state.code, self._state.details) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return '<_Rendezvous of RPC that terminated with ({}, {})>'.format( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    self._state.code, _common.decode(self._state.details)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return _NON_OK_RENDEZVOUS_REPR_FORMAT.format( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    self._state.code, self._state.details, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    self._state.debug_error_string) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def __repr__(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return self._repr() 
			 |