Skip to content
This repository was archived by the owner on Oct 11, 2023. It is now read-only.

Commit 7f376b0

Browse files
authored
Change all blanket catch statements to only catch Exception (#102)
* Change all blanket catch statements to only catch Exception * Code review feedback
1 parent 72c798d commit 7f376b0

18 files changed

+513
-195
lines changed

azure-iot-device/azure/iot/device/common/mqtt_provider.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def on_connect(client, userdata, flags, rc):
6464
if self.on_mqtt_connected:
6565
try:
6666
self.on_mqtt_connected()
67-
except: # noqa: E722 do not use bare 'except'
67+
except Exception:
6868
logger.error("Unexpected error calling on_mqtt_connected")
6969
logger.error(traceback.format_exc())
7070
else:
@@ -76,7 +76,7 @@ def on_disconnect(client, userdata, rc):
7676
if self.on_mqtt_disconnected:
7777
try:
7878
self.on_mqtt_disconnected()
79-
except: # noqa: E722 do not use bare 'except'
79+
except Exception:
8080
logger.error("Unexpected error calling on_mqtt_disconnected")
8181
logger.error(traceback.format_exc())
8282
else:
@@ -103,7 +103,7 @@ def on_message(client, userdata, mqtt_message):
103103
if self.on_mqtt_message_received:
104104
try:
105105
self.on_mqtt_message_received(mqtt_message.topic, mqtt_message.payload)
106-
except: # noqa: E722 do not use bare 'except'
106+
except Exception:
107107
logger.error("Unexpected error calling on_mqtt_message_received")
108108
logger.error(traceback.format_exc())
109109
else:
@@ -259,7 +259,7 @@ def establish_operation(self, mid, callback=None):
259259
if callback:
260260
try:
261261
callback()
262-
except: # noqa: E722 do not use bare 'except'
262+
except Exception:
263263
logger.error("Unexpected error calling callback for MID: {}".format(mid))
264264
logger.error(traceback.format_exc())
265265
else:
@@ -301,7 +301,7 @@ def complete_operation(self, mid):
301301
if callback:
302302
try:
303303
callback()
304-
except: # noqa: E722 do not use bare 'except'
304+
except Exception:
305305
logger.error("Unexpected error calling callback for MID: {}".format(mid))
306306
logger.error(traceback.format_exc())
307307
else:

azure-iot-device/azure/iot/device/common/pipeline/pipeline_stages_base.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,7 @@ def run_op(self, op):
9292
logger.info("{}({}): running".format(self.name, op.name))
9393
try:
9494
self._run_op(op)
95-
except: # noqa: E722 do not use bare 'except'
96-
_, e, _ = sys.exc_info()
95+
except Exception as e:
9796
logger.error(msg="Error in {}._run_op() call".format(self), exc_info=e)
9897
op.error = e
9998
self.complete_op(op)
@@ -177,8 +176,7 @@ def on_finally_done(finally_op):
177176
)
178177
)
179178
callback(finally_op)
180-
except: # noqa: E722 do not use bare 'except'
181-
_, e, _ = sys.exc_info()
179+
except Exception as e:
182180
logger.error(
183181
msg="{}({}):run_ops_serial: Unhandled error in callback".format(
184182
self.name, finally_op.name
@@ -200,8 +198,7 @@ def on_finally_done(finally_op):
200198
)
201199
)
202200
callback(last_op)
203-
except: # noqa: E722 do not use bare 'except'
204-
_, e, _ = sys.exc_info()
201+
except Exception as e:
205202
logger.error(
206203
msg="{}({}):run_ops_serial: Unhandled error in callback".format(
207204
self.name, last_op.name
@@ -257,8 +254,7 @@ def handle_pipeline_event(self, event):
257254
"""
258255
try:
259256
self._handle_pipeline_event(event)
260-
except: # noqa: E722 do not use bare 'except'
261-
_, e, _ = sys.exc_info()
257+
except Exception as e:
262258
logger.error(
263259
msg="Error in %s._handle_pipeline_event call".format(self.name), exc_info=e
264260
)
@@ -317,7 +313,7 @@ def complete_op(self, op):
317313
)
318314
try:
319315
op.callback(op)
320-
except: # noqa: E722 do not use bare 'except'
316+
except Exception as e:
321317
_, e, _ = sys.exc_info()
322318
logger.error(
323319
msg="Unhandled error calling back inside {}.complete_op() after {} complete".format(

azure-iot-device/azure/iot/device/common/pipeline/pipeline_stages_mqtt.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ def on_connected():
8383
self.provider.on_mqtt_connected = on_connected
8484
try:
8585
self.provider.connect(self.sas_token)
86-
except BaseException:
86+
except Exception as e:
8787
self.provider.on_mqtt_connected = self.on_connected
88-
raise
88+
raise e
8989

9090
elif isinstance(op, pipeline_ops_base.Reconnect):
9191
logger.info("{}({}): reconnecting".format(self.name, op.name))
@@ -100,9 +100,9 @@ def on_connected():
100100
self.provider.on_mqtt_connected = on_connected
101101
try:
102102
self.provider.reconnect(self.sas_token)
103-
except BaseException:
103+
except Exception as e:
104104
self.provider.on_mqtt_connected = self.on_connected
105-
raise
105+
raise e
106106

107107
elif isinstance(op, pipeline_ops_base.Disconnect):
108108
logger.info("{}({}): disconneting".format(self.name, op.name))
@@ -117,9 +117,9 @@ def on_disconnected():
117117
self.provider.on_mqtt_disconnected = on_disconnected
118118
try:
119119
self.provider.disconnect()
120-
except BaseException:
120+
except Exception as e:
121121
self.provider.on_mqtt_disconnected = self.on_disconnected
122-
raise
122+
raise e
123123

124124
elif isinstance(op, pipeline_ops_mqtt.Publish):
125125
logger.info("{}({}): publishing on {}".format(self.name, op.name, op.topic))

azure-iot-device/azure/iot/device/iothub/pipeline/pipeline_stages_iothub.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ class UseSkAuthProvider(PipelineStage):
3232

3333
def _run_op(self, op):
3434
if isinstance(op, pipeline_ops_iothub.SetAuthProvider):
35+
36+
def pipeline_ops_done(completed_op):
37+
op.error = completed_op.error
38+
op.callback(op)
39+
3540
auth_provider = op.auth_provider
3641
self.run_ops_serial(
3742
pipeline_ops_iothub.SetAuthProviderArgs(
@@ -42,7 +47,7 @@ def _run_op(self, op):
4247
ca_cert=getattr(auth_provider, "ca_cert", None),
4348
),
4449
pipeline_ops_base.SetSasToken(sas_token=auth_provider.get_current_sas_token()),
45-
callback=op.callback,
50+
callback=pipeline_ops_done,
4651
)
4752
else:
4853
self.continue_op(op)

azure-iot-device/azure/iot/device/provisioning/internal/polling_machine.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ def _on_disconnect_completed_error(self):
419419
self._register_callback = None
420420
try:
421421
callback(None, self._registration_error)
422-
except: # noqa: E722 do not use bare 'except'
422+
except Exception:
423423
logger.error("Unexpected error calling callback supplied to register")
424424
logger.error(traceback.format_exc())
425425

@@ -439,7 +439,7 @@ def _on_disconnect_completed_register(self):
439439
self._register_callback = None
440440
try:
441441
callback(self._registration_result, None)
442-
except: # noqa: E722 do not use bare 'except'
442+
except Exception:
443443
logger.error("Unexpected error calling callback supplied to register")
444444
logger.error(traceback.format_exc())
445445

azure-iot-device/azure/iot/device/provisioning/pipeline/pipeline_stages_provisioning.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ class UseSymmetricKeySecurityClient(PipelineStage):
3333

3434
def _run_op(self, op):
3535
if isinstance(op, pipeline_ops_provisioning.SetSymmetricKeySecurityClient):
36+
37+
def pipeline_ops_done(completed_op):
38+
op.error = completed_op.error
39+
op.callback(op)
40+
3641
security_client = op.security_client
3742
self.run_ops_serial(
3843
pipeline_ops_provisioning.SetSymmetricKeySecurityClientArgs(
@@ -41,7 +46,7 @@ def _run_op(self, op):
4146
id_scope=security_client.id_scope,
4247
),
4348
pipeline_ops_base.SetSasToken(sas_token=security_client.get_current_sas_token()),
44-
callback=op.callback,
49+
callback=pipeline_ops_done,
4550
)
4651
else:
4752
self.continue_op(op)

azure-iot-device/tests/common/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# --------------------------------------------------------------------------
66

77
import sys
8-
from .pipeline_test_fixtures import callback, fake_error, event
8+
from .pipeline_test_fixtures import callback, fake_exception, fake_base_exception, event
99

1010
collect_ignore = []
1111

azure-iot-device/tests/common/pipeline/test_pipeline_stages_base.py

Lines changed: 87 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
make_mock_stage,
1717
assert_callback_failed,
1818
assert_callback_succeeded,
19+
UnhandledException,
1920
)
2021

2122
logging.basicConfig(level=logging.INFO)
@@ -130,14 +131,22 @@ def test_failed_operation(self, stage, callback, op):
130131
stage.run_ops_serial(op, callback=callback)
131132
assert_callback_failed(op=op, callback=callback)
132133

133-
@pytest.mark.it("protects the callback with a try/except block")
134-
def test_exception_in_callback(self, stage, mocker, fake_error, op):
135-
callback = mocker.Mock(side_effect=fake_error)
134+
@pytest.mark.it(
135+
"handles Exceptions raised in the callback and passes them to the unhandled error handler"
136+
)
137+
def test_callback_throws_exception(self, stage, mocker, fake_exception, op):
138+
callback = mocker.Mock(side_effect=fake_exception)
136139
stage.run_ops_serial(op, callback=callback)
137140
assert callback.call_count == 1
138141
assert callback.call_args == mocker.call(op)
139142
assert stage.unhandled_error_handler.call_count == 1
140-
assert stage.unhandled_error_handler.call_args == mocker.call(fake_error)
143+
assert stage.unhandled_error_handler.call_args == mocker.call(fake_exception)
144+
145+
@pytest.mark.it("Allows any BaseExceptions raised in the callback to propagate")
146+
def test_callback_throws_base_exception(self, stage, mocker, fake_base_exception, op):
147+
callback = mocker.Mock(side_effect=fake_base_exception)
148+
with pytest.raises(UnhandledException):
149+
stage.run_ops_serial(op, callback=callback)
141150

142151

143152
@pytest.mark.describe("PipelineStage run_ops_serial function with one op and finally op")
@@ -196,14 +205,24 @@ def test_callback_with_error_if_op_fails_and_finally_op_succeeds(
196205
stage.run_ops_serial(op, finally_op=finally_op, callback=callback)
197206
assert_callback_failed(callback=callback, op=finally_op, error=op.error)
198207

199-
@pytest.mark.it("protects the callback with a try/except block")
200-
def test_exception_in_callback(self, stage, op, finally_op, fake_error, mocker):
201-
callback = mocker.Mock(side_effect=fake_error)
208+
@pytest.mark.it(
209+
"handles Exceptions raised in the callback and passes them to the unhandled error handler"
210+
)
211+
def test_callback_raises_exception(self, stage, op, finally_op, fake_exception, mocker):
212+
callback = mocker.Mock(side_effect=fake_exception)
202213
stage.run_ops_serial(op, finally_op=finally_op, callback=callback)
203214
assert callback.call_count == 1
204215
assert callback.call_args == mocker.call(finally_op)
205216
assert stage.unhandled_error_handler.call_count == 1
206-
assert stage.unhandled_error_handler.call_args == mocker.call(fake_error)
217+
assert stage.unhandled_error_handler.call_args == mocker.call(fake_exception)
218+
219+
@pytest.mark.it("Allows any BaseExceptions raised in the callback to propagate")
220+
def test_callback_raises_base_exception(
221+
self, stage, op, finally_op, fake_base_exception, mocker
222+
):
223+
callback = mocker.Mock(side_effect=fake_base_exception)
224+
with pytest.raises(UnhandledException):
225+
stage.run_ops_serial(op, finally_op=finally_op, callback=callback)
207226

208227

209228
@pytest.mark.describe("PipelineStage run_ops_serial function with three ops and without finally op")
@@ -231,14 +250,22 @@ def test_calls_callback_when_first_op_fails(self, stage, op, op2, op3, callback)
231250
stage.run_ops_serial(op, op2, op3, callback=callback)
232251
assert_callback_failed(callback=callback, op=op)
233252

234-
@pytest.mark.it("protects the callback with a try/except block")
235-
def test_exception_in_callback(self, stage, op, op2, op3, fake_error, mocker):
236-
callback = mocker.Mock(side_effect=fake_error)
253+
@pytest.mark.it(
254+
"handles Exceptions raised in the callback and passes them to the unhandled error handler"
255+
)
256+
def test_callback_raises_exception(self, stage, op, op2, op3, fake_exception, mocker):
257+
callback = mocker.Mock(side_effect=fake_exception)
237258
stage.run_ops_serial(op, op2, op3, callback=callback)
238259
assert callback.call_count == 1
239260
assert callback.call_args == mocker.call(op3)
240261
assert stage.unhandled_error_handler.call_count == 1
241-
assert stage.unhandled_error_handler.call_args == mocker.call(fake_error)
262+
assert stage.unhandled_error_handler.call_args == mocker.call(fake_exception)
263+
264+
@pytest.mark.it("Allows any BaseExceptions raised in the callback to propagate")
265+
def test_callback_raises_base_exception(self, stage, op, op2, op3, fake_base_exception, mocker):
266+
callback = mocker.Mock(side_effect=fake_base_exception)
267+
with pytest.raises(UnhandledException):
268+
stage.run_ops_serial(op, op2, op3, callback=callback)
242269

243270
@pytest.mark.it("runs the second op only after the first op succeeds")
244271
def test_runs_second_op_after_first_op_succceeds(self, mocker, stage, op, op2, op3, callback):
@@ -338,12 +365,24 @@ def test_calls_callbacK_with_error_when_first_op_and_finally_op_both_fail(
338365
stage.run_ops_serial(op, op2, op3, finally_op=finally_op, callback=callback)
339366
assert_callback_failed(callback=callback, op=finally_op, error=finally_op.error)
340367

341-
@pytest.mark.it("protects the callback with a try/except block")
342-
def test_exception_in_callback(self, stage, op, op2, op3, finally_op, fake_error, mocker):
343-
callback = mocker.Mock(side_effect=fake_error)
368+
@pytest.mark.it(
369+
"handles Exceptions raised in the callback and passes them to the unhandled error handler"
370+
)
371+
def test_callback_raises_exception(
372+
self, stage, op, op2, op3, finally_op, fake_exception, mocker
373+
):
374+
callback = mocker.Mock(side_effect=fake_exception)
344375
stage.run_ops_serial(op, op2, op3, callback=callback, finally_op=finally_op)
345376
assert stage.unhandled_error_handler.call_count == 1
346-
assert stage.unhandled_error_handler.call_args == mocker.call(fake_error)
377+
assert stage.unhandled_error_handler.call_args == mocker.call(fake_exception)
378+
379+
@pytest.mark.it("Allows any BaseExceptions raised in the callback to propagate")
380+
def test_callback_raises_base_exception(
381+
self, stage, op, op2, op3, finally_op, fake_base_exception, mocker
382+
):
383+
callback = mocker.Mock(side_effect=fake_base_exception)
384+
with pytest.raises(UnhandledException):
385+
stage.run_ops_serial(op, op2, op3, callback=callback, finally_op=finally_op)
347386

348387
@pytest.mark.it("runs the second op only after the first op succeeds")
349388
def test_runs_second_op(self, mocker, stage, op, op2, op3, finally_op, callback):
@@ -488,12 +527,22 @@ def test_calls_private_handle_pipeline_event(self, stage, event, mocker):
488527
assert stage._handle_pipeline_event.call_count == 1
489528
assert stage._handle_pipeline_event.call_args == mocker.call(event)
490529

491-
@pytest.mark.it("protects _handle_pipeline_event with a try/except block")
492-
def test_exception_in_provate_handle_pipeline_event(self, stage, event, fake_error, mocker):
493-
stage._handle_pipeline_event = mocker.Mock(side_effect=fake_error)
530+
@pytest.mark.it(
531+
"handles Exceptions raised in _handle_pipeline_Event and passes them to the unhandled error handler"
532+
)
533+
def test_handle_pipeline_events_raises_exception(self, stage, event, fake_exception, mocker):
534+
stage._handle_pipeline_event = mocker.Mock(side_effect=fake_exception)
494535
stage.handle_pipeline_event(event)
495536
assert stage.unhandled_error_handler.call_count == 1
496-
assert stage.unhandled_error_handler.call_args == mocker.call(fake_error)
537+
assert stage.unhandled_error_handler.call_args == mocker.call(fake_exception)
538+
539+
@pytest.mark.it("Allows any BaseExceptions raised in _handle_pipeline_event to propagate")
540+
def test_handle_pipeline_events_raises_base_exception(
541+
self, stage, event, fake_base_exception, mocker
542+
):
543+
stage._handle_pipeline_event = mocker.Mock(side_effect=fake_base_exception)
544+
with pytest.raises(UnhandledException):
545+
stage.handle_pipeline_event(event)
497546

498547

499548
@pytest.mark.describe("PipelineStage _handle_pipeline_event function")
@@ -516,12 +565,11 @@ def test_error_if_no_previous_stage(self, stage, event):
516565
@pytest.mark.describe("PipelineStage continue_op function")
517566
class TestPipelineStageContinueOp(object):
518567
@pytest.mark.it("completes the op without continuing if the op has an error")
519-
def test_completes_op_with_error(self, mocker, stage, op, fake_error, callback):
520-
op.error = fake_error
568+
def test_completes_op_with_error(self, mocker, stage, op, fake_exception, callback):
569+
op.error = fake_exception
521570
op.callback = callback
522571
stage.continue_op(op)
523-
assert callback.call_count == 1
524-
assert callback.call_args == mocker.call(op)
572+
assert_callback_failed(op=op, error=fake_exception)
525573
assert stage.next.run_op.call_count == 0
526574

527575
@pytest.mark.it("fails the op if there is no next stage")
@@ -548,20 +596,28 @@ def test_calls_callback_on_success(self, stage, op, callback):
548596
assert_callback_succeeded(op)
549597

550598
@pytest.mark.it("calls the op callback on failure")
551-
def test_calls_callback_on_error(self, stage, op, callback, fake_error):
552-
op.error = fake_error
599+
def test_calls_callback_on_error(self, stage, op, callback, fake_exception):
600+
op.error = fake_exception
553601
op.callback = callback
554602
stage.complete_op(op)
555-
assert_callback_failed(op=op, error=fake_error)
603+
assert_callback_failed(op=op, error=fake_exception)
556604

557-
@pytest.mark.it("protects the op callback with a try/except handler")
558-
def test_exception_in_callback(self, stage, op, fake_error, mocker):
559-
op.callback = mocker.Mock(side_effect=fake_error)
605+
@pytest.mark.it(
606+
"handles Exceptions raised in operation callback and passes them to the unhandled error handler"
607+
)
608+
def test_op_callback_raises_exception(self, stage, op, fake_exception, mocker):
609+
op.callback = mocker.Mock(side_effect=fake_exception)
560610
stage.complete_op(op)
561611
assert op.callback.call_count == 1
562612
assert op.callback.call_args == mocker.call(op)
563613
assert stage.unhandled_error_handler.call_count == 1
564-
assert stage.unhandled_error_handler.call_args == mocker.call(fake_error)
614+
assert stage.unhandled_error_handler.call_args == mocker.call(fake_exception)
615+
616+
@pytest.mark.it("Allows any BaseExceptions raised in operation callback to propagate")
617+
def test_op_callback_raises_base_exception(self, stage, op, fake_base_exception, mocker):
618+
op.callback = mocker.Mock(side_effect=fake_base_exception)
619+
with pytest.raises(UnhandledException):
620+
stage.complete_op(op)
565621

566622

567623
@pytest.mark.describe("PipelineStage continue_with_different_op function")

0 commit comments

Comments
 (0)