22
22
from google .api_core import exceptions
23
23
24
24
_LOGGER = logging .getLogger (__name__ )
25
- _BIDIRECTIONAL_CONSUMER_NAME = ' Thread-ConsumeBidirectionalStream'
25
+ _BIDIRECTIONAL_CONSUMER_NAME = " Thread-ConsumeBidirectionalStream"
26
26
27
27
28
28
class _RequestQueueGenerator (object ):
@@ -79,6 +79,7 @@ class _RequestQueueGenerator(object):
79
79
easily restarting streams that require some initial configuration
80
80
request.
81
81
"""
82
+
82
83
def __init__ (self , queue , period = 1 , initial_request = None ):
83
84
self ._queue = queue
84
85
self ._period = period
@@ -107,8 +108,8 @@ def __iter__(self):
107
108
except queue .Empty :
108
109
if not self ._is_active ():
109
110
_LOGGER .debug (
110
- ' Empty queue and inactive call, exiting request '
111
- 'generator.' )
111
+ " Empty queue and inactive call, exiting request " "generator."
112
+ )
112
113
return
113
114
else :
114
115
# call is still active, keep waiting for queue items.
@@ -117,16 +118,17 @@ def __iter__(self):
117
118
# The consumer explicitly sent "None", indicating that the request
118
119
# should end.
119
120
if item is None :
120
- _LOGGER .debug (' Cleanly exiting request generator.' )
121
+ _LOGGER .debug (" Cleanly exiting request generator." )
121
122
return
122
123
123
124
if not self ._is_active ():
124
125
# We have an item, but the call is closed. We should put the
125
126
# item back on the queue so that the next call can consume it.
126
127
self ._queue .put (item )
127
128
_LOGGER .debug (
128
- 'Inactive call, replacing item on queue and exiting '
129
- 'request generator.' )
129
+ "Inactive call, replacing item on queue and exiting "
130
+ "request generator."
131
+ )
130
132
return
131
133
132
134
yield item
@@ -164,6 +166,7 @@ class BidiRpc(object):
164
166
yield. This is useful if an initial request is needed to start the
165
167
stream.
166
168
"""
169
+
167
170
def __init__ (self , start_rpc , initial_request = None ):
168
171
self ._start_rpc = start_rpc
169
172
self ._initial_request = initial_request
@@ -192,17 +195,18 @@ def _on_call_done(self, future):
192
195
def open (self ):
193
196
"""Opens the stream."""
194
197
if self .is_active :
195
- raise ValueError (' Can not open an already open stream.' )
198
+ raise ValueError (" Can not open an already open stream." )
196
199
197
200
request_generator = _RequestQueueGenerator (
198
- self ._request_queue , initial_request = self ._initial_request )
201
+ self ._request_queue , initial_request = self ._initial_request
202
+ )
199
203
call = self ._start_rpc (iter (request_generator ))
200
204
201
205
request_generator .call = call
202
206
203
207
# TODO: api_core should expose the future interface for wrapped
204
208
# callables as well.
205
- if hasattr (call , ' _wrapped' ): # pragma: NO COVER
209
+ if hasattr (call , " _wrapped" ): # pragma: NO COVER
206
210
call ._wrapped .add_done_callback (self ._on_call_done )
207
211
else :
208
212
call .add_done_callback (self ._on_call_done )
@@ -232,8 +236,7 @@ def send(self, request):
232
236
request (protobuf.Message): The request to send.
233
237
"""
234
238
if self .call is None :
235
- raise ValueError (
236
- 'Can not send() on an RPC that has never been open()ed.' )
239
+ raise ValueError ("Can not send() on an RPC that has never been open()ed." )
237
240
238
241
# Don't use self.is_active(), as ResumableBidiRpc will overload it
239
242
# to mean something semantically different.
@@ -254,8 +257,7 @@ def recv(self):
254
257
protobuf.Message: The received message.
255
258
"""
256
259
if self .call is None :
257
- raise ValueError (
258
- 'Can not recv() on an RPC that has never been open()ed.' )
260
+ raise ValueError ("Can not recv() on an RPC that has never been open()ed." )
259
261
260
262
return next (self .call )
261
263
@@ -309,6 +311,7 @@ def should_recover(exc):
309
311
True if the stream should be recovered. This will be called
310
312
whenever an error is encountered on the stream.
311
313
"""
314
+
312
315
def __init__ (self , start_rpc , should_recover , initial_request = None ):
313
316
super (ResumableBidiRpc , self ).__init__ (start_rpc , initial_request )
314
317
self ._should_recover = should_recover
@@ -334,14 +337,14 @@ def _on_call_done(self, future):
334
337
if not self ._should_recover (future ):
335
338
self ._finalize (future )
336
339
else :
337
- _LOGGER .debug (' Re-opening stream from gRPC callback.' )
340
+ _LOGGER .debug (" Re-opening stream from gRPC callback." )
338
341
self ._reopen ()
339
342
340
343
def _reopen (self ):
341
344
with self ._operational_lock :
342
345
# Another thread already managed to re-open this stream.
343
346
if self .call is not None and self .call .is_active ():
344
- _LOGGER .debug (' Stream was already re-established.' )
347
+ _LOGGER .debug (" Stream was already re-established." )
345
348
return
346
349
347
350
self .call = None
@@ -362,11 +365,11 @@ def _reopen(self):
362
365
# If re-opening or re-calling the method fails for any reason,
363
366
# consider it a terminal error and finalize the stream.
364
367
except Exception as exc :
365
- _LOGGER .debug (' Failed to re-open stream due to %s' , exc )
368
+ _LOGGER .debug (" Failed to re-open stream due to %s" , exc )
366
369
self ._finalize (exc )
367
370
raise
368
371
369
- _LOGGER .info (' Re-established stream' )
372
+ _LOGGER .info (" Re-established stream" )
370
373
371
374
def _recoverable (self , method , * args , ** kwargs ):
372
375
"""Wraps a method to recover the stream and retry on error.
@@ -388,18 +391,15 @@ def _recoverable(self, method, *args, **kwargs):
388
391
389
392
except Exception as exc :
390
393
with self ._operational_lock :
391
- _LOGGER .debug (
392
- 'Call to retryable %r caused %s.' , method , exc )
394
+ _LOGGER .debug ("Call to retryable %r caused %s." , method , exc )
393
395
394
396
if not self ._should_recover (exc ):
395
397
self .close ()
396
- _LOGGER .debug (
397
- 'Not retrying %r due to %s.' , method , exc )
398
+ _LOGGER .debug ("Not retrying %r due to %s." , method , exc )
398
399
self ._finalize (exc )
399
400
raise exc
400
401
401
- _LOGGER .debug (
402
- 'Re-opening stream from retryable %r.' , method )
402
+ _LOGGER .debug ("Re-opening stream from retryable %r." , method )
403
403
self ._reopen ()
404
404
405
405
def _send (self , request ):
@@ -414,8 +414,7 @@ def _send(self, request):
414
414
call = self .call
415
415
416
416
if call is None :
417
- raise ValueError (
418
- 'Can not send() on an RPC that has never been open()ed.' )
417
+ raise ValueError ("Can not send() on an RPC that has never been open()ed." )
419
418
420
419
# Don't use self.is_active(), as ResumableBidiRpc will overload it
421
420
# to mean something semantically different.
@@ -434,8 +433,7 @@ def _recv(self):
434
433
call = self .call
435
434
436
435
if call is None :
437
- raise ValueError (
438
- 'Can not recv() on an RPC that has never been open()ed.' )
436
+ raise ValueError ("Can not recv() on an RPC that has never been open()ed." )
439
437
440
438
return next (call )
441
439
@@ -493,6 +491,7 @@ def on_response(response):
493
491
on_response (Callable[[protobuf.Message], None]): The callback to
494
492
be called for every response on the stream.
495
493
"""
494
+
496
495
def __init__ (self , bidi_rpc , on_response ):
497
496
self ._bidi_rpc = bidi_rpc
498
497
self ._on_response = on_response
@@ -522,43 +521,47 @@ def _thread_main(self):
522
521
# Python 2.7.
523
522
with self ._wake :
524
523
if self ._paused :
525
- _LOGGER .debug (' paused, waiting for waking.' )
524
+ _LOGGER .debug (" paused, waiting for waking." )
526
525
self ._wake .wait ()
527
- _LOGGER .debug (' woken.' )
526
+ _LOGGER .debug (" woken." )
528
527
529
- _LOGGER .debug (' waiting for recv.' )
528
+ _LOGGER .debug (" waiting for recv." )
530
529
response = self ._bidi_rpc .recv ()
531
- _LOGGER .debug (' recved response.' )
530
+ _LOGGER .debug (" recved response." )
532
531
self ._on_response (response )
533
532
534
533
except exceptions .GoogleAPICallError as exc :
535
534
_LOGGER .debug (
536
- '%s caught error %s and will exit. Generally this is due to '
537
- 'the RPC itself being cancelled and the error will be '
538
- 'surfaced to the calling code.' ,
539
- _BIDIRECTIONAL_CONSUMER_NAME , exc , exc_info = True )
535
+ "%s caught error %s and will exit. Generally this is due to "
536
+ "the RPC itself being cancelled and the error will be "
537
+ "surfaced to the calling code." ,
538
+ _BIDIRECTIONAL_CONSUMER_NAME ,
539
+ exc ,
540
+ exc_info = True ,
541
+ )
540
542
541
543
except Exception as exc :
542
544
_LOGGER .exception (
543
- '%s caught unexpected exception %s and will exit.' ,
544
- _BIDIRECTIONAL_CONSUMER_NAME , exc )
545
+ "%s caught unexpected exception %s and will exit." ,
546
+ _BIDIRECTIONAL_CONSUMER_NAME ,
547
+ exc ,
548
+ )
545
549
546
550
else :
547
- _LOGGER .error (
548
- 'The bidirectional RPC exited.' )
551
+ _LOGGER .error ("The bidirectional RPC exited." )
549
552
550
- _LOGGER .info (' %s exiting' , _BIDIRECTIONAL_CONSUMER_NAME )
553
+ _LOGGER .info (" %s exiting" , _BIDIRECTIONAL_CONSUMER_NAME )
551
554
552
555
def start (self ):
553
556
"""Start the background thread and begin consuming the thread."""
554
557
with self ._operational_lock :
555
558
thread = threading .Thread (
556
- name = _BIDIRECTIONAL_CONSUMER_NAME ,
557
- target = self . _thread_main )
559
+ name = _BIDIRECTIONAL_CONSUMER_NAME , target = self . _thread_main
560
+ )
558
561
thread .daemon = True
559
562
thread .start ()
560
563
self ._thread = thread
561
- _LOGGER .debug (' Started helper thread %s' , thread .name )
564
+ _LOGGER .debug (" Started helper thread %s" , thread .name )
562
565
563
566
def stop (self ):
564
567
"""Stop consuming the stream and shutdown the background thread."""
0 commit comments