openapi-spec-generator 0.1.0__tar.gz

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,98 @@
1
+ Metadata-Version: 2.4
2
+ Name: openapi-spec-generator
3
+ Version: 0.1.0
4
+ Summary: Generate OpenAPI specifications for any REST API project directory.
5
+ License: MIT
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: click>=8.0
9
+ Provides-Extra: claude
10
+ Requires-Dist: anthropic>=0.25; extra == "claude"
11
+ Provides-Extra: openai
12
+ Requires-Dist: openai>=1.0; extra == "openai"
13
+ Provides-Extra: all
14
+ Requires-Dist: anthropic>=0.25; extra == "all"
15
+ Requires-Dist: openai>=1.0; extra == "all"
16
+ Provides-Extra: dev
17
+ Requires-Dist: pytest>=8.0; extra == "dev"
18
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
19
+
20
+ # OpenAPI Generator
21
+
22
+ A pip-installable CLI tool that uses AI to generate OpenAPI 3.0.3 specifications for any REST API project directory.
23
+
24
+ ## Overview
25
+
26
+ Point this tool at any REST API project and it will scan the source files, send them to an AI model (Claude or OpenAI), and produce a valid OpenAPI 3.0.3 JSON specification.
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ # With Claude support (default)
32
+ pip install "openapi-generator[claude]"
33
+
34
+ # With OpenAI support
35
+ pip install "openapi-generator[openai]"
36
+
37
+ # Both providers
38
+ pip install "openapi-generator[all]"
39
+ ```
40
+
41
+ ## Usage
42
+
43
+ ```bash
44
+ openapi-gen <path-to-project> --api-key <your-api-key>
45
+ ```
46
+
47
+ The API key can also be provided via the `OPENAPI_GEN_API_KEY` environment variable:
48
+
49
+ ```bash
50
+ export OPENAPI_GEN_API_KEY=sk-ant-...
51
+ openapi-gen <path-to-project>
52
+ ```
53
+
54
+ ### Options
55
+
56
+ | Option | Default | Description |
57
+ |---|---|---|
58
+ | `<path>` | _(required)_ | Path to the REST API project directory |
59
+ | `--api-key` | `OPENAPI_GEN_API_KEY` env var | AI provider API key |
60
+ | `--provider` | `claude` | AI provider: `claude` or `openai` |
61
+ | `--output`, `-o` | `openapi.json` | Output file path |
62
+ | `--title` | `API` | API title in the spec |
63
+ | `--version` | `1.0.0` | API version in the spec |
64
+
65
+ ### Examples
66
+
67
+ ```bash
68
+ # Generate a spec using Claude (default)
69
+ export OPENAPI_GEN_API_KEY=sk-ant-...
70
+ openapi-gen ./my-api
71
+
72
+ # Generate a spec using OpenAI
73
+ openapi-gen ./my-api --provider openai --api-key sk-...
74
+
75
+ # Specify title, version, and output path
76
+ openapi-gen ./my-api --title "My REST API" --version "2.0.0" --output ./docs/openapi.json
77
+ ```
78
+
79
+ ## Output
80
+
81
+ The generated file follows the [OpenAPI 3.0.3 specification](https://spec.openapis.org/oas/v3.0.3) and can be used directly with tools like Swagger UI, Postman, or any OpenAPI-compatible client generator.
82
+
83
+ ## Supported Languages
84
+
85
+ The tool scans files with the following extensions: `.py`, `.js`, `.ts`, `.go`, `.java`, `.rb`, `.php`, `.cs`
86
+
87
+ ## Development
88
+
89
+ ```bash
90
+ git clone https://github.com/your-org/openapi-generator
91
+ cd openapi-generator
92
+ pip install -e ".[dev]"
93
+ pytest
94
+ ```
95
+
96
+ ## License
97
+
98
+ MIT
@@ -0,0 +1,79 @@
1
+ # OpenAPI Generator
2
+
3
+ A pip-installable CLI tool that uses AI to generate OpenAPI 3.0.3 specifications for any REST API project directory.
4
+
5
+ ## Overview
6
+
7
+ Point this tool at any REST API project and it will scan the source files, send them to an AI model (Claude or OpenAI), and produce a valid OpenAPI 3.0.3 JSON specification.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ # With Claude support (default)
13
+ pip install "openapi-generator[claude]"
14
+
15
+ # With OpenAI support
16
+ pip install "openapi-generator[openai]"
17
+
18
+ # Both providers
19
+ pip install "openapi-generator[all]"
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ```bash
25
+ openapi-gen <path-to-project> --api-key <your-api-key>
26
+ ```
27
+
28
+ The API key can also be provided via the `OPENAPI_GEN_API_KEY` environment variable:
29
+
30
+ ```bash
31
+ export OPENAPI_GEN_API_KEY=sk-ant-...
32
+ openapi-gen <path-to-project>
33
+ ```
34
+
35
+ ### Options
36
+
37
+ | Option | Default | Description |
38
+ |---|---|---|
39
+ | `<path>` | _(required)_ | Path to the REST API project directory |
40
+ | `--api-key` | `OPENAPI_GEN_API_KEY` env var | AI provider API key |
41
+ | `--provider` | `claude` | AI provider: `claude` or `openai` |
42
+ | `--output`, `-o` | `openapi.json` | Output file path |
43
+ | `--title` | `API` | API title in the spec |
44
+ | `--version` | `1.0.0` | API version in the spec |
45
+
46
+ ### Examples
47
+
48
+ ```bash
49
+ # Generate a spec using Claude (default)
50
+ export OPENAPI_GEN_API_KEY=sk-ant-...
51
+ openapi-gen ./my-api
52
+
53
+ # Generate a spec using OpenAI
54
+ openapi-gen ./my-api --provider openai --api-key sk-...
55
+
56
+ # Specify title, version, and output path
57
+ openapi-gen ./my-api --title "My REST API" --version "2.0.0" --output ./docs/openapi.json
58
+ ```
59
+
60
+ ## Output
61
+
62
+ The generated file follows the [OpenAPI 3.0.3 specification](https://spec.openapis.org/oas/v3.0.3) and can be used directly with tools like Swagger UI, Postman, or any OpenAPI-compatible client generator.
63
+
64
+ ## Supported Languages
65
+
66
+ The tool scans files with the following extensions: `.py`, `.js`, `.ts`, `.go`, `.java`, `.rb`, `.php`, `.cs`
67
+
68
+ ## Development
69
+
70
+ ```bash
71
+ git clone https://github.com/your-org/openapi-generator
72
+ cd openapi-generator
73
+ pip install -e ".[dev]"
74
+ pytest
75
+ ```
76
+
77
+ ## License
78
+
79
+ MIT
@@ -0,0 +1,29 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "openapi-spec-generator"
7
+ version = "0.1.0"
8
+ description = "Generate OpenAPI specifications for any REST API project directory."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ dependencies = [
13
+ "click>=8.0",
14
+ ]
15
+
16
+ [project.optional-dependencies]
17
+ claude = ["anthropic>=0.25"]
18
+ openai = ["openai>=1.0"]
19
+ all = ["anthropic>=0.25", "openai>=1.0"]
20
+ dev = ["pytest>=8.0", "pytest-cov>=5.0"]
21
+
22
+ [project.scripts]
23
+ openapi-gen = "openapi_generator.cli:main"
24
+
25
+ [tool.setuptools.packages.find]
26
+ where = ["src"]
27
+
28
+ [tool.pytest.ini_options]
29
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,22 @@
1
+ def call_ai(prompt: str, api_key: str, provider: str) -> str:
2
+ if provider == "claude":
3
+ import anthropic
4
+
5
+ client = anthropic.Anthropic(api_key=api_key)
6
+ with client.messages.stream(
7
+ model="claude-sonnet-4-6",
8
+ max_tokens=4096,
9
+ messages=[{"role": "user", "content": prompt}],
10
+ ) as stream:
11
+ return stream.get_final_message().content[0].text
12
+ elif provider == "openai":
13
+ import openai
14
+
15
+ client = openai.OpenAI(api_key=api_key)
16
+ response = client.chat.completions.create(
17
+ model="gpt-4o",
18
+ messages=[{"role": "user", "content": prompt}],
19
+ )
20
+ return response.choices[0].message.content
21
+ else:
22
+ raise ValueError(f"Unknown provider '{provider}'. Choose 'claude' or 'openai'.")
@@ -0,0 +1,31 @@
1
+ import json
2
+ import click
3
+ from pathlib import Path
4
+ from .generator import generate_spec
5
+
6
+
7
+ @click.command()
8
+ @click.argument("path", type=click.Path(exists=True, file_okay=False, path_type=Path))
9
+ @click.option("--output", "-o", default="openapi.json", show_default=True, help="Output file path.")
10
+ @click.option("--title", default="API", show_default=True, help="API title.")
11
+ @click.option("--version", "api_version", default="1.0.0", show_default=True, help="API version.")
12
+ @click.option(
13
+ "--api-key",
14
+ envvar="OPENAPI_GEN_API_KEY",
15
+ required=True,
16
+ help="AI provider API key (or set OPENAPI_GEN_API_KEY).",
17
+ )
18
+ @click.option(
19
+ "--provider",
20
+ type=click.Choice(["claude", "openai"]),
21
+ default="claude",
22
+ show_default=True,
23
+ help="AI provider to use.",
24
+ )
25
+ def main(path: Path, output: str, title: str, api_version: str, api_key: str, provider: str) -> None:
26
+ """Generate an OpenAPI specification for a REST API project directory."""
27
+ click.echo(f"Scanning {path} ...")
28
+ spec = generate_spec(path, title=title, api_version=api_version, api_key=api_key, provider=provider)
29
+ output_path = Path(output)
30
+ output_path.write_text(json.dumps(spec, indent=2), encoding="utf-8")
31
+ click.echo(f"Wrote JSON spec to {output_path}")
@@ -0,0 +1,37 @@
1
+ import os
2
+ from pathlib import Path
3
+
4
+ _INCLUDE_EXTENSIONS = {".py", ".js", ".ts", ".go", ".java", ".rb", ".php", ".cs"}
5
+ _SKIP_DIRS = {"node_modules", ".git", "__pycache__", "venv", ".venv", "dist", "build", ".eggs"}
6
+
7
+
8
+ def collect_files(project_dir: Path, max_bytes: int = 400_000) -> list[tuple[str, str]]:
9
+ """Walk *project_dir* and return (relative_path, content) for each source file.
10
+
11
+ Stops collecting once the total accumulated size exceeds *max_bytes* to
12
+ avoid exceeding AI model context limits.
13
+ """
14
+ results: list[tuple[str, str]] = []
15
+ total = 0
16
+
17
+ for root, dirs, files in os.walk(project_dir):
18
+ dirs[:] = [d for d in dirs if d not in _SKIP_DIRS]
19
+
20
+ for filename in sorted(files):
21
+ if Path(filename).suffix not in _INCLUDE_EXTENSIONS:
22
+ continue
23
+
24
+ abs_path = Path(root) / filename
25
+ try:
26
+ content = abs_path.read_text(encoding="utf-8")
27
+ except (UnicodeDecodeError, OSError):
28
+ continue
29
+
30
+ total += len(content.encode("utf-8"))
31
+ if total > max_bytes:
32
+ return results
33
+
34
+ rel_path = abs_path.relative_to(project_dir).as_posix()
35
+ results.append((rel_path, content))
36
+
37
+ return results
@@ -0,0 +1,49 @@
1
+ import json
2
+ import re
3
+ from pathlib import Path
4
+
5
+ from .file_collector import collect_files
6
+ from .ai_client import call_ai
7
+
8
+ _SYSTEM_PROMPT = (
9
+ "You are an expert OpenAPI specification writer. "
10
+ "Given source files from a REST API project, produce a complete, valid "
11
+ "OpenAPI 3.0.3 specification in JSON. "
12
+ "Respond with ONLY the raw JSON — no markdown fences, no explanation, no commentary."
13
+ )
14
+
15
+
16
+ def _build_prompt(files: list[tuple[str, str]], title: str, api_version: str) -> str:
17
+ file_blocks = "\n\n".join(
18
+ f"### {path}\n{content}" for path, content in files
19
+ )
20
+ return (
21
+ f"{_SYSTEM_PROMPT}\n\n"
22
+ f"API title: {title}\n"
23
+ f"API version: {api_version}\n\n"
24
+ f"Source files:\n\n{file_blocks}"
25
+ )
26
+
27
+
28
+ def _parse_json(raw: str) -> dict:
29
+ text = raw.strip()
30
+ text = re.sub(r"^```(?:json)?\s*", "", text)
31
+ text = re.sub(r"\s*```$", "", text)
32
+ try:
33
+ return json.loads(text)
34
+ except json.JSONDecodeError as exc:
35
+ raise ValueError(f"AI response was not valid JSON:\n{raw[:500]}") from exc
36
+
37
+
38
+ def generate_spec(
39
+ project_dir: Path,
40
+ *,
41
+ title: str = "API",
42
+ api_version: str = "1.0.0",
43
+ api_key: str,
44
+ provider: str = "claude",
45
+ ) -> dict:
46
+ files = collect_files(project_dir)
47
+ prompt = _build_prompt(files, title, api_version)
48
+ raw = call_ai(prompt, api_key, provider)
49
+ return _parse_json(raw)
@@ -0,0 +1,98 @@
1
+ Metadata-Version: 2.4
2
+ Name: openapi-spec-generator
3
+ Version: 0.1.0
4
+ Summary: Generate OpenAPI specifications for any REST API project directory.
5
+ License: MIT
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: click>=8.0
9
+ Provides-Extra: claude
10
+ Requires-Dist: anthropic>=0.25; extra == "claude"
11
+ Provides-Extra: openai
12
+ Requires-Dist: openai>=1.0; extra == "openai"
13
+ Provides-Extra: all
14
+ Requires-Dist: anthropic>=0.25; extra == "all"
15
+ Requires-Dist: openai>=1.0; extra == "all"
16
+ Provides-Extra: dev
17
+ Requires-Dist: pytest>=8.0; extra == "dev"
18
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
19
+
20
+ # OpenAPI Generator
21
+
22
+ A pip-installable CLI tool that uses AI to generate OpenAPI 3.0.3 specifications for any REST API project directory.
23
+
24
+ ## Overview
25
+
26
+ Point this tool at any REST API project and it will scan the source files, send them to an AI model (Claude or OpenAI), and produce a valid OpenAPI 3.0.3 JSON specification.
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ # With Claude support (default)
32
+ pip install "openapi-generator[claude]"
33
+
34
+ # With OpenAI support
35
+ pip install "openapi-generator[openai]"
36
+
37
+ # Both providers
38
+ pip install "openapi-generator[all]"
39
+ ```
40
+
41
+ ## Usage
42
+
43
+ ```bash
44
+ openapi-gen <path-to-project> --api-key <your-api-key>
45
+ ```
46
+
47
+ The API key can also be provided via the `OPENAPI_GEN_API_KEY` environment variable:
48
+
49
+ ```bash
50
+ export OPENAPI_GEN_API_KEY=sk-ant-...
51
+ openapi-gen <path-to-project>
52
+ ```
53
+
54
+ ### Options
55
+
56
+ | Option | Default | Description |
57
+ |---|---|---|
58
+ | `<path>` | _(required)_ | Path to the REST API project directory |
59
+ | `--api-key` | `OPENAPI_GEN_API_KEY` env var | AI provider API key |
60
+ | `--provider` | `claude` | AI provider: `claude` or `openai` |
61
+ | `--output`, `-o` | `openapi.json` | Output file path |
62
+ | `--title` | `API` | API title in the spec |
63
+ | `--version` | `1.0.0` | API version in the spec |
64
+
65
+ ### Examples
66
+
67
+ ```bash
68
+ # Generate a spec using Claude (default)
69
+ export OPENAPI_GEN_API_KEY=sk-ant-...
70
+ openapi-gen ./my-api
71
+
72
+ # Generate a spec using OpenAI
73
+ openapi-gen ./my-api --provider openai --api-key sk-...
74
+
75
+ # Specify title, version, and output path
76
+ openapi-gen ./my-api --title "My REST API" --version "2.0.0" --output ./docs/openapi.json
77
+ ```
78
+
79
+ ## Output
80
+
81
+ The generated file follows the [OpenAPI 3.0.3 specification](https://spec.openapis.org/oas/v3.0.3) and can be used directly with tools like Swagger UI, Postman, or any OpenAPI-compatible client generator.
82
+
83
+ ## Supported Languages
84
+
85
+ The tool scans files with the following extensions: `.py`, `.js`, `.ts`, `.go`, `.java`, `.rb`, `.php`, `.cs`
86
+
87
+ ## Development
88
+
89
+ ```bash
90
+ git clone https://github.com/your-org/openapi-generator
91
+ cd openapi-generator
92
+ pip install -e ".[dev]"
93
+ pytest
94
+ ```
95
+
96
+ ## License
97
+
98
+ MIT
@@ -0,0 +1,14 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/openapi_generator/__init__.py
4
+ src/openapi_generator/ai_client.py
5
+ src/openapi_generator/cli.py
6
+ src/openapi_generator/file_collector.py
7
+ src/openapi_generator/generator.py
8
+ src/openapi_spec_generator.egg-info/PKG-INFO
9
+ src/openapi_spec_generator.egg-info/SOURCES.txt
10
+ src/openapi_spec_generator.egg-info/dependency_links.txt
11
+ src/openapi_spec_generator.egg-info/entry_points.txt
12
+ src/openapi_spec_generator.egg-info/requires.txt
13
+ src/openapi_spec_generator.egg-info/top_level.txt
14
+ tests/test_generator.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ openapi-gen = openapi_generator.cli:main
@@ -0,0 +1,15 @@
1
+ click>=8.0
2
+
3
+ [all]
4
+ anthropic>=0.25
5
+ openai>=1.0
6
+
7
+ [claude]
8
+ anthropic>=0.25
9
+
10
+ [dev]
11
+ pytest>=8.0
12
+ pytest-cov>=5.0
13
+
14
+ [openai]
15
+ openai>=1.0
@@ -0,0 +1,82 @@
1
+ import json
2
+ import pytest
3
+ from pathlib import Path
4
+ from unittest.mock import patch
5
+
6
+ from openapi_generator.file_collector import collect_files
7
+ from openapi_generator.generator import generate_spec
8
+
9
+
10
+ # --- file_collector tests ---
11
+
12
+ def test_collect_files_filters_extensions(tmp_path: Path) -> None:
13
+ (tmp_path / "app.py").write_text("# python")
14
+ (tmp_path / "README.md").write_text("# docs")
15
+ (tmp_path / "logo.png").write_bytes(b"\x89PNG")
16
+
17
+ files = collect_files(tmp_path)
18
+ paths = [p for p, _ in files]
19
+ assert "app.py" in paths
20
+ assert "README.md" not in paths
21
+ assert "logo.png" not in paths
22
+
23
+
24
+ def test_collect_files_respects_max_bytes(tmp_path: Path) -> None:
25
+ # "a_small.py" sorts before "z_big.py", so small is collected first;
26
+ # adding big would exceed the budget, so we stop with exactly 1 file.
27
+ (tmp_path / "a_small.py").write_text("y" * 100)
28
+ (tmp_path / "z_big.py").write_text("x" * 300)
29
+
30
+ files = collect_files(tmp_path, max_bytes=250)
31
+ assert len(files) == 1
32
+ assert files[0][0] == "a_small.py"
33
+
34
+
35
+ def test_collect_files_skips_excluded_dirs(tmp_path: Path) -> None:
36
+ node_modules = tmp_path / "node_modules"
37
+ node_modules.mkdir()
38
+ (node_modules / "dep.js").write_text("module.exports = {}")
39
+ (tmp_path / "index.js").write_text("const x = 1")
40
+
41
+ files = collect_files(tmp_path)
42
+ paths = [p for p, _ in files]
43
+ assert "index.js" in paths
44
+ assert not any("node_modules" in p for p in paths)
45
+
46
+
47
+ # --- generator tests ---
48
+
49
+ def test_generate_spec_calls_ai_and_parses_result(tmp_path: Path) -> None:
50
+ (tmp_path / "app.py").write_text("# flask app")
51
+ fake_spec = {
52
+ "openapi": "3.0.3",
53
+ "info": {"title": "Test API", "version": "0.1.0"},
54
+ "paths": {},
55
+ }
56
+
57
+ with patch("openapi_generator.generator.call_ai", return_value=json.dumps(fake_spec)):
58
+ spec = generate_spec(tmp_path, title="Test API", api_version="0.1.0", api_key="fake", provider="claude")
59
+
60
+ assert spec["openapi"] == "3.0.3"
61
+ assert spec["info"]["title"] == "Test API"
62
+ assert spec["info"]["version"] == "0.1.0"
63
+ assert "paths" in spec
64
+
65
+
66
+ def test_generate_spec_strips_markdown_fences(tmp_path: Path) -> None:
67
+ (tmp_path / "app.py").write_text("# flask app")
68
+ fake_spec = {"openapi": "3.0.3", "info": {"title": "A", "version": "1"}, "paths": {}}
69
+ raw = f"```json\n{json.dumps(fake_spec)}\n```"
70
+
71
+ with patch("openapi_generator.generator.call_ai", return_value=raw):
72
+ spec = generate_spec(tmp_path, title="A", api_version="1", api_key="fake", provider="claude")
73
+
74
+ assert spec["openapi"] == "3.0.3"
75
+
76
+
77
+ def test_generate_spec_raises_on_invalid_json(tmp_path: Path) -> None:
78
+ (tmp_path / "app.py").write_text("# flask app")
79
+
80
+ with patch("openapi_generator.generator.call_ai", return_value="not json at all"):
81
+ with pytest.raises(ValueError, match="not valid JSON"):
82
+ generate_spec(tmp_path, title="A", api_version="1", api_key="fake", provider="claude")