modelbump 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
modelbump/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ """ModelBump: Dependabot for LLM models."""
2
+
3
+ from importlib.metadata import version
4
+
5
+ __version__ = version("modelbump")
modelbump/cli.py ADDED
@@ -0,0 +1,154 @@
1
+ """Command-line interface for ModelBump."""
2
+
3
+ from datetime import date, datetime
4
+ from pathlib import Path
5
+ from typing import Annotated
6
+
7
+ import typer
8
+
9
+ from modelbump import __version__
10
+ from modelbump.registry import Status, load_registry
11
+ from modelbump.scanner import DEFAULT_SOON_DAYS, scan_path
12
+ from modelbump.scanner.report import (
13
+ RENDERERS,
14
+ OutputFormat,
15
+ build_report,
16
+ failure_line,
17
+ summary_line,
18
+ )
19
+
20
+ app = typer.Typer(
21
+ name="modelbump",
22
+ help="Dependabot for LLM models.",
23
+ no_args_is_help=True,
24
+ )
25
+
26
+
27
+ def _version_callback(value: bool) -> None:
28
+ if value:
29
+ typer.echo(f"modelbump {__version__}")
30
+ raise typer.Exit()
31
+
32
+
33
+ @app.callback()
34
+ def main(
35
+ version: Annotated[
36
+ bool,
37
+ typer.Option(
38
+ "--version",
39
+ "-V",
40
+ help="Show the version and exit.",
41
+ callback=_version_callback,
42
+ is_eager=True,
43
+ ),
44
+ ] = False,
45
+ ) -> None:
46
+ """Dependabot for LLM models."""
47
+
48
+
49
+ @app.command()
50
+ def scan(
51
+ path: Annotated[
52
+ Path,
53
+ typer.Argument(help="Folder or file to scan.", exists=True, resolve_path=True),
54
+ ] = Path("."),
55
+ soon_days: Annotated[
56
+ int,
57
+ typer.Option(
58
+ min=0, help="Mark a model RETIRING_SOON when it shuts down within this many days."
59
+ ),
60
+ ] = DEFAULT_SOON_DAYS,
61
+ fail_within: Annotated[
62
+ int | None,
63
+ typer.Option(
64
+ min=0,
65
+ help="Exit with code 1 if a model is retired or shuts down within this many days.",
66
+ ),
67
+ ] = None,
68
+ today: Annotated[
69
+ datetime | None,
70
+ typer.Option(
71
+ formats=["%Y-%m-%d"],
72
+ help="Check as if today were this day (YYYY-MM-DD), to replay the past.",
73
+ ),
74
+ ] = None,
75
+ output_format: Annotated[
76
+ OutputFormat,
77
+ typer.Option("--format", help="Report format: text, json or sarif."),
78
+ ] = OutputFormat.TEXT,
79
+ exclude: Annotated[
80
+ list[str] | None,
81
+ typer.Option(
82
+ help="Skip paths matching this pattern, e.g. 'tests' or '*.ipynb'. Repeat for more.",
83
+ ),
84
+ ] = None,
85
+ skip_comments: Annotated[
86
+ bool,
87
+ typer.Option(
88
+ help="Leave out IDs that only describe a model: comments, docstrings, "
89
+ "sentences and price tables.",
90
+ ),
91
+ ] = False,
92
+ skip_tests: Annotated[
93
+ bool,
94
+ typer.Option(help="Leave out test files and test folders."),
95
+ ] = False,
96
+ output: Annotated[
97
+ Path | None,
98
+ typer.Option(help="Write the report to this file instead of the screen.", dir_okay=False),
99
+ ] = None,
100
+ ) -> None:
101
+ """Find the LLM model IDs in a repository's code and config, and how urgent each is."""
102
+ registry = load_registry()
103
+ day = today.date() if today is not None else date.today()
104
+ result = scan_path(path, registry, exclude or (), skip_comments, skip_tests)
105
+ report = build_report(result, registry, day, soon_days, fail_within, _root_uri(path))
106
+ rendered = RENDERERS[output_format](report)
107
+ if output is None:
108
+ typer.echo(rendered, nl=False)
109
+ else:
110
+ output.write_text(rendered, encoding="utf-8")
111
+ typer.echo(f"Wrote {output_format.value} report to {output}.")
112
+ typer.echo(summary_line(report))
113
+ failure = failure_line(report)
114
+ if failure is not None:
115
+ if output is not None or output_format is not OutputFormat.TEXT:
116
+ # Keep the screen output a valid JSON or SARIF document.
117
+ typer.echo(failure, err=True)
118
+ raise typer.Exit(code=1)
119
+
120
+
121
+ def _root_uri(path: Path) -> str:
122
+ """The scan root relative to the working directory, for SARIF paths."""
123
+ base = path.parent if path.is_file() else path
124
+ try:
125
+ relative = base.relative_to(Path.cwd()).as_posix()
126
+ except ValueError:
127
+ return ""
128
+ return "" if relative == "." else relative + "/"
129
+
130
+
131
+ @app.command()
132
+ def check(
133
+ model_id: Annotated[str, typer.Argument(help="Model ID, e.g. claude-3-haiku-20240307.")],
134
+ ) -> None:
135
+ """Look up one model ID in the retirement registry."""
136
+ found = load_registry().get(model_id)
137
+ if found is None:
138
+ typer.echo(f"{model_id}: no retirement announced (not in the registry).")
139
+ return
140
+ provider, model = found
141
+ status = model.status_on(date.today())
142
+ if status is Status.RETIRED:
143
+ line = f"RETIRED since {model.shutdown}"
144
+ if model.shutdown_is_earliest:
145
+ line += " (the earliest possible date the provider gave)"
146
+ elif model.shutdown_is_earliest:
147
+ line = f"{status.value.upper()}, shuts down no earlier than {model.shutdown}"
148
+ else:
149
+ line = f"{status.value.upper()}, shuts down on {model.shutdown}"
150
+ typer.echo(f"{model_id} ({provider.value}): {line}.")
151
+ if model.superseded:
152
+ typer.echo(f"Rescheduled: {len(model.superseded)} earlier plan(s) were replaced.")
153
+ if model.replacement:
154
+ typer.echo(f"Suggested replacement: {model.replacement}")
modelbump/py.typed ADDED
File without changes
@@ -0,0 +1,27 @@
1
+ """Retirement registry: which LLM models are being shut down, and when."""
2
+
3
+ from modelbump.registry.loader import (
4
+ DuplicateModelError,
5
+ Registry,
6
+ load_provider_file,
7
+ load_registry,
8
+ )
9
+ from modelbump.registry.models import (
10
+ EarlierPlan,
11
+ Provider,
12
+ ProviderFile,
13
+ RetiredModel,
14
+ Status,
15
+ )
16
+
17
+ __all__ = [
18
+ "DuplicateModelError",
19
+ "EarlierPlan",
20
+ "Provider",
21
+ "ProviderFile",
22
+ "Registry",
23
+ "RetiredModel",
24
+ "Status",
25
+ "load_provider_file",
26
+ "load_registry",
27
+ ]
@@ -0,0 +1,88 @@
1
+ # Copied from the "Deprecation history" table of the source page.
2
+ # `announced` is the date of each section on that page; `shutdown` is its
3
+ # "Retirement date". `replacement` is what the page recommends TODAY, which is
4
+ # not always what was recommended at the time (see ADR 0006).
5
+ provider: anthropic
6
+ source_url: https://platform.claude.com/docs/en/about-claude/model-deprecations
7
+ retrieved: 2026-10-08
8
+ models:
9
+ - id: claude-sonnet-4-5-20250929
10
+ announced: 2026-09-30
11
+ shutdown: 2026-11-30
12
+ replacement: claude-sonnet-5-5
13
+ - id: claude-opus-4-1-20250805
14
+ announced: 2026-06-05
15
+ shutdown: 2026-08-05
16
+ replacement: claude-opus-4-8
17
+ - id: claude-sonnet-4-20250514
18
+ announced: 2026-04-14
19
+ shutdown: 2026-06-15
20
+ replacement: claude-sonnet-4-6
21
+ - id: claude-opus-4-20250514
22
+ announced: 2026-04-14
23
+ shutdown: 2026-06-15
24
+ replacement: claude-opus-4-8
25
+ - id: claude-3-haiku-20240307
26
+ announced: 2026-02-19
27
+ shutdown: 2026-04-20
28
+ replacement: claude-haiku-4-5-20251001
29
+ - id: claude-3-5-haiku-20241022
30
+ announced: 2025-12-19
31
+ shutdown: 2026-02-19
32
+ replacement: claude-haiku-4-5-20251001
33
+ - id: claude-3-7-sonnet-20250219
34
+ announced: 2025-10-28
35
+ shutdown: 2026-02-19
36
+ replacement: claude-sonnet-4-6
37
+ - id: claude-3-5-sonnet-20240620
38
+ announced: 2025-08-13
39
+ shutdown: 2025-10-28
40
+ replacement: claude-sonnet-4-6
41
+ - id: claude-3-5-sonnet-20241022
42
+ announced: 2025-08-13
43
+ shutdown: 2025-10-28
44
+ replacement: claude-sonnet-4-6
45
+ - id: claude-3-opus-20240229
46
+ announced: 2025-06-30
47
+ shutdown: 2026-01-05
48
+ replacement: claude-opus-4-8
49
+ - id: claude-2.0
50
+ announced: 2025-01-21
51
+ shutdown: 2025-07-21
52
+ replacement: claude-opus-4-8
53
+ - id: claude-2.1
54
+ announced: 2025-01-21
55
+ shutdown: 2025-07-21
56
+ replacement: claude-opus-4-8
57
+ - id: claude-3-sonnet-20240229
58
+ announced: 2025-01-21
59
+ shutdown: 2025-07-21
60
+ replacement: claude-sonnet-4-6
61
+ - id: claude-1.0
62
+ announced: 2024-09-04
63
+ shutdown: 2024-11-06
64
+ replacement: claude-haiku-4-5-20251001
65
+ - id: claude-1.1
66
+ announced: 2024-09-04
67
+ shutdown: 2024-11-06
68
+ replacement: claude-haiku-4-5-20251001
69
+ - id: claude-1.2
70
+ announced: 2024-09-04
71
+ shutdown: 2024-11-06
72
+ replacement: claude-haiku-4-5-20251001
73
+ - id: claude-1.3
74
+ announced: 2024-09-04
75
+ shutdown: 2024-11-06
76
+ replacement: claude-haiku-4-5-20251001
77
+ - id: claude-instant-1.0
78
+ announced: 2024-09-04
79
+ shutdown: 2024-11-06
80
+ replacement: claude-haiku-4-5-20251001
81
+ - id: claude-instant-1.1
82
+ announced: 2024-09-04
83
+ shutdown: 2024-11-06
84
+ replacement: claude-haiku-4-5-20251001
85
+ - id: claude-instant-1.2
86
+ announced: 2024-09-04
87
+ shutdown: 2024-11-06
88
+ replacement: claude-haiku-4-5-20251001
@@ -0,0 +1,102 @@
1
+ # Copied from the source page. Scope: Gemini text models and embedding models
2
+ # that have a shutdown date (see docs/architecture/registry.md).
3
+ # The page gives no announcement dates, and says: "The shutdown dates listed in
4
+ # the table indicate the earliest possible dates on which a model might be
5
+ # retired." So every entry has `shutdown_is_earliest: true`.
6
+ # `replacement` is what the page recommends TODAY (see ADR 0006).
7
+ provider: google
8
+ source_url: https://ai.google.dev/gemini-api/docs/deprecations
9
+ retrieved: 2026-10-08
10
+ models:
11
+ - id: gemini-3.1-flash-lite
12
+ shutdown: 2027-05-07
13
+ shutdown_is_earliest: true
14
+ replacement: gemini-3.5-flash-lite
15
+ - id: gemini-3-pro-preview
16
+ shutdown: 2026-03-09
17
+ shutdown_is_earliest: true
18
+ replacement: gemini-3.1-pro-preview
19
+ - id: gemini-3.1-flash-lite-preview
20
+ shutdown: 2026-05-25
21
+ shutdown_is_earliest: true
22
+ replacement: gemini-3.1-flash-lite
23
+ - id: gemini-2.5-computer-use-preview-10-2025
24
+ shutdown: 2026-07-28
25
+ shutdown_is_earliest: true
26
+ replacement: gemini-3.8-flash
27
+ - id: gemini-2.5-pro-preview-03-25
28
+ shutdown: 2025-12-02
29
+ shutdown_is_earliest: true
30
+ replacement: gemini-3.1-pro-preview
31
+ - id: gemini-2.5-pro-preview-05-06
32
+ shutdown: 2025-12-02
33
+ shutdown_is_earliest: true
34
+ replacement: gemini-3.1-pro-preview
35
+ - id: gemini-2.5-pro-preview-06-05
36
+ shutdown: 2025-12-02
37
+ shutdown_is_earliest: true
38
+ replacement: gemini-3.1-pro-preview
39
+ - id: gemini-2.5-flash-lite-preview-09-2025
40
+ shutdown: 2026-03-31
41
+ shutdown_is_earliest: true
42
+ replacement: gemini-3.1-flash-lite
43
+ - id: gemini-2.5-flash-preview-05-20
44
+ shutdown: 2025-11-18
45
+ shutdown_is_earliest: true
46
+ replacement: gemini-3.6-flash
47
+ - id: gemini-2.5-flash-preview-09-25
48
+ shutdown: 2026-02-17
49
+ shutdown_is_earliest: true
50
+ replacement: gemini-3.6-flash
51
+ - id: gemini-2.0-flash
52
+ shutdown: 2026-06-01
53
+ shutdown_is_earliest: true
54
+ replacement: gemini-3.6-flash
55
+ - id: gemini-2.0-flash-001
56
+ shutdown: 2026-06-01
57
+ shutdown_is_earliest: true
58
+ replacement: gemini-3.6-flash
59
+ - id: gemini-2.0-flash-lite
60
+ shutdown: 2026-06-01
61
+ shutdown_is_earliest: true
62
+ replacement: gemini-3.1-flash-lite
63
+ - id: gemini-2.0-flash-lite-001
64
+ shutdown: 2026-06-01
65
+ shutdown_is_earliest: true
66
+ replacement: gemini-3.1-flash-lite
67
+ - id: gemini-2.0-flash-lite-preview
68
+ shutdown: 2025-12-09
69
+ shutdown_is_earliest: true
70
+ replacement: gemini-2.5-flash-lite
71
+ - id: gemini-2.0-flash-lite-preview-02-05
72
+ shutdown: 2025-12-09
73
+ shutdown_is_earliest: true
74
+ replacement: gemini-2.5-flash-lite
75
+ - id: gemini-embedding-001
76
+ shutdown: 2028-05-14
77
+ shutdown_is_earliest: true
78
+ replacement: gemini-embedding-2
79
+ - id: text-embedding-004
80
+ shutdown: 2026-01-14
81
+ shutdown_is_earliest: true
82
+ replacement: gemini-embedding-2
83
+ - id: embedding-2-preview
84
+ shutdown: 2026-08-10
85
+ shutdown_is_earliest: true
86
+ replacement: gemini-embedding-2
87
+ - id: embedding-001
88
+ shutdown: 2025-10-30
89
+ shutdown_is_earliest: true
90
+ replacement: gemini-embedding-2
91
+ - id: embedding-gecko-001
92
+ shutdown: 2025-10-30
93
+ shutdown_is_earliest: true
94
+ replacement: gemini-embedding-2
95
+ - id: gemini-embedding-exp
96
+ shutdown: 2025-10-30
97
+ shutdown_is_earliest: true
98
+ replacement: gemini-embedding-2
99
+ - id: gemini-embedding-exp-03-07
100
+ shutdown: 2025-10-30
101
+ shutdown_is_earliest: true
102
+ replacement: gemini-embedding-2