From ac0a4e044b8b826bc47018a9131bb5c4050fe0d2 Mon Sep 17 00:00:00 2001 From: Edward Thomas Date: Sat, 9 May 2026 21:34:10 +0100 Subject: [PATCH 1/4] Handle multiple functions with same name in StatsProfile --- Lib/pstats.py | 9 +++++++-- Lib/test/test_pstats.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/Lib/pstats.py b/Lib/pstats.py index 07ecda07796e44..14c62a0ca53d28 100644 --- a/Lib/pstats.py +++ b/Lib/pstats.py @@ -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 @@ -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] @@ -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 diff --git a/Lib/test/test_pstats.py b/Lib/test/test_pstats.py index a26a8c1d522a70..89287b0cb792e1 100644 --- a/Lib/test/test_pstats.py +++ b/Lib/test/test_pstats.py @@ -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) From 94c62c45712e29defe813c0d3e0f2892eaa5454b Mon Sep 17 00:00:00 2001 From: Edward Thomas Date: Sat, 9 May 2026 22:12:37 +0100 Subject: [PATCH 2/4] Fix lint --- Lib/test/test_pstats.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_pstats.py b/Lib/test/test_pstats.py index 89287b0cb792e1..bb8be695abc9ea 100644 --- a/Lib/test/test_pstats.py +++ b/Lib/test/test_pstats.py @@ -155,7 +155,7 @@ def test_get_stats_profile_duplicate_func_names(self): class Test1: def pass_fn(self): pass - + class Test2: def pass_fn(self): pass From 8e46a18dbadb04159eaf3bdcb3dac926a4a114c4 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sat, 9 May 2026 21:18:16 +0000 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Library/2026-05-09-21-18-15.gh-issue-126850.om89px.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-05-09-21-18-15.gh-issue-126850.om89px.rst diff --git a/Misc/NEWS.d/next/Library/2026-05-09-21-18-15.gh-issue-126850.om89px.rst b/Misc/NEWS.d/next/Library/2026-05-09-21-18-15.gh-issue-126850.om89px.rst new file mode 100644 index 00000000000000..54616c254a26e6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-09-21-18-15.gh-issue-126850.om89px.rst @@ -0,0 +1,3 @@ +Add an attribute to the object returned by :func:`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. From 4f5aef870d8492f5dfeca862fedb7fe95d19c091 Mon Sep 17 00:00:00 2001 From: Edward Thomas Date: Sat, 9 May 2026 22:29:08 +0100 Subject: [PATCH 4/4] Correct func reference in NEWS entry --- .../Library/2026-05-09-21-18-15.gh-issue-126850.om89px.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2026-05-09-21-18-15.gh-issue-126850.om89px.rst b/Misc/NEWS.d/next/Library/2026-05-09-21-18-15.gh-issue-126850.om89px.rst index 54616c254a26e6..cf40b8e15041e6 100644 --- a/Misc/NEWS.d/next/Library/2026-05-09-21-18-15.gh-issue-126850.om89px.rst +++ b/Misc/NEWS.d/next/Library/2026-05-09-21-18-15.gh-issue-126850.om89px.rst @@ -1,3 +1,3 @@ -Add an attribute to the object returned by :func:`Stats.get_stats_profile` to access -function profiles disambiguated by file name and line number. This handles cases +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.