Skip to content

Commit f617d89

Browse files
committed
versioning
1 parent a1fc416 commit f617d89

4 files changed

Lines changed: 71 additions & 24 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "openresponses-types"
3-
version = "0.1.0"
3+
version = "2.3.0"
44
description = "Python SDK for OpenResponses specification"
55
readme = "README.md"
66
license = "Apache-2.0"

scripts/generate_types.py

Lines changed: 67 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@
1010
Options:
1111
--force Regenerate even if spec hasn't changed
1212
--check Check if spec has changed without regenerating (exit 1 if changed)
13-
--version Show current spec hash and exit
13+
--version Show current spec version and hash, then exit
1414
"""
1515

1616
import argparse
1717
import hashlib
18+
import json
1819
import re
1920
import subprocess
2021
import sys
@@ -28,8 +29,10 @@
2829
SPEC_CACHE_DIR = PROJECT_ROOT / "src" / "openresponses_types" / "_spec_cache"
2930
SPEC_CACHE_FILE = SPEC_CACHE_DIR / "openapi.json"
3031
SPEC_HASH_FILE = SPEC_CACHE_DIR / "openapi.sha256"
32+
SPEC_VERSION_FILE = SPEC_CACHE_DIR / "openapi.version"
3133
OUTPUT_FILE = PROJECT_ROOT / "src" / "openresponses_types" / "types.py"
3234
INIT_FILE = PROJECT_ROOT / "src" / "openresponses_types" / "__init__.py"
35+
PYPROJECT_FILE = PROJECT_ROOT / "pyproject.toml"
3336

3437
GENERATION_HEADER = '''\
3538
"""Auto-generated Pydantic models from OpenResponses OpenAPI specification.
@@ -38,6 +41,7 @@
3841
3942
This file is generated by: scripts/generate_types.py
4043
Source: {spec_url}
44+
Spec Version: {spec_version}
4145
Spec Hash: {spec_hash}
4246
4347
To regenerate:
@@ -54,6 +58,12 @@ def fetch_spec() -> bytes:
5458
return response.read()
5559

5660

61+
def extract_spec_version(content: bytes) -> str:
62+
"""Extract the version from the OpenAPI spec."""
63+
spec = json.loads(content)
64+
return spec.get("info", {}).get("version", "0.0.0")
65+
66+
5767
def compute_hash(content: bytes) -> str:
5868
"""Compute SHA-256 hash of content."""
5969
return hashlib.sha256(content).hexdigest()
@@ -66,11 +76,19 @@ def get_cached_hash() -> str | None:
6676
return None
6777

6878

69-
def save_spec_cache(content: bytes, spec_hash: str) -> None:
70-
"""Save the spec and its hash to the cache directory."""
79+
def get_cached_version() -> str | None:
80+
"""Get the previously stored spec version, if any."""
81+
if SPEC_VERSION_FILE.exists():
82+
return SPEC_VERSION_FILE.read_text().strip()
83+
return None
84+
85+
86+
def save_spec_cache(content: bytes, spec_hash: str, spec_version: str) -> None:
87+
"""Save the spec, its hash, and version to the cache directory."""
7188
SPEC_CACHE_DIR.mkdir(parents=True, exist_ok=True)
7289
SPEC_CACHE_FILE.write_bytes(content)
7390
SPEC_HASH_FILE.write_text(spec_hash)
91+
SPEC_VERSION_FILE.write_text(spec_version)
7492

7593

7694
def fix_discriminator_issues() -> None:
@@ -113,7 +131,7 @@ def format_output() -> None:
113131
print(f"Warning: ruff formatting failed: {result.stderr}", file=sys.stderr)
114132

115133

116-
def generate_models(spec_hash: str) -> None:
134+
def generate_models(spec_hash: str, spec_version: str) -> None:
117135
"""Run datamodel-codegen to generate Pydantic models."""
118136
print("Generating Pydantic models...")
119137

@@ -141,17 +159,21 @@ def generate_models(spec_hash: str) -> None:
141159
print(f"Error generating models: {result.stderr}", file=sys.stderr)
142160
sys.exit(1)
143161

144-
prepend_header(spec_hash)
162+
prepend_header(spec_hash, spec_version)
145163
fix_discriminator_issues()
146164
format_output()
147-
update_init_spec_hash(spec_hash)
165+
update_init_metadata(spec_hash, spec_version)
148166
print(f"Generated: {OUTPUT_FILE}")
149167

150168

151-
def prepend_header(spec_hash: str) -> None:
169+
def prepend_header(spec_hash: str, spec_version: str) -> None:
152170
"""Prepend generation header to the output file."""
153171
content = OUTPUT_FILE.read_text()
154-
header = GENERATION_HEADER.format(spec_url=OPENRESPONSES_SPEC_URL, spec_hash=spec_hash)
172+
header = GENERATION_HEADER.format(
173+
spec_url=OPENRESPONSES_SPEC_URL,
174+
spec_hash=spec_hash,
175+
spec_version=spec_version,
176+
)
155177

156178
lines = content.split("\n")
157179
filtered_lines = []
@@ -166,16 +188,31 @@ def prepend_header(spec_hash: str) -> None:
166188
OUTPUT_FILE.write_text(header + "\n".join(filtered_lines))
167189

