Skip to content
Merged
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
10 changes: 5 additions & 5 deletions .github/workflows/check-test-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python: ["3.9", "3.10", "3.11", "3.12", "3.13"]
python: ["3.10", "3.11", "3.12", "3.13", "3.14"]

steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v7
with:
fetch-depth: 0

Expand All @@ -44,7 +44,7 @@ jobs:
- run: pytest

- name: "Upload coverage to Codecov"
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v7
with:
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}
Expand All @@ -59,12 +59,12 @@ jobs:
id-token: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: actions/setup-python@v6
with:
python-version: '3.13'
python-version: '3.14'

- run: pip install build twine
- run: python -m build
Expand Down
1 change: 1 addition & 0 deletions gto/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ def format_hexsha(hexsha):
d["version"],
]
+ [d["stage"][name] for name in stages],
strict=True,
),
)
for name, d in sorted(models_state.items())
Expand Down
18 changes: 10 additions & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,17 @@ keywords = ["git", "repo", "repository", "artifact", "registry", "developer-tool
classifiers = [
"Development Status :: 2 - Pre-Alpha",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@skshetry are we good to drop Python 3.9 now? should not be impacting DVC I think, right?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified against current DVC mainno impact:

  • DVC only uses gto's pure library surface: dvc/repo/artifacts.py imports gto.constants (assert_name_is_valid, fullname_re), gto.exceptions, gto.tag (find, parse_tag), gto.base (sort_versions). None of those modules import click/typer (that's confined to gto/cli.py/gto/utils.py), and none changed in this PR.
  • DVC still supports and tests py3.9 (requires-python = ">=3.9", 3.9 in its matrix) with gto>=1.6.0,<2. Once gto releases with >=3.10, pip on py3.9 simply resolves the last 3.9-compatible gto (1.9.x) — installs keep working; 3.9 users just stop receiving gto updates (3.9 has been EOL since Oct 2025).
  • No pin conflicts: DVC envs already carry click via celery (which requires click>=8.1,<9 — same range as the new pin), and nothing in DVC's tree uses typer.
  • ⚠️ One requirement: the next gto release must be 1.10.0, not 2.0.0 — DVC caps at gto<2, so a major bump would be invisible to DVC until they raise the cap.

Side benefit for DVC docs/users: this PR fixes the gto CLI being broken on fresh 3.10+ installs (unpinned typer resolves to 0.26.x → gto --help crashes).

@skshetry skshetry Jul 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, 3.9 is already EOL'd. I don't plan to drop support in dvc though. But 3.9 users should be able to install older version of GTO.

"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
]
requires-python = ">=3.9"
requires-python = ">=3.10"
dynamic = ["version"]
dependencies = [
# gto imports click directly, so declare it explicitly
"click>=8,<9",
"entrypoints",
"funcy",
"pydantic>=2",
Expand All @@ -30,7 +32,10 @@ dependencies = [
"scmrepo>=3,<4",
"semver>=2.13.0",
"tabulate>=0.8.10",
"typer>=0.4.1",
# typer>=0.26 vendors click and is incompatible with gto's click-based
# CLI machinery (subclassing click.Command, @click.pass_context, etc.):
# the CLI crashes on startup. Migration tracked separately.
"typer>=0.4.1,<0.26",
]

[project.urls]
Expand All @@ -48,11 +53,8 @@ tests = [
]
dev = [
"gto[tests]",
"mypy==1.17.1; python_version > '3.9'",
# mypy>=1.11.0 crashes when used with pydantic-settings on Python 3.9,
# see: https://github.com/python/mypy/issues/17535
"mypy<1.11.0; python_version <= '3.9'",
"pylint==3.3.8",
"mypy==2.2.0",
"pylint==4.0.6",
"types-PyYAML",
"types-filelock",
"types-freezegun",
Expand Down
9 changes: 1 addition & 8 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# pylint: disable=redefined-outer-name
import inspect
import os
import sys
from time import sleep
Expand All @@ -19,13 +18,7 @@

class Runner:
def __init__(self):
# Older versions of CliRunner need this
# Can we removed when we drop Py 3.9 support
init_sig = inspect.signature(CliRunner.__init__)
if "mix_stderr" in init_sig.parameters:
self._runner = CliRunner(mix_stderr=False) # pylint: disable=unexpected-keyword-arg
else:
self._runner = CliRunner()
self._runner = CliRunner()

def invoke(self, *args, **kwargs) -> Result:
return self._runner.invoke(app, *args, **kwargs)
Expand Down
1 change: 1 addition & 0 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ def test_check_ref_catch_the_bug(scm: Git):
for assignment, tag in zip(
[assignment1, assignment2, assignment3],
[f"{NAME}#staging#1", f"{NAME}#prod#2", f"{NAME}#dev#3"],
strict=True,
):
events = gto.api.check_ref(scm, tag)
assert len(events) == 1, events
Expand Down
2 changes: 2 additions & 0 deletions tests/test_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,13 +431,15 @@ def test_registry_state_tag_tag(tmp_dir: TmpDir):
for appeared, expected in zip(
iter_over(appeared_state["artifacts"][artifact]["versions"]),
iter_over(expected_state["artifacts"][artifact]["versions"]),
strict=True,
):
check_obj(appeared, expected, exclude["versions"])

for key in ["enrichments", "registrations", "deregistrations"]:
for a, e in zip(
iter_over(appeared[key]),
iter_over(expected[key]),
strict=True,
):
check_obj(a, e, exclude[key])

Expand Down
Loading