From 564a21d818f7194d84f76fe834b3570de8637d34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Saugat=20Pachhai=20=28=E0=A4=B8=E0=A5=8C=E0=A4=97=E0=A4=BE?= =?UTF-8?q?=E0=A4=A4=29?= Date: Sun, 6 Sep 2026 13:50:03 +0545 Subject: [PATCH 1/5] test on Python 3.15 --- .github/workflows/tests.yml | 2 +- pyproject.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 692ba39..254c69e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,7 +21,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] - pyv: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + pyv: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14', '3.15'] steps: - name: Check out the repository diff --git a/pyproject.toml b/pyproject.toml index e4912b3..be23999 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,6 +19,7 @@ classifiers = [ "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: 3.15", "Development Status :: 4 - Beta", ] requires-python = ">=3.9" From a8e5601ba4f81357c6ede33cdc35f518d3187166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Saugat=20Pachhai=20=28=E0=A4=B8=E0=A5=8C=E0=A4=97=E0=A4=BE?= =?UTF-8?q?=E0=A4=A4=29?= Date: Fri, 6 Nov 2026 13:29:28 +0545 Subject: [PATCH 2/5] avoid deprecated os.path.commonprefix os.path.commonprefix() emits a DeprecationWarning on Python 3.15. Use os.path.commonpath() to detect paths on different drives in relpath(), and compute FileSystem.commonprefix() directly so its character-wise behavior is unchanged. Co-Authored-By: Claude Opus 5.5 --- src/dvc_objects/fs/base.py | 9 ++++++++- src/dvc_objects/fs/utils.py | 5 ++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/dvc_objects/fs/base.py b/src/dvc_objects/fs/base.py index 0fe15ba..766a7eb 100644 --- a/src/dvc_objects/fs/base.py +++ b/src/dvc_objects/fs/base.py @@ -135,7 +135,14 @@ def abspath(self, path: str) -> str: @classmethod def commonprefix(cls, paths: Sequence[str]) -> str: - return cls.flavour.commonprefix(paths) + # os.path.commonprefix() is deprecated since Python 3.15 + if not paths: + return "" + s1, s2 = min(paths), max(paths) + for i, c in enumerate(s1): + if c != s2[i]: + return s1[:i] + return s1 @classmethod def commonpath(cls, paths: Iterable[str]) -> str: diff --git a/src/dvc_objects/fs/utils.py b/src/dvc_objects/fs/utils.py index f7e0e1f..e8166d3 100644 --- a/src/dvc_objects/fs/utils.py +++ b/src/dvc_objects/fs/utils.py @@ -53,7 +53,10 @@ def resolve_network_drive_windows(path_to_resolve): path = resolve_network_drive_windows(os.path.abspath(path)) start = resolve_network_drive_windows(start) - if not os.path.commonprefix([start, path]): + try: + os.path.commonpath([start, path]) + except ValueError: + # paths are on different drives return path return os.path.relpath(path, start) From caa59404a1bc779d3301258ee0a4aecba87b3443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Saugat=20Pachhai=20=28=E0=A4=B8=E0=A5=8C=E0=A4=97=E0=A4=BE?= =?UTF-8?q?=E0=A4=A4=29?= Date: Fri, 6 Nov 2026 13:35:22 +0545 Subject: [PATCH 3/5] set asyncio_default_fixture_loop_scope for pytest-asyncio pytest-asyncio 1.4.1 with pytest 9.2 raises PytestDeprecationWarning when the option is unset, which -Werror turns into an INTERNALERROR. The option exists since pytest-asyncio 0.24, so raise the floor. Co-Authored-By: Claude Opus 5.5 --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index be23999..46d0e7e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,7 @@ tests = [ "pytest-cov>=4.1.0", "pytest-mock", "pytest-benchmark", - "pytest-asyncio>=0.23.2,<2", + "pytest-asyncio>=0.24,<2", "reflink", ] dev = [ @@ -57,6 +57,7 @@ dvc_objects = ["py.typed"] [tool.pytest.ini_options] addopts = "-ra -Werror --benchmark-skip" +asyncio_default_fixture_loop_scope = "function" [tool.coverage.run] branch = true From 244c454c5b31dd4b464071f8b509abd383fac3bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Saugat=20Pachhai=20=28=E0=A4=B8=E0=A5=8C=E0=A4=97=E0=A4=BE?= =?UTF-8?q?=E0=A4=A4=29?= Date: Fri, 6 Nov 2026 13:49:07 +0545 Subject: [PATCH 4/5] remove FileSystem.commonprefix It compared paths character by character (e.g. "/a/bc" and "/a/bd" give "/a/b"), which is not a path operation. CPython deprecated os.path.commonprefix in 3.15 for the same reason and recommends os.path.commonpath; use FileSystem.commonpath instead. No callers in dvc, dvc-data, scmrepo or the dvc remote plugins. Co-Authored-By: Claude Opus 5.5 --- src/dvc_objects/fs/base.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/dvc_objects/fs/base.py b/src/dvc_objects/fs/base.py index 766a7eb..29e1b56 100644 --- a/src/dvc_objects/fs/base.py +++ b/src/dvc_objects/fs/base.py @@ -5,7 +5,7 @@ import os import posixpath import shutil -from collections.abc import Iterable, Iterator, Sequence +from collections.abc import Iterable, Iterator from functools import partial from multiprocessing import cpu_count from typing import ( @@ -133,17 +133,6 @@ def abspath(self, path: str) -> str: path = self.join(self.getcwd(), path) return self.normpath(path) - @classmethod - def commonprefix(cls, paths: Sequence[str]) -> str: - # os.path.commonprefix() is deprecated since Python 3.15 - if not paths: - return "" - s1, s2 = min(paths), max(paths) - for i, c in enumerate(s1): - if c != s2[i]: - return s1[:i] - return s1 - @classmethod def commonpath(cls, paths: Iterable[str]) -> str: return cls.flavour.commonpath(list(paths)) From 475838d00ddaca7d060119bf07d3309582ed3f81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Saugat=20Pachhai=20=28=E0=A4=B8=E0=A5=8C=E0=A4=97=E0=A4=BE?= =?UTF-8?q?=E0=A4=A4=29?= Date: Fri, 6 Nov 2026 13:53:33 +0545 Subject: [PATCH 5/5] release: build on Python 3.15 Co-Authored-By: Claude Opus 5.5 --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 30d53f9..66d36bb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,10 +21,10 @@ jobs: with: fetch-depth: 0 - - name: Set up Python 3.14 + - name: Set up Python 3.15 uses: actions/setup-python@v6 with: - python-version: '3.14' + python-version: '3.15' - name: Upgrade pip and nox run: |