Skip to content

Commit 6459ca0

Browse files
committed
Fix referenced inherited methods
1 parent 311b46d commit 6459ca0

File tree

4 files changed

+39
-7
lines changed

4 files changed

+39
-7
lines changed

aws_xray_sdk/core/patcher.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ def _is_valid_import(module):
5050
is_module = os.path.isdir(realpath) and (
5151
os.path.isfile('{}/__init__.py'.format(module)) or os.path.isfile('{}/__init__.pyc'.format(module))
5252
)
53-
is_file = os.path.isfile('{}.py'.format(module)) or os.path.isfile('{}.pyc'.format(module))
53+
is_file = not is_module and (
54+
os.path.isfile('{}.py'.format(module)) or os.path.isfile('{}.pyc'.format(module))
55+
)
5456
return is_module or is_file
5557

5658

@@ -113,6 +115,10 @@ def _patch(module_to_patch):
113115

114116

115117
def _patch_func(parent, func_name, func, modifier=lambda x: x):
118+
if func_name not in parent.__dict__:
119+
# Ignore functions not directly defined in parent, i.e. exclude inherited ones
120+
return
121+
116122
from aws_xray_sdk.core import xray_recorder
117123

118124
capture_name = func_name
@@ -129,12 +135,12 @@ def _patch_class(module, cls):
129135

130136
for member_name, member in inspect.getmembers(cls, inspect.ismethod):
131137
if member.__module__ == module.__name__:
132-
# Only patch methods of the class defined in the module, ignore inherited
138+
# Only patch methods of the class defined in the module, ignore other modules
133139
_patch_func(cls, member_name, member)
134140

135141
for member_name, member in inspect.getmembers(cls, inspect.isfunction):
136142
if member.__module__ == module.__name__:
137-
# Only patch static methods of the class defined in the module, ignore inherited
143+
# Only patch static methods of the class defined in the module, ignore other modules
138144
if is_instance_method(cls, member_name, member):
139145
_patch_func(cls, member_name, member)
140146
else:

aws_xray_sdk/core/utils/compat.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import inspect
12
import sys
23

34

@@ -13,4 +14,14 @@
1314

1415

1516
def is_instance_method(parent_class, func_name, func):
16-
return getattr(func, '__self__', None) is None and not isinstance(parent_class.__dict__[func_name], staticmethod)
17+
try:
18+
func_from_dict = parent_class.__dict__[func_name]
19+
except KeyError:
20+
for base in inspect.getmro(parent_class):
21+
if func_name in base.__dict__:
22+
func_from_dict = base.__dict__[func_name]
23+
break
24+
else:
25+
return True
26+
27+
return getattr(func, '__self__', None) is None and not isinstance(func_from_dict, staticmethod)

tests/mock_module/mock_submodule/mock_subfile.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,11 @@ def mock_classmethod(cls):
2424
@staticmethod
2525
def mock_staticmethod():
2626
pass
27+
28+
29+
class MockSubclass(MockClass):
30+
def __init__(self):
31+
super(MockSubclass, self).__init__()
32+
33+
def mock_submethod(self):
34+
pass

tests/test_patcher.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def _call_all_mock_functions():
6868
mock_subfile.MockClass.mock_classmethod()
6969
mock_subfile.MockClass.mock_staticmethod()
7070
mock_subfile.MockClass().mock_method()
71+
mock_subfile.MockSubclass().mock_submethod()
7172

7273

7374
@pytest.mark.parametrize('modules', [
@@ -104,14 +105,16 @@ def test_external_module():
104105

105106
_call_all_mock_functions()
106107

107-
assert len(xray_recorder.current_segment().subsegments) == 7
108+
assert len(xray_recorder.current_segment().subsegments) == 9
108109
assert xray_recorder.current_segment().subsegments[0].name == 'mock_subinit'
109110
assert xray_recorder.current_segment().subsegments[1].name == 'mock_subfunc'
110111
assert xray_recorder.current_segment().subsegments[2].name == 'mock_no_doublepatch' # Should appear only once
111112
assert xray_recorder.current_segment().subsegments[3].name == 'mock_classmethod'
112113
assert xray_recorder.current_segment().subsegments[4].name == 'mock_staticmethod'
113114
assert xray_recorder.current_segment().subsegments[5].name == 'MockClass.__init__'
114115
assert xray_recorder.current_segment().subsegments[6].name == 'mock_method'
116+
assert xray_recorder.current_segment().subsegments[7].name == 'MockSubclass.__init__'
117+
assert xray_recorder.current_segment().subsegments[8].name == 'mock_submethod'
115118

116119

117120
def test_external_submodules_full():
@@ -123,7 +126,7 @@ def test_external_submodules_full():
123126

124127
_call_all_mock_functions()
125128

126-
assert len(xray_recorder.current_segment().subsegments) == 9
129+
assert len(xray_recorder.current_segment().subsegments) == 11
127130
assert xray_recorder.current_segment().subsegments[0].name == 'mock_init'
128131
assert xray_recorder.current_segment().subsegments[1].name == 'mock_subinit'
129132
assert xray_recorder.current_segment().subsegments[2].name == 'mock_func'
@@ -133,6 +136,8 @@ def test_external_submodules_full():
133136
assert xray_recorder.current_segment().subsegments[6].name == 'mock_staticmethod'
134137
assert xray_recorder.current_segment().subsegments[7].name == 'MockClass.__init__'
135138
assert xray_recorder.current_segment().subsegments[8].name == 'mock_method'
139+
assert xray_recorder.current_segment().subsegments[9].name == 'MockSubclass.__init__'
140+
assert xray_recorder.current_segment().subsegments[10].name == 'mock_submethod'
136141

137142

138143
def test_external_submodules_ignores_file():
@@ -144,7 +149,7 @@ def test_external_submodules_ignores_file():
144149

145150
_call_all_mock_functions()
146151

147-
assert len(xray_recorder.current_segment().subsegments) == 8
152+
assert len(xray_recorder.current_segment().subsegments) == 10
148153
assert xray_recorder.current_segment().subsegments[0].name == 'mock_init'
149154
assert xray_recorder.current_segment().subsegments[1].name == 'mock_subinit'
150155
assert xray_recorder.current_segment().subsegments[2].name == 'mock_subfunc'
@@ -153,6 +158,8 @@ def test_external_submodules_ignores_file():
153158
assert xray_recorder.current_segment().subsegments[5].name == 'mock_staticmethod'
154159
assert xray_recorder.current_segment().subsegments[6].name == 'MockClass.__init__'
155160
assert xray_recorder.current_segment().subsegments[7].name == 'mock_method'
161+
assert xray_recorder.current_segment().subsegments[8].name == 'MockSubclass.__init__'
162+
assert xray_recorder.current_segment().subsegments[9].name == 'mock_submethod'
156163

157164

158165
def test_external_submodules_ignores_module():

0 commit comments

Comments
 (0)