Compare commits

..
Author SHA1 Message Date
Claude 291bb79836 fix: use Self return type for SCMContext.__enter__ and __call__
Return self directly in __enter__ instead of the @contextmanager's
__enter__() return value. Also update __call__ to return
Iterator[Self]. They're semantically identical (the contextmanager
yields self), but this satisfies both ruff PYI034 and mypy.

https://claude.ai/code/session_01M18n2k6KLenwMRANgSFMXc
2026-02-11 08:15:06 +00:00
Claude c541954a80 fix: resolve ruff v0.15.0 linter errors
- PYI034: Use `Self` return type for `__enter__` in SCMContext
- PLW0108: Replace unnecessary lambda with direct `bool` reference

https://claude.ai/code/session_01M18n2k6KLenwMRANgSFMXc
2026-02-11 07:45:58 +00:00
pre-commit-ci[bot] 6073f3f197 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2026-02-09 23:34:55 +00:00
pre-commit-ci[bot] 656689fbe9 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.14.13 → v0.15.0](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.13...v0.15.0)
2026-02-09 23:34:42 +00:00
19 changed files with 60 additions and 138 deletions
+3 -3
View File
@@ -14,11 +14,11 @@ jobs:
name: run benchmarks
runs-on: ubuntu-latest
steps:
- uses: actions/setup-python@v7
- uses: actions/setup-python@v6
with:
python-version: "3.14"
- uses: actions/checkout@v7
- uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.base.sha }}
fetch-depth: 0
@@ -32,7 +32,7 @@ jobs:
- name: run benchmarks on base branch
run: pytest --benchmark-autosave dvc/testing/benchmarks/ -k 'test_init or test_help'
- uses: actions/checkout@v7
- uses: actions/checkout@v6
with:
fetch-depth: 0
clean: false
+5 -5
View File
@@ -19,11 +19,11 @@ jobs:
name: Build & Verify package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-python@v7
- uses: actions/setup-python@v6
with:
python-version: "3.14"
@@ -41,7 +41,7 @@ jobs:
- name: Check dist
run: uv tool run twine check --strict dist/*
- uses: actions/upload-artifact@v7
- uses: actions/upload-artifact@v6
with:
name: Packages
path: dist/
@@ -61,7 +61,7 @@ jobs:
id-token: write
steps:
- uses: actions/download-artifact@v8
- uses: actions/download-artifact@v7
with:
name: Packages
path: dist
@@ -86,7 +86,7 @@ jobs:
id-token: write
steps:
- uses: actions/download-artifact@v8
- uses: actions/download-artifact@v7
with:
name: Packages
path: dist
+3 -3
View File
@@ -28,13 +28,13 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v7
uses: actions/checkout@v6
- name: Initialize CodeQL
uses: github/codeql-action/init@v4.38.2
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
queries: security-extended
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4.38.2
uses: github/codeql-action/analyze@v4
+3 -3
View File
@@ -23,18 +23,18 @@ jobs:
plugin: ["dvc-s3"]
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v6
with:
path: dvc
- uses: actions/checkout@v7
- uses: actions/checkout@v6
with:
repository: treeverse/${{ matrix.plugin }}
ref: main
path: ${{ matrix.plugin }}
- name: Set up Python
uses: actions/setup-python@v7
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.pyv }}
+7 -7
View File
@@ -26,11 +26,11 @@ jobs:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v7
uses: actions/setup-python@v6
with:
python-version: '3.14'
- uses: astral-sh/setup-uv@v7
@@ -42,7 +42,7 @@ jobs:
UV_LINK_MODE: ${{ runner.os == 'Windows' && 'symlink' || 'hardlink' }}
- name: Cache mypy
uses: actions/cache@v6
uses: actions/cache@v5
with:
path: .mypy_cache
key: mypy-${{ runner.os }}-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}
@@ -130,11 +130,11 @@ jobs:
pyv: "3.14"
pytestargs: "--splitting-algorithm=least_duration --splits 4 --group 4"
steps:
- uses: actions/checkout@v7
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v7
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.pyv }}
- uses: astral-sh/setup-uv@v7
@@ -155,7 +155,7 @@ jobs:
pytest ${{ matrix.pytestargs }} -n=logical --dist=worksteal --timeout=300 --durations=0
--cov --cov-report=xml --cov-report=term --durations-path=./.github/.test_durations
- name: upload coverage report
uses: codecov/codecov-action@v7
uses: codecov/codecov-action@v5
check:
if: always()
needs: [tests]
@@ -170,7 +170,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Slack Notification
uses: rtCamp/action-slack-notify@v2.4.0
uses: rtCamp/action-slack-notify@v2.3.3
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_COLOR: ${{ job.status }}
+2 -2
View File
@@ -22,13 +22,13 @@ repos:
- id: sort-simple-yaml
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: 'v0.15.20'
rev: 'v0.15.0'
hooks:
- id: ruff-check
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
- repo: https://github.com/codespell-project/codespell
rev: v2.4.2
rev: v2.4.1
hooks:
- id: codespell
additional_dependencies: ["tomli"]
+4 -11
View File
@@ -40,16 +40,9 @@ class CmdGC(CmdBase):
msg += " and all git commits"
else:
if self.args.all_branches and self.args.all_tags:
if self.args.num:
msg += f" and last {self.args.num} commits from all git branches"
msg += " and all git tags"
else:
msg += " and all git branches and tags"
msg += " and all git branches and tags"
elif self.args.all_branches:
if self.args.num:
msg += f" and last {self.args.num} commits from all git branches"
else:
msg += " and all git branches"
msg += " and all git branches"
elif self.args.all_tags:
msg += " and all git tags"
if self.args.commit_date:
@@ -133,8 +126,8 @@ def add_parser(subparsers, parent_parser):
metavar="<num>",
help=(
"Keep data files used in the last `num` commits "
"starting from each selected revision root. "
"Can be used with `--rev` and `--all-branches`. "
"starting from the `--rev` <commit>. "
"Only used if `--rev` is also provided. "
"Defaults to `1`."
),
)
+9 -1
View File
@@ -109,6 +109,8 @@ def _build_tree_structure(
def show_tree(entries, with_color=False, with_size=False, with_hash=False):
import tabulate
rows = _build_tree_structure(
entries,
with_color=with_color,
@@ -117,7 +119,13 @@ def show_tree(entries, with_color=False, with_size=False, with_hash=False):
)
colalign = ("right",) if with_size else None
ui.table(rows, colalign=colalign, preserve_whitespace=True)
_orig = tabulate.PRESERVE_WHITESPACE
tabulate.PRESERVE_WHITESPACE = True
try:
ui.table(rows, colalign=colalign)
finally:
tabulate.PRESERVE_WHITESPACE = _orig
class CmdList(CmdBaseNoRepo):
+3 -3
View File
@@ -37,13 +37,13 @@ KEYCRE = re.compile(
def get_parser():
from pyparsing import CharsNotIn, ParserElement, Suppress, ZeroOrMore
ParserElement.enable_packrat()
ParserElement.enablePackrat()
word = CharsNotIn(f"{PERIOD}{LBRACK}{RBRACK}")
idx = Suppress(LBRACK) + word + Suppress(RBRACK)
attr = Suppress(PERIOD) + word
parser = word + ZeroOrMore(attr ^ idx)
parser.set_parse_action(PERIOD.join)
parser.setParseAction(PERIOD.join)
return parser
@@ -178,7 +178,7 @@ def parse_expr(s: str):
from pyparsing import ParseException
try:
result = get_parser().parse_string(s, parse_all=True)
result = get_parser().parseString(s, parse_all=True)
except ParseException as exc:
format_and_raise_parse_error(exc)
raise AssertionError("unreachable") # noqa: B904
+1 -1
View File
@@ -90,7 +90,7 @@ class BaseStashQueue(ABC):
"""Construct a queue.
Arguments:
repo: DVC repo instance for this queue.
scm: Git SCM instance for this queue.
ref: Git stash ref for this queue.
failed_ref: Failed run Git stash ref for this queue.
"""
+2 -2
View File
@@ -84,8 +84,8 @@ def cleanup_exp(executor: TempDirExecutor, infofile: str) -> None:
"""Cleanup after an experiment.
Arguments:
executor: Executor to clean up.
infofile: Path to the executor info file.
tmp_dir: Temp directory to be removed.
entry_dict: Serialized QueueEntry for this experiment.
"""
executor.cleanup(infofile)
+2 -4
View File
@@ -28,10 +28,8 @@ def _validate_args(**kwargs):
"`--all-experiments`, `--all-commits`, `--date` or `--rev` "
"needs to be set."
)
if kwargs.get("num") and not (kwargs.get("rev") or kwargs.get("all_branches")):
raise InvalidArgumentError(
"`--num` can only be used alongside `--rev` or `--all-branches`"
)
if kwargs.get("num") and not kwargs.get("rev"):
raise InvalidArgumentError("`--num` can only be used alongside `--rev`")
def _used_obj_ids_not_in_remote(
+2 -5
View File
@@ -234,7 +234,7 @@ def iter_revs(
results.extend(scm.list_all_commits())
else:
if all_branches:
results.extend(_get_n_commits(scm, scm.list_branches(), num))
results.extend(scm.list_branches())
if all_tags:
results.extend(scm.list_tags())
@@ -258,10 +258,7 @@ def iter_revs(
results.extend(exp_commits(scm))
rev_resolver = partial(resolve_rev, scm)
grouped = group_by(rev_resolver, results)
for rev, names in grouped.items():
grouped[rev] = list(dict.fromkeys(names))
return grouped
return group_by(rev_resolver, results)
def lfs_prefetch(fs: "FileSystem", paths: list[str]):
+4 -6
View File
@@ -2,7 +2,7 @@ import os
import pathlib
import posixpath
import sys
from typing import Callable, ClassVar, Union
from typing import Callable, ClassVar
from urllib.parse import urlparse
from dvc.utils import relpath
@@ -79,17 +79,15 @@ class PathInfo(pathlib.PurePath, _BasePath):
and self._cparts[:n] == other._cparts # type: ignore[attr-defined]
)
def relative_to(
self, *other: Union[str, "os.PathLike[str]"], **kwargs
) -> "PathInfo":
def relative_to(self, other, *args, **kwargs):
# pathlib relative_to raises exception when one path is not a direct
# descendant of the other when os.path.relpath would return abspath.
# For DVC PathInfo we only need the relpath behavior.
# See: https://bugs.python.org/issue40358
try:
path = super().relative_to(*other, **kwargs)
path = super().relative_to(other, *args, **kwargs)
except ValueError:
path = relpath(self, other[0])
path = relpath(self, other)
return self.__class__(path)
+1 -3
View File
@@ -289,7 +289,7 @@ class Console:
return console.Console(stderr=True)
def table( # noqa: PLR0913
def table(
self,
data: "TableData",
headers: Optional["Headers"] = None,
@@ -301,7 +301,6 @@ class Console:
row_styles: Optional[Sequence["Styles"]] = None,
borders: Union[bool, str] = False,
colalign: Optional[tuple[str, ...]] = None,
preserve_whitespace: bool = False,
) -> None:
from dvc.ui import table as t
@@ -330,7 +329,6 @@ class Console:
pager=pager,
force=force,
colalign=colalign,
preserve_whitespace=preserve_whitespace,
)
def status(self, status: str, **kwargs: Any) -> "Status":
+9 -27
View File
@@ -30,37 +30,19 @@ def plain_table(
pager: bool = False,
force: bool = True,
colalign: Optional[tuple[str, ...]] = None,
preserve_whitespace: bool = False,
) -> None:
import tabulate as tabulate_mod
from funcy import nullcontext
from packaging.version import Version
from tabulate import tabulate
# NOTE: tabulate 0.10.0+ supports preserve_whitespace as a kwarg,
# while 0.9.0 only respects the global PRESERVE_WHITESPACE.
kwargs: dict = {}
_orig = tabulate_mod.PRESERVE_WHITESPACE
if preserve_whitespace:
if Version(tabulate_mod.__version__) >= Version("0.10"):
kwargs["preserve_whitespace"] = True
else:
tabulate_mod.PRESERVE_WHITESPACE = True
try:
text: str = tabulate(
data,
headers if headers is not None else (),
tablefmt="github" if markdown else "plain",
disable_numparse=True,
# None will be shown as "" by default, overriding
missingval="-",
colalign=colalign,
**kwargs,
)
finally:
tabulate_mod.PRESERVE_WHITESPACE = _orig
text: str = tabulate(
data,
headers if headers is not None else (),
tablefmt="github" if markdown else "plain",
disable_numparse=True,
# None will be shown as "" by default, overriding
missingval="-",
colalign=colalign,
)
if markdown:
# NOTE: md table is incomplete without the trailing newline
text += "\n"
-21
View File
@@ -92,27 +92,6 @@ def test_gc_multiple_dvc_repos(tmp_dir, scm, dvc, erepo_dir):
assert len(list(odb.all())) == 2
def test_gc_multiple_dvc_repos_all_branches_num(tmp_dir, scm, dvc, erepo_dir):
tmp_dir.dvc_gen("main", "main", commit="main")
erepo_dir.dvc.cache.local.path = dvc.cache.local.path
with erepo_dir.chdir():
erepo_dir.scm_gen("base", "base", commit="base")
with erepo_dir.branch("feature", new=True):
erepo_dir.dvc_gen("shared", "feature-v1", commit="feature-v1")
erepo_dir.dvc.remove("shared.dvc")
erepo_dir.dvc_gen("shared", "feature-v2", commit="feature-v2")
odb = dvc.cache.local
assert len(list(odb.all())) == 3
dvc.gc(all_branches=True, num=2, repos=[erepo_dir])
assert len(list(odb.all())) == 3
dvc.gc(all_branches=True, repos=[erepo_dir])
assert len(list(odb.all())) == 2
def test_all_commits(tmp_dir, scm, dvc):
tmp_dir.dvc_gen("testfile", "uncommitted")
tmp_dir.dvc_gen("testfile", "committed", commit="committed")
-24
View File
@@ -65,30 +65,6 @@ def test_(dvc, scm, mocker):
with pytest.raises(InvalidArgumentError):
cmd.run()
cli_args = parse_args(["gc", "--all-branches", "--num", "2", "--force"])
cmd = cli_args.func(cli_args)
assert cmd.run() == 0
m.assert_called_with(
workspace=False,
all_tags=False,
all_branches=True,
all_commits=False,
all_experiments=False,
commit_date=None,
cloud=False,
remote=None,
force=True,
jobs=None,
repos=None,
rev=None,
num=2,
not_in_remote=False,
dry=False,
skip_failed=False,
)
cli_args = parse_args(["gc", "--cloud", "--not-in-remote"])
cmd = cli_args.func(cli_args)
with pytest.raises(InvalidArgumentError):
-7
View File
@@ -47,13 +47,6 @@ def test_iter_revs(tmp_dir, scm, mocker):
assert gen == {rev_old: ["tag"]}
gen = iter_revs(scm, all_branches=True)
assert gen == {rev_old: [old], rev_new: ["new"], rev_other: ["other"]}
gen = iter_revs(scm, all_branches=True, num=2)
assert gen == {
rev_old: [old, rev_old],
rev_root: [rev_root],
rev_new: ["new"],
rev_other: ["other"],
}
gen = iter_revs(scm, all_tags=True)
assert gen == {rev_old: ["tag"]}
gen = iter_revs(scm, all_commits=True)