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.
@@ -0,0 +1,384 @@
1
+ # Copied from the source page. Scope: models called through text-generation or
2
+ # embedding APIs; audio, realtime, image, video, moderation and fine-tuning
3
+ # entries are left out (see docs/architecture/registry.md).
4
+ # `announced` is the date of the page section; `shutdown` is its shutdown date.
5
+ # `replacement` is what the page recommends TODAY (see ADR 0006).
6
+ # When a model appears in more than one section, the newest section is the
7
+ # current plan and older ones go under `superseded` (see ADR 0007).
8
+ provider: openai
9
+ source_url: https://developers.openai.com/api/docs/deprecations
10
+ retrieved: 2026-10-08
11
+ models:
12
+ - id: gpt-5.3-codex
13
+ announced: 2026-10-01
14
+ shutdown: 2027-04-01
15
+ replacement: gpt-6-sol
16
+ - id: gpt-5.4-nano
17
+ announced: 2026-10-01
18
+ shutdown: 2027-04-01
19
+ replacement: gpt-6-luna
20
+ - id: gpt-5.1
21
+ announced: 2026-10-01
22
+ shutdown: 2027-04-01
23
+ replacement: gpt-6-sol
24
+ - id: gpt-5.4-cyber
25
+ announced: 2026-09-11
26
+ shutdown: 2026-10-01
27
+ notes: "Page recommends the most capable cyber model available to you."
28
+ - id: gpt-5-2025-08-07
29
+ announced: 2026-06-11
30
+ shutdown: 2026-12-11
31
+ replacement: gpt-5.6-sol
32
+ - id: gpt-5-mini-2025-08-07
33
+ announced: 2026-06-11
34
+ shutdown: 2026-12-11
35
+ replacement: gpt-5.6-terra
36
+ - id: gpt-5-nano-2025-08-07
37
+ announced: 2026-06-11
38
+ shutdown: 2026-12-11
39
+ replacement: gpt-5.6-luna
40
+ - id: gpt-5-pro-2025-10-06
41
+ announced: 2026-06-11
42
+ shutdown: 2026-12-11
43
+ replacement: gpt-5.6-sol
44
+ notes: "Replacement uses reasoning.mode pro."
45
+ - id: o3-2025-04-16
46
+ announced: 2026-06-11
47
+ shutdown: 2026-12-11
48
+ replacement: gpt-5.6-sol
49
+ - id: o3-pro-2025-06-10
50
+ announced: 2026-06-11
51
+ shutdown: 2026-12-11
52
+ replacement: gpt-5.6-sol
53
+ notes: "Replacement uses reasoning.mode pro."
54
+ - id: gpt-5.2-chat-latest
55
+ announced: 2026-05-08
56
+ shutdown: 2026-08-10
57
+ replacement: gpt-5.6-sol
58
+ - id: gpt-5.3-chat-latest
59
+ announced: 2026-05-08
60
+ shutdown: 2026-08-10
61
+ replacement: gpt-5.6-sol
62
+ - id: gpt-3.5-turbo-0125
63
+ aliases: [gpt-3.5-turbo]
64
+ announced: 2026-04-22
65
+ shutdown: 2026-10-23
66
+ replacement: gpt-5.6-terra
67
+ - id: gpt-4-0613
68
+ aliases: [gpt-4, gpt-4-0613-completions, gpt-4-completions]
69
+ announced: 2026-04-22
70
+ shutdown: 2026-10-23
71
+ replacement: gpt-5.6-sol
72
+ - id: gpt-4-1106-preview
73
+ announced: 2026-04-22
74
+ shutdown: 2026-10-23
75
+ replacement: gpt-5.6-sol
76
+ notes: "Rescheduled: first set to shut down on 2026-03-26."
77
+ superseded:
78
+ - announced: 2025-09-26
79
+ shutdown: 2026-03-26
80
+ - id: gpt-4-turbo-2024-04-09
81
+ aliases: [gpt-4-turbo, gpt-4-turbo-completions]
82
+ announced: 2026-04-22
83
+ shutdown: 2026-10-23
84
+ replacement: gpt-5.6-sol
85
+ - id: gpt-4.1-nano-2025-04-14
86
+ aliases: [gpt-4.1-nano]
87
+ announced: 2026-04-22
88
+ shutdown: 2026-10-23
89
+ replacement: gpt-5.6-luna
90
+ - id: gpt-4o-2024-05-13
91
+ announced: 2026-04-22
92
+ shutdown: 2026-10-23
93
+ replacement: gpt-5.6-sol
94
+ - id: o1-2024-12-17
95
+ aliases: [o1]
96
+ announced: 2026-04-22
97
+ shutdown: 2026-10-23
98
+ replacement: gpt-5.6-sol
99
+ - id: o1-pro-2025-03-19
100
+ aliases: [o1-pro]
101
+ announced: 2026-04-22
102
+ shutdown: 2026-10-23
103
+ replacement: gpt-5.6-sol
104
+ notes: "Replacement uses reasoning.mode pro."
105
+ - id: o3-mini-2025-01-31
106
+ aliases: [o3-mini]
107
+ announced: 2026-04-22
108
+ shutdown: 2026-10-23
109
+ replacement: gpt-5.6-sol
110
+ - id: o4-mini-2025-04-16
111
+ aliases: [o4-mini]
112
+ announced: 2026-04-22
113
+ shutdown: 2026-10-23
114
+ replacement: gpt-5.6-terra
115
+ - id: computer-use-preview-2025-03-11
116
+ aliases: [computer-use-preview]
117
+ announced: 2026-04-22
118
+ shutdown: 2026-07-23
119
+ replacement: gpt-5.6-terra
120
+ - id: gpt-4o-mini-search-preview-2025-03-11
121
+ announced: 2026-04-22
122
+ shutdown: 2026-07-23
123
+ replacement: gpt-5.6-terra
124
+ - id: gpt-4o-search-preview-2025-03-11
125
+ announced: 2026-04-22
126
+ shutdown: 2026-07-23
127
+ replacement: gpt-5.6-terra
128
+ - id: gpt-5-chat-latest
129
+ announced: 2026-04-22
130
+ shutdown: 2026-07-23
131
+ replacement: gpt-5.6-sol
132
+ - id: gpt-5-codex
133
+ announced: 2026-04-22
134
+ shutdown: 2026-07-23
135
+ replacement: gpt-5.6-sol
136
+ - id: gpt-5.1-chat-latest
137
+ announced: 2026-04-22
138
+ shutdown: 2026-07-23
139
+ replacement: gpt-5.6-sol
140
+ - id: gpt-5.1-codex
141
+ announced: 2026-04-22
142
+ shutdown: 2026-07-23
143
+ replacement: gpt-5.6-sol
144
+ - id: gpt-5.1-codex-max
145
+ announced: 2026-04-22
146
+ shutdown: 2026-07-23
147
+ replacement: gpt-5.6-sol
148
+ - id: gpt-5.1-codex-mini
149
+ announced: 2026-04-22
150
+ shutdown: 2026-07-23
151
+ replacement: gpt-5.6-terra
152
+ - id: o3-deep-research-2025-06-26
153
+ aliases: [o3-deep-research]
154
+ announced: 2026-04-22
155
+ shutdown: 2026-07-23
156
+ replacement: gpt-5.6-sol
157
+ - id: o4-mini-deep-research-2025-06-26
158
+ aliases: [o4-mini-deep-research]
159
+ announced: 2026-04-22
160
+ shutdown: 2026-07-23
161
+ replacement: gpt-5.6-sol
162
+ - id: gpt-5.2-codex
163
+ announced: 2026-04-22
164
+ shutdown: 2026-07-23
165
+ replacement: gpt-5.6-sol
166
+ - id: chatgpt-4o-latest
167
+ announced: 2025-11-18
168
+ shutdown: 2026-02-17
169
+ replacement: gpt-5.1-chat-latest
170
+ - id: codex-mini-latest
171
+ announced: 2025-11-17
172
+ shutdown: 2026-02-12
173
+ replacement: gpt-5-codex-mini
174
+ - id: gpt-3.5-turbo-instruct
175
+ announced: 2025-09-26
176
+ shutdown: 2026-09-28
177
+ replacement: gpt-5.6-terra
178
+ - id: babbage-002
179
+ announced: 2025-09-26
180
+ shutdown: 2026-09-28
181
+ replacement: gpt-5.6-terra
182
+ - id: davinci-002
183
+ announced: 2025-09-26
184
+ shutdown: 2026-09-28
185
+ replacement: gpt-5.6-terra
186
+ - id: gpt-3.5-turbo-1106
187
+ announced: 2025-09-26
188
+ shutdown: 2026-09-28
189
+ replacement: gpt-5.6-terra
190
+ - id: gpt-4-0314
191
+ announced: 2025-09-26
192
+ shutdown: 2026-03-26
193
+ replacement: gpt-5
194
+ notes: "Rescheduled: first announced on 2023-06-13 with shutdown at earliest 2024-06-13. Page recommends gpt-5 or gpt-4.1."
195
+ superseded:
196
+ - announced: 2023-06-13
197
+ shutdown: 2024-06-13
198
+ shutdown_is_earliest: true
199
+ - id: gpt-4-0125-preview
200
+ aliases: [gpt-4-turbo-preview, gpt-4-turbo-preview-completions]
201
+ announced: 2025-09-26
202
+ shutdown: 2026-03-26
203
+ replacement: gpt-5
204
+ notes: "Page recommends gpt-5 or gpt-4.1."
205
+ - id: o1-preview
206
+ announced: 2025-04-28
207
+ shutdown: 2025-07-28
208
+ replacement: o3
209
+ - id: o1-mini
210
+ announced: 2025-04-28
211
+ shutdown: 2025-10-27
212
+ replacement: o4-mini
213
+ - id: gpt-4.5-preview
214
+ announced: 2025-04-14
215
+ shutdown: 2025-07-14
216
+ replacement: gpt-4.1
217
+ - id: gpt-4-32k
218
+ announced: 2024-06-06
219
+ shutdown: 2025-06-06
220
+ replacement: gpt-4o
221
+ - id: gpt-4-32k-0613
222
+ announced: 2024-06-06
223
+ shutdown: 2025-06-06
224
+ replacement: gpt-4o
225
+ - id: gpt-4-32k-0314
226
+ announced: 2024-06-06
227
+ shutdown: 2025-06-06
228
+ replacement: gpt-4o
229
+ notes: "Also listed in the 2023-06-13 section with the same shutdown date."
230
+ superseded:
231
+ - announced: 2023-06-13
232
+ shutdown: 2025-06-06
233
+ - id: gpt-4-vision-preview
234
+ announced: 2024-06-06
235
+ shutdown: 2024-12-06
236
+ replacement: gpt-4o
237
+ - id: gpt-4-1106-vision-preview
238
+ announced: 2024-06-06
239
+ shutdown: 2024-12-06
240
+ replacement: gpt-4o
241
+ - id: gpt-3.5-turbo-0613
242
+ announced: 2023-11-06
243
+ shutdown: 2024-09-13
244
+ replacement: gpt-3.5-turbo
245
+ - id: gpt-3.5-turbo-16k-0613
246
+ announced: 2023-11-06
247
+ shutdown: 2024-09-13
248
+ replacement: gpt-3.5-turbo
249
+ - id: text-ada-001
250
+ announced: 2023-07-06
251
+ shutdown: 2024-01-04
252
+ replacement: gpt-3.5-turbo-instruct
253
+ - id: text-babbage-001
254
+ announced: 2023-07-06
255
+ shutdown: 2024-01-04
256
+ replacement: gpt-3.5-turbo-instruct
257
+ - id: text-curie-001
258
+ announced: 2023-07-06
259
+ shutdown: 2024-01-04
260
+ replacement: gpt-3.5-turbo-instruct
261
+ - id: text-davinci-001
262
+ announced: 2023-07-06
263
+ shutdown: 2024-01-04
264
+ replacement: gpt-3.5-turbo-instruct
265
+ - id: text-davinci-002
266
+ announced: 2023-07-06
267
+ shutdown: 2024-01-04
268
+ replacement: gpt-3.5-turbo-instruct
269
+ - id: text-davinci-003
270
+ announced: 2023-07-06
271
+ shutdown: 2024-01-04
272
+ replacement: gpt-3.5-turbo-instruct
273
+ - id: ada
274
+ announced: 2023-07-06
275
+ shutdown: 2024-01-04
276
+ replacement: babbage-002
277
+ - id: babbage
278
+ announced: 2023-07-06
279
+ shutdown: 2024-01-04
280
+ replacement: babbage-002
281
+ - id: curie
282
+ announced: 2023-07-06
283
+ shutdown: 2024-01-04
284
+ replacement: davinci-002
285
+ - id: davinci
286
+ announced: 2023-07-06
287
+ shutdown: 2024-01-04
288
+ replacement: davinci-002
289
+ - id: code-davinci-002
290
+ announced: 2023-07-06
291
+ shutdown: 2024-01-04
292
+ replacement: gpt-3.5-turbo-instruct
293
+ notes: "Rescheduled: the 2023-03-20 section lists a 2023-03-23 shutdown."
294
+ superseded:
295
+ - announced: 2023-03-20
296
+ shutdown: 2023-03-23
297
+ - id: text-davinci-edit-001
298
+ announced: 2023-07-06
299
+ shutdown: 2024-01-04
300
+ replacement: gpt-4o
301
+ - id: code-davinci-edit-001
302
+ announced: 2023-07-06
303
+ shutdown: 2024-01-04
304
+ replacement: gpt-4o
305
+ - id: text-similarity-ada-001
306
+ announced: 2023-07-06
307
+ shutdown: 2024-01-04
308
+ replacement: text-embedding-3-small
309
+ - id: text-search-ada-doc-001
310
+ announced: 2023-07-06
311
+ shutdown: 2024-01-04
312
+ replacement: text-embedding-3-small
313
+ - id: text-search-ada-query-001
314
+ announced: 2023-07-06
315
+ shutdown: 2024-01-04
316
+ replacement: text-embedding-3-small
317
+ - id: code-search-ada-code-001
318
+ announced: 2023-07-06
319
+ shutdown: 2024-01-04
320
+ replacement: text-embedding-3-small
321
+ - id: code-search-ada-text-001
322
+ announced: 2023-07-06
323
+ shutdown: 2024-01-04
324
+ replacement: text-embedding-3-small
325
+ - id: text-similarity-babbage-001
326
+ announced: 2023-07-06
327
+ shutdown: 2024-01-04
328
+ replacement: text-embedding-3-small
329
+ - id: text-search-babbage-doc-001
330
+ announced: 2023-07-06
331
+ shutdown: 2024-01-04
332
+ replacement: text-embedding-3-small
333
+ - id: text-search-babbage-query-001
334
+ announced: 2023-07-06
335
+ shutdown: 2024-01-04
336
+ replacement: text-embedding-3-small
337
+ - id: code-search-babbage-code-001
338
+ announced: 2023-07-06
339
+ shutdown: 2024-01-04
340
+ replacement: text-embedding-3-small
341
+ - id: code-search-babbage-text-001
342
+ announced: 2023-07-06
343
+ shutdown: 2024-01-04
344
+ replacement: text-embedding-3-small
345
+ - id: text-similarity-curie-001
346
+ announced: 2023-07-06
347
+ shutdown: 2024-01-04
348
+ replacement: text-embedding-3-small
349
+ - id: text-search-curie-doc-001
350
+ announced: 2023-07-06
351
+ shutdown: 2024-01-04
352
+ replacement: text-embedding-3-small
353
+ - id: text-search-curie-query-001
354
+ announced: 2023-07-06
355
+ shutdown: 2024-01-04
356
+ replacement: text-embedding-3-small
357
+ - id: text-similarity-davinci-001
358
+ announced: 2023-07-06
359
+ shutdown: 2024-01-04
360
+ replacement: text-embedding-3-small
361
+ - id: text-search-davinci-doc-001
362
+ announced: 2023-07-06
363
+ shutdown: 2024-01-04
364
+ replacement: text-embedding-3-small
365
+ - id: text-search-davinci-query-001
366
+ announced: 2023-07-06
367
+ shutdown: 2024-01-04
368
+ replacement: text-embedding-3-small
369
+ - id: gpt-3.5-turbo-0301
370
+ announced: 2023-06-13
371
+ shutdown: 2024-09-13
372
+ replacement: gpt-3.5-turbo
373
+ - id: code-davinci-001
374
+ announced: 2023-03-20
375
+ shutdown: 2023-03-23
376
+ replacement: gpt-4o
377
+ - id: code-cushman-002
378
+ announced: 2023-03-20
379
+ shutdown: 2023-03-23
380
+ replacement: gpt-4o
381
+ - id: code-cushman-001
382
+ announced: 2023-03-20
383
+ shutdown: 2023-03-23
384
+ replacement: gpt-4o
@@ -0,0 +1,59 @@
1
+ """Load the retirement data files and look models up by ID."""
2
+
3
+ from collections.abc import Iterable, Iterator
4
+ from importlib.resources import files
5
+ from importlib.resources.abc import Traversable
6
+
7
+ import yaml
8
+
9
+ from modelbump.registry.models import Provider, ProviderFile, RetiredModel
10
+
11
+
12
+ class DuplicateModelError(ValueError):
13
+ """Raised when the same model ID appears in more than one entry."""
14
+
15
+
16
+ def load_provider_file(path: Traversable) -> ProviderFile:
17
+ """Read and validate one YAML data file."""
18
+ data = yaml.safe_load(path.read_text(encoding="utf-8"))
19
+ return ProviderFile.model_validate(data)
20
+
21
+
22
+ class Registry:
23
+ """All known retirements, indexed by every model ID and alias."""
24
+
25
+ def __init__(self, sources: Iterable[ProviderFile]) -> None:
26
+ self._sources = tuple(sources)
27
+ self._by_id: dict[str, tuple[Provider, RetiredModel]] = {}
28
+ for source in self._sources:
29
+ for model in source.models:
30
+ for model_id in model.all_ids():
31
+ if model_id in self._by_id:
32
+ raise DuplicateModelError(f"{model_id} appears more than once")
33
+ self._by_id[model_id] = (source.provider, model)
34
+
35
+ @property
36
+ def sources(self) -> tuple[ProviderFile, ...]:
37
+ """The data files this registry was built from."""
38
+ return self._sources
39
+
40
+ def get(self, model_id: str) -> tuple[Provider, RetiredModel] | None:
41
+ """Return the provider and entry for ``model_id``, or None if unknown."""
42
+ return self._by_id.get(model_id)
43
+
44
+ def __iter__(self) -> Iterator[tuple[Provider, RetiredModel]]:
45
+ for source in self._sources:
46
+ for model in source.models:
47
+ yield source.provider, model
48
+
49
+ def __len__(self) -> int:
50
+ return sum(len(source.models) for source in self._sources)
51
+
52
+
53
+ def load_registry() -> Registry:
54
+ """Load every data file shipped inside the package."""
55
+ data_dir = files("modelbump.registry") / "data"
56
+ paths = sorted(
57
+ (p for p in data_dir.iterdir() if p.name.endswith(".yaml")), key=lambda p: p.name
58
+ )
59
+ return Registry(load_provider_file(p) for p in paths)
@@ -0,0 +1,111 @@
1
+ """Data model for the retirement registry.
2
+
3
+ Every field is checked when a data file is loaded, so a typo in a YAML file
4
+ fails the tests instead of silently producing wrong warnings later.
5
+ """
6
+
7
+ from datetime import date
8
+ from enum import StrEnum
9
+ from typing import Self
10
+
11
+ from pydantic import BaseModel, ConfigDict, Field, HttpUrl, model_validator
12
+
13
+
14
+ class Provider(StrEnum):
15
+ """LLM providers whose retirements we track."""
16
+
17
+ ANTHROPIC = "anthropic"
18
+ GOOGLE = "google"
19
+ OPENAI = "openai"
20
+
21
+
22
+ class Status(StrEnum):
23
+ """Where a model is in its life cycle on a given day."""
24
+
25
+ ACTIVE = "active"
26
+ DEPRECATED = "deprecated"
27
+ RETIRED = "retired"
28
+
29
+
30
+ class EarlierPlan(BaseModel):
31
+ """A retirement plan the provider announced and later replaced."""
32
+
33
+ model_config = ConfigDict(frozen=True, extra="forbid")
34
+
35
+ announced: date | None = None
36
+ shutdown: date
37
+ shutdown_is_earliest: bool = False
38
+
39
+
40
+ class RetiredModel(BaseModel):
41
+ """One model version that a provider has announced it will shut down."""
42
+
43
+ model_config = ConfigDict(frozen=True, extra="forbid")
44
+
45
+ id: str = Field(min_length=1, description="Model ID exactly as used in API calls.")
46
+ aliases: tuple[str, ...] = Field(
47
+ default=(), description="Other IDs that point to this same model."
48
+ )
49
+ announced: date | None = Field(
50
+ default=None, description="Day the provider announced the deprecation."
51
+ )
52
+ shutdown: date = Field(description="Day API calls to this model stop working.")
53
+ shutdown_is_earliest: bool = Field(
54
+ default=False,
55
+ description="True when the source only promises the shutdown no sooner than this day.",
56
+ )
57
+ replacement: str | None = Field(
58
+ default=None,
59
+ description="Replacement the source page recommended on the day we retrieved it.",
60
+ )
61
+ superseded: tuple[EarlierPlan, ...] = Field(
62
+ default=(), description="Earlier retirement plans for this model, oldest first."
63
+ )
64
+ notes: str | None = None
65
+
66
+ @model_validator(mode="after")
67
+ def _check_consistency(self) -> Self:
68
+ if self.announced is not None and self.shutdown < self.announced:
69
+ raise ValueError(f"{self.id}: shutdown {self.shutdown} is before announced")
70
+ ids = self.all_ids()
71
+ if len(set(ids)) != len(ids):
72
+ raise ValueError(f"{self.id}: an alias repeats the id or another alias")
73
+ if self.replacement in ids:
74
+ raise ValueError(f"{self.id}: replacement cannot be the model itself")
75
+ for plan in self.superseded:
76
+ if (
77
+ plan.announced is not None
78
+ and self.announced is not None
79
+ and plan.announced >= self.announced
80
+ ):
81
+ raise ValueError(
82
+ f"{self.id}: a superseded plan must be announced before the current one"
83
+ )
84
+ return self
85
+
86
+ def all_ids(self) -> tuple[str, ...]:
87
+ """Return the main ID followed by every alias."""
88
+ return (self.id, *self.aliases)
89
+
90
+ def status_on(self, day: date) -> Status:
91
+ """Return the model's status on ``day``, using the current plan.
92
+
93
+ A model is retired from its shutdown day onwards, and deprecated from
94
+ the announcement day until then.
95
+ """
96
+ if day >= self.shutdown:
97
+ return Status.RETIRED
98
+ if self.announced is not None and day >= self.announced:
99
+ return Status.DEPRECATED
100
+ return Status.ACTIVE
101
+
102
+
103
+ class ProviderFile(BaseModel):
104
+ """The contents of one ``data/<provider>.yaml`` file."""
105
+
106
+ model_config = ConfigDict(frozen=True, extra="forbid")
107
+
108
+ provider: Provider
109
+ source_url: HttpUrl = Field(description="Page the data was copied from.")
110
+ retrieved: date = Field(description="Day we last checked the data against the source.")
111
+ models: tuple[RetiredModel, ...] = Field(min_length=1)
@@ -0,0 +1,26 @@
1
+ """Scanner: find the LLM model IDs a repository depends on (ADR 0023)."""
2
+
3
+ from modelbump.scanner.context import Context, Place, places
4
+ from modelbump.scanner.files import iter_source_files, read_source
5
+ from modelbump.scanner.ids import IdMatch, ModelIdFinder
6
+ from modelbump.scanner.resolve import resolve
7
+ from modelbump.scanner.scan import Finding, ScanResult, scan_path
8
+ from modelbump.scanner.severity import DEFAULT_SOON_DAYS, Assessment, Severity, assess
9
+
10
+ __all__ = [
11
+ "DEFAULT_SOON_DAYS",
12
+ "Assessment",
13
+ "Context",
14
+ "Finding",
15
+ "IdMatch",
16
+ "ModelIdFinder",
17
+ "Place",
18
+ "ScanResult",
19
+ "Severity",
20
+ "assess",
21
+ "iter_source_files",
22
+ "places",
23
+ "read_source",
24
+ "resolve",
25
+ "scan_path",
26
+ ]