From e124cb97a0f94977103247b619e4e22fcc83f0ea Mon Sep 17 00:00:00 2001
From: Steve Kowalik <steven@wedontsleep.org>
Date: Tue, 11 Aug 2026 15:03:16 +1000
Subject: [PATCH] Switch to os.path.commonpath

os.path.commonprefix has been deprecated for a few Python releases, and
finally removed as of Python 3.15. os.path.commonpath is the
replacement, switch to using it, and write a test to make certain there
was no behavior changes.
---
 param/_utils.py     |  6 +++---
 param/parameters.py |  2 +-
 tests/testutils.py  | 15 +++++++++++++++
 3 files changed, 19 insertions(+), 4 deletions(-)

Index: python-param/param/_utils.py
===================================================================
--- python-param.orig/param/_utils.py
+++ python-param/param/_utils.py
@@ -541,10 +541,10 @@ def _abbreviate_paths(pathspec,named_pat
     Given a dict of (pathname,path) pairs, removes any prefix shared by all pathnames.
     Helps keep menu items short yet unambiguous.
     """
-    from os.path import commonprefix, dirname, sep
+    from os.path import commonpath, dirname, sep
 
-    prefix = commonprefix([dirname(name)+sep for name in named_paths.keys()]+[pathspec])
-    return OrderedDict([(name[len(prefix):],path) for name,path in named_paths.items()])
+    prefix = commonpath([dirname(name)+sep for name in named_paths.keys()]+[pathspec])
+    return OrderedDict([(name[len(prefix)+1:],path) for name,path in named_paths.items()])
 
 
 # PARAM3_DEPRECATION
Index: python-param/tests/testutils.py
===================================================================
--- python-param.orig/tests/testutils.py
+++ python-param/tests/testutils.py
@@ -1,14 +1,16 @@
 import datetime as dt
 import os
 
+from collections import OrderedDict
 from functools import partial
+from tempfile import TemporaryDirectory
 
 import param
 import pytest
 
 from param import guess_param_types, resolve_path
 from param.parameterized import bothmethod
-from param._utils import _is_mutable_container, iscoroutinefunction
+from param._utils import _abbreviate_paths, _is_mutable_container, iscoroutinefunction
 
 
 try:
@@ -421,3 +423,15 @@ def test_iscoroutinefunction_asyncgen():
 def test_iscoroutinefunction_partial_asyncgen():
     pagen = partial(partial(agen))
     assert iscoroutinefunction(pagen)
+
+def test_abbreviate_paths():
+    ranges = OrderedDict()
+    expected = OrderedDict()
+    with TemporaryDirectory() as tempdir:
+        path = f"{tempdir}/*"
+        for filename in ("a.txt", "f.txt"):
+            fullpath = f"{tempdir}/{filename}"
+            ranges[fullpath] = fullpath
+            expected[filename] = fullpath
+    assert _abbreviate_paths(path, ranges) == expected
+