168190

169-
def update_init_spec_hash(spec_hash: str) -> None:
170-
"""Update the __spec_hash__ in __init__.py."""
191+
def update_init_metadata(spec_hash: str, spec_version: str) -> None:
192+
"""Update the __spec_hash__ and __spec_version__ in __init__.py."""
171193
if not INIT_FILE.exists():
172194
return
173195

174196
content = INIT_FILE.read_text()
197+
175198
# Update __spec_hash__ if it exists
176199
if "__spec_hash__" in content:
177200
content = re.sub(r'__spec_hash__\s*=\s*"[^"]*"', f'__spec_hash__ = "{spec_hash}"', content)
178-
INIT_FILE.write_text(content)
201+
202+
# Update __spec_version__ if it exists
203+
if "__spec_version__" in content:
204+
content = re.sub(r'__spec_version__\s*=\s*"[^"]*"', f'__spec_version__ = "{spec_version}"', content)
205+
206+
INIT_FILE.write_text(content)
207+
208+
209+
def suggest_package_version(spec_version: str) -> str:
210+
"""Suggest a package version based on the spec version.
211+
212+
Package version matches the spec version directly.
213+
For hotfixes, use PEP 440 post-releases (e.g., 2.3.0.post1).
214+
"""
215+
return spec_version
179216

180217

181218
def main() -> None:
@@ -184,43 +221,51 @@ def main() -> None:
184221
parser.add_argument(
185222
"--check", action="store_true", help="Check if spec has changed without regenerating (exit 1 if changed)"
186223
)
187-
parser.add_argument("--version", action="store_true", help="Show current spec hash and exit")
224+
parser.add_argument("--version", action="store_true", help="Show current spec version and hash, then exit")
188225
args = parser.parse_args()
189226

190227
if args.version:
228+
cached_version = get_cached_version()
191229
cached_hash = get_cached_hash()
192-
if cached_hash:
193-
print(f"Current spec hash: {cached_hash}")
230+
if cached_version and cached_hash:
231+
print(f"Spec version: {cached_version}")
232+
print(f"Spec hash: {cached_hash}")
233+
print(f"Suggested package version: {suggest_package_version(cached_version)}")
194234
else:
195-
print("No spec hash cached yet. Run without --version to generate.")
235+
print("No spec cached yet. Run without --version to generate.")
196236
return
197237

198238
spec_content = fetch_spec()
199239
current_hash = compute_hash(spec_content)
240+
current_version = extract_spec_version(spec_content)
200241
cached_hash = get_cached_hash()
242+
cached_version = get_cached_version()
201243

202244
if cached_hash == current_hash and not args.force:
203-
print(f"OpenResponses spec unchanged (hash: {current_hash[:12]}...)")
245+
print(f"OpenResponses spec unchanged (v{current_version}, hash: {current_hash[:12]}...)")
204246
if args.check:
205247
sys.exit(0)
206248
print("Use --force to regenerate anyway.")
207249
return
208250

209251
if cached_hash is None:
210-
print("First time generating OpenResponses types.")
252+
print(f"First time generating OpenResponses types (spec v{current_version}).")
211253
else:
212254
print("OpenResponses spec has CHANGED!")
213-
print(f" Previous: {cached_hash[:12]}...")
214-
print(f" Current: {current_hash[:12]}...")
255+
print(f" Previous: v{cached_version} (hash: {cached_hash[:12]}...)")
256+
print(f" Current: v{current_version} (hash: {current_hash[:12]}...)")
215257

216258
if args.check:
217259
print("\nSpec change detected. Run without --check to regenerate.")
218260
sys.exit(1)
219261

220-
save_spec_cache(spec_content, current_hash)
221-
generate_models(current_hash)
262+
save_spec_cache(spec_content, current_hash, current_version)
263+
generate_models(current_hash, current_version)
222264

223-
print("\nGeneration complete!")
265+
print(f"\nGeneration complete!")
266+
print(f"Spec version: {current_version}")
267+
print(f"Suggested package version: {suggest_package_version(current_version)}")
268+
print(f"\nTo release, update pyproject.toml version and tag: git tag v{suggest_package_version(current_version)}")
224269

225270

226271
if __name__ == "__main__":

src/openresponses_types/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
event: ResponseStreamEvent = ...
1515
"""
1616

17-
__version__ = "0.1.0"
17+
__version__ = "2.3.0"
18+
__spec_version__ = "2.3.0"
1819
__spec_hash__ = "915047617fddd639c691fe1e00d5ba6917b7187d7abc62adf074fd7c823bad7f"
1920

2021
# Re-export all types from generated module

src/openresponses_types/types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
55
This file is generated by: scripts/generate_types.py
66
Source: https://raw.githubusercontent.com/openresponses/openresponses/main/public/openapi/openapi.json
7+
Spec Version: 2.3.0
78
Spec Hash: 915047617fddd639c691fe1e00d5ba6917b7187d7abc62adf074fd7c823bad7f
89
910
To regenerate:

0 commit comments

Comments
 (0)