Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions Lib/pstats.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,14 @@ class FunctionProfile:
file_name: str
line_number: int

FunctionLoc = tuple[str, int, str] # filename, line number, function name

@dataclass(unsafe_hash=True)
class StatsProfile:
'''Class for keeping track of an item in inventory.'''
total_tt: float
func_profiles: dict[str, FunctionProfile]
func_profiles: dict[tuple[str, int, str], FunctionProfile]
func_profiles_by_loc: dict[FunctionLoc, FunctionProfile]

class Stats:
"""This class is used for creating reports from data generated by the
Expand Down Expand Up @@ -366,7 +369,8 @@ def get_stats_profile(self):

total_tt = float(f8(self.total_tt))
func_profiles = {}
stats_profile = StatsProfile(total_tt, func_profiles)
func_profiles_by_loc = {}
stats_profile = StatsProfile(total_tt, func_profiles, func_profiles_by_loc)

for func in func_list:
cc, nc, tt, ct, callers = self.stats[func]
Expand All @@ -386,6 +390,7 @@ def get_stats_profile(self):
line_number
)
func_profiles[func_name] = func_profile
func_profiles_by_loc[func] = func_profile

return stats_profile

Expand Down
29 changes: 29 additions & 0 deletions Lib/test/test_pstats.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,35 @@ def pass3(): pass
self.assertIn('pass2', funcs_called)
self.assertIn('pass3', funcs_called)

def test_get_stats_profile_duplicate_func_names(self):
class Test1:
def pass_fn(self):
pass

class Test2:
def pass_fn(self):
pass

def main():
Test1().pass_fn()
Test2().pass_fn()

pr = cProfile.Profile()
pr.enable()
main()
pr.create_stats()
ps = pstats.Stats(pr)
stats_profile = ps.get_stats_profile()
# Functions with same name have different keys in func_profiles_by_loc
pass_fn_keys = [
(file_name, line_number, func_name)
for file_name, line_number, func_name
in stats_profile.func_profiles_by_loc
if func_name == "pass_fn"
]

self.assertEqual(len(pass_fn_keys), 2)

def test_SortKey_enum(self):
self.assertEqual(SortKey.FILENAME, 'filename')
self.assertNotEqual(SortKey.FILENAME, SortKey.CALLS)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Add an attribute to the object returned by :func:`pstats.Stats.get_stats_profile` to access
function profiles disambiguated by file name and line number. This handles cases
where multiple functions share the same name in profiling programs. Contributed by Edward Thomas.
Loading