Skip to content

Commit 620b148

Browse files
authored
Use importlib instead of deprecated imp module (#28)
1 parent 7afc4c4 commit 620b148

File tree

4 files changed

+97
-102
lines changed

4 files changed

+97
-102
lines changed

Diff for: .gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,6 @@ dmypy.json
143143

144144
# Cython debug symbols
145145
cython_debug/
146+
147+
# Test files generated
148+
tmp*.py

Diff for: awslambdaric/bootstrap.py

+9-25
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,19 @@
22
Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
33
"""
44

5+
import importlib
56
import json
67
import logging
78
import os
89
import sys
910
import time
1011
import traceback
11-
import warnings
1212

1313
from .lambda_context import LambdaContext
1414
from .lambda_runtime_client import LambdaRuntimeClient
1515
from .lambda_runtime_exception import FaultException
1616
from .lambda_runtime_marshaller import to_json
1717

18-
with warnings.catch_warnings():
19-
warnings.filterwarnings("ignore", category=DeprecationWarning)
20-
import imp
21-
2218
ERROR_LOG_LINE_TERMINATE = "\r"
2319
ERROR_LOG_IDENT = "\u00a0" # NO-BREAK SPACE U+00A0
2420

@@ -33,23 +29,14 @@ def _get_handler(handler):
3329
)
3430
return make_fault_handler(fault)
3531

36-
file_handle, pathname, desc = None, None, None
3732
try:
38-
# Recursively loading handler in nested directories
39-
for segment in modname.split("."):
40-
if pathname is not None:
41-
pathname = [pathname]
42-
file_handle, pathname, desc = imp.find_module(segment, pathname)
43-
if file_handle is None:
44-
module_type = desc[2]
45-
if module_type == imp.C_BUILTIN:
46-
fault = FaultException(
47-
FaultException.BUILT_IN_MODULE_CONFLICT,
48-
"Cannot use built-in module {} as a handler module".format(modname),
49-
)
50-
request_handler = make_fault_handler(fault)
51-
return request_handler
52-
m = imp.load_module(modname, file_handle, pathname, desc)
33+
if modname.split(".")[0] in sys.builtin_module_names:
34+
fault = FaultException(
35+
FaultException.BUILT_IN_MODULE_CONFLICT,
36+
"Cannot use built-in module {} as a handler module".format(modname),
37+
)
38+
return make_fault_handler(fault)
39+
m = importlib.import_module(modname)
5340
except ImportError as e:
5441
fault = FaultException(
5542
FaultException.IMPORT_MODULE_ERROR,
@@ -66,9 +53,6 @@ def _get_handler(handler):
6653
)
6754
request_handler = make_fault_handler(fault)
6855
return request_handler
69-
finally:
70-
if file_handle is not None:
71-
file_handle.close()
7256

7357
try:
7458
request_handler = getattr(m, fname)
@@ -402,7 +386,7 @@ def run(app_root, handler, lambda_runtime_api_addr):
402386
global _GLOBAL_AWS_REQUEST_ID
403387

404388
request_handler = _get_handler(handler)
405-
except Exception as e:
389+
except Exception:
406390
error_result = build_fault_result(sys.exc_info(), None)
407391

408392
log_error(error_result, log_sink)

Diff for: requirements/dev.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ coverage>=4.4.0
22
flake8>=3.3.0
33
tox>=2.2.1
44
pytest-cov>=2.4.0
5-
pylint>=1.7.2,<2.0
5+
pylint>=1.7.2
66
black>=20.8b0
77
bandit>=1.6.2
88

Diff for: tests/test_bootstrap.py

+84-76
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@
22
Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
33
"""
44

5+
import importlib
56
import json
67
import os
78
import re
89
import tempfile
910
import traceback
1011
import unittest
11-
from imp import C_BUILTIN
1212
from io import StringIO
1313
from tempfile import NamedTemporaryFile
14-
from unittest.mock import patch, Mock, MagicMock
14+
from unittest.mock import MagicMock, Mock, patch
1515

1616
import awslambdaric.bootstrap as bootstrap
1717
from awslambdaric.lambda_runtime_exception import FaultException
@@ -350,7 +350,7 @@ def __init__(self, message):
350350

351351
def test_handle_event_request_no_module(self):
352352
def unable_to_import_module(json_input, lambda_context):
353-
import invalid_module
353+
import invalid_module # noqa: F401
354354

355355
expected_response = {
356356
"errorType": "ModuleNotFoundError",
@@ -381,8 +381,8 @@ def unable_to_import_module(json_input, lambda_context):
381381
def test_handle_event_request_fault_exception(self):
382382
def raise_exception_handler(json_input, lambda_context):
383383
try:
384-
import invalid_module
385-
except ImportError as e:
384+
import invalid_module # noqa: F401
385+
except ImportError:
386386
raise FaultException(
387387
"FaultExceptionType",
388388
"Fault exception msg",
@@ -429,8 +429,8 @@ def raise_exception_handler(json_input, lambda_context):
429429
def test_handle_event_request_fault_exception_logging(self, mock_stdout):
430430
def raise_exception_handler(json_input, lambda_context):
431431
try:
432-
import invalid_module
433-
except ImportError as e:
432+
import invalid_module # noqa: F401
433+
except ImportError:
434434
raise bootstrap.FaultException(
435435
"FaultExceptionType",
436436
"Fault exception msg",
@@ -469,8 +469,8 @@ def raise_exception_handler(json_input, lambda_context):
469469
def test_handle_event_request_fault_exception_logging_notrace(self, mock_stdout):
470470
def raise_exception_handler(json_input, lambda_context):
471471
try:
472-
import invalid_module
473-
except ImportError as e:
472+
import invalid_module # noqa: F401
473+
except ImportError:
474474
raise bootstrap.FaultException(
475475
"FaultExceptionType", "Fault exception msg", None
476476
)
@@ -497,8 +497,8 @@ def test_handle_event_request_fault_exception_logging_nomessage_notrace(
497497
):
498498
def raise_exception_handler(json_input, lambda_context):
499499
try:
500-
import invalid_module
501-
except ImportError as e:
500+
import invalid_module # noqa: F401
501+
except ImportError:
502502
raise bootstrap.FaultException("FaultExceptionType", None, None)
503503

504504
bootstrap.handle_event_request(
@@ -523,8 +523,8 @@ def test_handle_event_request_fault_exception_logging_notype_notrace(
523523
):
524524
def raise_exception_handler(json_input, lambda_context):
525525
try:
526-
import invalid_module
527-
except ImportError as e:
526+
import invalid_module # noqa: F401
527+
except ImportError:
528528
raise bootstrap.FaultException(None, "Fault exception msg", None)
529529

530530
bootstrap.handle_event_request(
@@ -549,8 +549,8 @@ def test_handle_event_request_fault_exception_logging_notype_nomessage(
549549
):
550550
def raise_exception_handler(json_input, lambda_context):
551551
try:
552-
import invalid_module
553-
except ImportError as e:
552+
import invalid_module # noqa: F401
553+
except ImportError:
554554
raise bootstrap.FaultException(
555555
None,
556556
None,
@@ -585,19 +585,16 @@ def raise_exception_handler(json_input, lambda_context):
585585
self.assertEqual(mock_stdout.getvalue(), error_logs)
586586

587587
@patch("sys.stdout", new_callable=StringIO)
588-
@patch("imp.find_module")
589-
@patch("imp.load_module")
588+
@patch("importlib.import_module")
590589
def test_handle_event_request_fault_exception_logging_syntax_error(
591-
self, mock_load_module, mock_find_module, mock_stdout
590+
self, mock_import_module, mock_stdout
592591
):
593-
594592
try:
595593
eval("-")
596594
except SyntaxError as e:
597595
syntax_error = e
598596

599-
mock_find_module.return_value = (None, None, ("", "", None))
600-
mock_load_module.side_effect = syntax_error
597+
mock_import_module.side_effect = syntax_error
601598

602599
response_handler = bootstrap._get_handler("a.b")
603600

@@ -618,7 +615,10 @@ def test_handle_event_request_fault_exception_logging_syntax_error(
618615

619616
sys.stderr.write(mock_stdout.getvalue())
620617

621-
error_logs = "[ERROR] Runtime.UserCodeSyntaxError: Syntax error in module 'a': unexpected EOF while parsing (<string>, line 1)\r"
618+
error_logs = (
619+
"[ERROR] Runtime.UserCodeSyntaxError: Syntax error in module 'a': "
620+
"unexpected EOF while parsing (<string>, line 1)\r"
621+
)
622622
error_logs += "Traceback (most recent call last):\r"
623623
error_logs += '  File "<string>" Line 1\r'
624624
error_logs += "    -\n"
@@ -730,56 +730,57 @@ def test_get_event_handler_import_error(self):
730730
)
731731

732732
def test_get_event_handler_syntax_error(self):
733-
tmp_file = tempfile.NamedTemporaryFile(suffix=".py", dir=".", delete=False)
734-
tmp_file.write(
735-
b"def syntax_error()\n\tprint('syntax error, no colon after function')"
736-
)
737-
tmp_file.close()
738-
filename_w_ext = os.path.basename(tmp_file.name)
739-
filename, _ = os.path.splitext(filename_w_ext)
740-
handler_name = "{}.syntax_error".format(filename)
741-
response_handler = bootstrap._get_handler(handler_name)
742-
743-
with self.assertRaises(FaultException) as cm:
744-
response_handler()
745-
returned_exception = cm.exception
746-
self.assertEqual(
747-
self.FaultExceptionMatcher(
748-
"Syntax error in",
749-
"Runtime.UserCodeSyntaxError",
750-
".*File.*\\.py.*Line 1.*",
751-
),
752-
returned_exception,
753-
)
754-
if os.path.exists(tmp_file.name):
755-
os.remove(tmp_file.name)
733+
importlib.invalidate_caches()
734+
with tempfile.NamedTemporaryFile(
735+
suffix=".py", dir=".", delete=False
736+
) as tmp_file:
737+
tmp_file.write(
738+
b"def syntax_error()\n\tprint('syntax error, no colon after function')"
739+
)
740+
tmp_file.flush()
741+
742+
filename_w_ext = os.path.basename(tmp_file.name)
743+
filename, _ = os.path.splitext(filename_w_ext)
744+
handler_name = "{}.syntax_error".format(filename)
745+
response_handler = bootstrap._get_handler(handler_name)
746+
747+
with self.assertRaises(FaultException) as cm:
748+
response_handler()
749+
returned_exception = cm.exception
750+
self.assertEqual(
751+
self.FaultExceptionMatcher(
752+
"Syntax error in",
753+
"Runtime.UserCodeSyntaxError",
754+
".*File.*\\.py.*Line 1.*",
755+
),
756+
returned_exception,
757+
)
756758

757759
def test_get_event_handler_missing_error(self):
758-
tmp_file = tempfile.NamedTemporaryFile(suffix=".py", dir=".", delete=False)
759-
tmp_file.write(b"def wrong_handler_name():\n\tprint('hello')")
760-
tmp_file.close()
761-
filename_w_ext = os.path.basename(tmp_file.name)
762-
filename, _ = os.path.splitext(filename_w_ext)
763-
handler_name = "{}.my_handler".format(filename)
764-
response_handler = bootstrap._get_handler(handler_name)
765-
with self.assertRaises(FaultException) as cm:
766-
response_handler()
767-
returned_exception = cm.exception
768-
self.assertEqual(
769-
self.FaultExceptionMatcher(
770-
"Handler 'my_handler' missing on module '{}'".format(filename),
771-
"Runtime.HandlerNotFound",
772-
),
773-
returned_exception,
774-
)
775-
if os.path.exists(tmp_file.name):
776-
os.remove(tmp_file.name)
760+
importlib.invalidate_caches()
761+
with tempfile.NamedTemporaryFile(
762+
suffix=".py", dir=".", delete=False
763+
) as tmp_file:
764+
tmp_file.write(b"def wrong_handler_name():\n\tprint('hello')")
765+
tmp_file.flush()
766+
767+
filename_w_ext = os.path.basename(tmp_file.name)
768+
filename, _ = os.path.splitext(filename_w_ext)
769+
handler_name = "{}.my_handler".format(filename)
770+
response_handler = bootstrap._get_handler(handler_name)
771+
with self.assertRaises(FaultException) as cm:
772+
response_handler()
773+
returned_exception = cm.exception
774+
self.assertEqual(
775+
self.FaultExceptionMatcher(
776+
"Handler 'my_handler' missing on module '{}'".format(filename),
777+
"Runtime.HandlerNotFound",
778+
),
779+
returned_exception,
780+
)
777781

778-
@patch("imp.find_module")
779-
def test_get_event_handler_build_in_conflict(self, mock_find_module):
780-
handler_name = "sys.hello"
781-
mock_find_module.return_value = (None, None, ("", "", C_BUILTIN))
782-
response_handler = bootstrap._get_handler(handler_name)
782+
def test_get_event_handler_build_in_conflict(self):
783+
response_handler = bootstrap._get_handler("sys.hello")
783784
with self.assertRaises(FaultException) as cm:
784785
response_handler()
785786
returned_exception = cm.exception
@@ -921,7 +922,10 @@ def test_log_error_indentation_standard_log_sink(self, mock_stdout):
921922
)
922923
bootstrap.log_error(err_to_log, bootstrap.StandardLogSink())
923924

924-
expected_logged_error = "[ERROR] ErrorType: Error message\rTraceback (most recent call last):\r\xa0\xa0line1 \r\xa0\xa0line2 \r\xa0\xa0\n"
925+
expected_logged_error = (
926+
"[ERROR] ErrorType: Error message\rTraceback (most recent call last):"
927+
"\r\xa0\xa0line1 \r\xa0\xa0line2 \r\xa0\xa0\n"
928+
)
925929
self.assertEqual(mock_stdout.getvalue(), expected_logged_error)
926930

927931
def test_log_error_indentation_framed_log_sink(self):
@@ -932,7 +936,10 @@ def test_log_error_indentation_framed_log_sink(self):
932936
)
933937
bootstrap.log_error(err_to_log, log_sink)
934938

935-
expected_logged_error = "[ERROR] ErrorType: Error message\nTraceback (most recent call last):\n\xa0\xa0line1 \n\xa0\xa0line2 \n\xa0\xa0"
939+
expected_logged_error = (
940+
"[ERROR] ErrorType: Error message\nTraceback (most recent call last):"
941+
"\n\xa0\xa0line1 \n\xa0\xa0line2 \n\xa0\xa0"
942+
)
936943

937944
with open(temp_file.name, "rb") as f:
938945
content = f.read()
@@ -964,7 +971,10 @@ def test_log_error_empty_stacktrace_line_framed_log_sink(self):
964971
)
965972
bootstrap.log_error(err_to_log, log_sink)
966973

967-
expected_logged_error = "[ERROR] ErrorType: Error message\nTraceback (most recent call last):\nline1\n\nline2"
974+
expected_logged_error = (
975+
"[ERROR] ErrorType: Error message\nTraceback "
976+
"(most recent call last):\nline1\n\nline2"
977+
)
968978

969979
with open(temp_file.name, "rb") as f:
970980
content = f.read()
@@ -1082,11 +1092,10 @@ def test_run(self, mock_runtime_client, mock_handle_event_request):
10821092
MagicMock(),
10831093
]
10841094

1085-
with self.assertRaises(TypeError) as cm:
1095+
with self.assertRaises(TypeError):
10861096
bootstrap.run(
10871097
expected_app_root, expected_handler, expected_lambda_runtime_api_addr
10881098
)
1089-
returned_exception = cm.exception
10901099

10911100
mock_handle_event_request.assert_called_once()
10921101

@@ -1108,11 +1117,10 @@ class TestException(Exception):
11081117

11091118
mock_sys.exit.side_effect = TestException("Boom!")
11101119

1111-
with self.assertRaises(TestException) as cm:
1120+
with self.assertRaises(TestException):
11121121
bootstrap.run(
11131122
expected_app_root, expected_handler, expected_lambda_runtime_api_addr
11141123
)
1115-
returned_exception = cm.exception
11161124

11171125
mock_sys.exit.assert_called_once_with(1)
11181126

0 commit comments

Comments
 (0)