msra-codegen 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.
- msra_codegen/README.md +23 -0
- msra_codegen/__init__.py +6 -0
- msra_codegen/__main__.py +5 -0
- msra_codegen/bridge.py +29 -0
- msra_codegen/cli.py +105 -0
- msra_codegen/codegen_context.py +1690 -0
- msra_codegen/config.toml +164 -0
- msra_codegen/core_naming.py +155 -0
- msra_codegen/docs_generator.py +346 -0
- msra_codegen/file_utils.py +8 -0
- msra_codegen/funcresult.py +156 -0
- msra_codegen/generator.py +6 -0
- msra_codegen/generator_config.py +35 -0
- msra_codegen/github_workflows.py +129 -0
- msra_codegen/gitignore.py +31 -0
- msra_codegen/issue_templates.py +100 -0
- msra_codegen/logo_assets.py +99 -0
- msra_codegen/msra_serializer.py +205 -0
- msra_codegen/node_export.js +296 -0
- msra_codegen/package_metadata.py +306 -0
- msra_codegen/package_writer.py +175 -0
- msra_codegen/project_model.py +490 -0
- msra_codegen/python_formatting.py +88 -0
- msra_codegen/python_render.py +242 -0
- msra_codegen/readme_pipeline.py +519 -0
- msra_codegen/requirements.txt +5 -0
- msra_codegen/template_engine.py +26 -0
- msra_codegen/templates/Makefile.tpl +44 -0
- msra_codegen/templates/README.md.tpl +55 -0
- msra_codegen/templates/abstraction/__init__.py.tpl +188 -0
- msra_codegen/templates/abstraction/regexes.py.tpl +25 -0
- msra_codegen/templates/docs/requirements.txt.tpl +3 -0
- msra_codegen/templates/docs/source/Makefile.tpl +20 -0
- msra_codegen/templates/docs/source/api.rst.tpl +9 -0
- msra_codegen/templates/docs/source/conf.py.tpl +88 -0
- msra_codegen/templates/docs/source/index.rst.tpl +14 -0
- msra_codegen/templates/docs/source/module.rst.tpl +34 -0
- msra_codegen/templates/docs/source/quick_start.rst.tpl +19 -0
- msra_codegen/templates/endpoints_init.py.tpl +15 -0
- msra_codegen/templates/example.py.tpl +1 -0
- msra_codegen/templates/function.py.tpl +364 -0
- msra_codegen/templates/github/issue_templates/bug_report.yml.tpl +55 -0
- msra_codegen/templates/github/issue_templates/config.yml.tpl +8 -0
- msra_codegen/templates/github/issue_templates/documentation_issue.yml.tpl +33 -0
- msra_codegen/templates/github/issue_templates/feature_request.yml.tpl +36 -0
- msra_codegen/templates/github/workflows/publish.yml.tpl +100 -0
- msra_codegen/templates/github/workflows/source-sync.yml.tpl +177 -0
- msra_codegen/templates/github/workflows/tests.yml.tpl +69 -0
- msra_codegen/templates/gitignore.tpl +3 -0
- msra_codegen/templates/group.py.tpl +56 -0
- msra_codegen/templates/group_init.py.tpl +14 -0
- msra_codegen/templates/init.py.tpl +4 -0
- msra_codegen/templates/licenses/GPL-3.0-or-later.txt.tpl +674 -0
- msra_codegen/templates/licenses/MIT.txt.tpl +21 -0
- msra_codegen/templates/manager.py.tpl +257 -0
- msra_codegen/templates/pyproject.toml.tpl +38 -0
- msra_codegen/templates/tests/api_test.py.tpl +49 -0
- msra_codegen/templates/tests/conftest.py.tpl +21 -0
- msra_codegen/templates/variable.py.tpl +54 -0
- msra_codegen/tests_generator.py +988 -0
- msra_codegen/typespec.py +275 -0
- msra_codegen/validation.py +118 -0
- msra_codegen-0.1.0.dist-info/METADATA +47 -0
- msra_codegen-0.1.0.dist-info/RECORD +68 -0
- msra_codegen-0.1.0.dist-info/WHEEL +5 -0
- msra_codegen-0.1.0.dist-info/entry_points.txt +2 -0
- msra_codegen-0.1.0.dist-info/licenses/LICENSE +674 -0
- msra_codegen-0.1.0.dist-info/top_level.txt +1 -0
msra_codegen/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# msra-codegen
|
|
2
|
+
|
|
3
|
+
MSRA to async Python client generator.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```powershell
|
|
8
|
+
pip install msra-codegen
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```powershell
|
|
14
|
+
msra-codegen generate .\examples\example\example.msra -o .\generated
|
|
15
|
+
msra-codegen validate .\generated
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The module entrypoint stays available as well:
|
|
19
|
+
|
|
20
|
+
```powershell
|
|
21
|
+
python -m msra_codegen generate .\examples\example\example.msra -o .\generated
|
|
22
|
+
python -m msra_codegen validate .\generated
|
|
23
|
+
```
|
msra_codegen/__init__.py
ADDED
msra_codegen/__main__.py
ADDED
msra_codegen/bridge.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import subprocess
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
PACKAGE_ROOT = Path(__file__).resolve().parent
|
|
10
|
+
NODE_EXPORT = PACKAGE_ROOT / "node_export.js"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def load_msra_document(msra_path: Path) -> dict[str, Any]:
|
|
14
|
+
msra_path = msra_path.resolve()
|
|
15
|
+
if not msra_path.exists():
|
|
16
|
+
raise FileNotFoundError(msra_path)
|
|
17
|
+
|
|
18
|
+
process = subprocess.run(
|
|
19
|
+
["node", str(NODE_EXPORT), str(msra_path)],
|
|
20
|
+
capture_output=True,
|
|
21
|
+
text=True,
|
|
22
|
+
encoding="utf-8",
|
|
23
|
+
errors="replace",
|
|
24
|
+
check=False,
|
|
25
|
+
)
|
|
26
|
+
if process.returncode != 0:
|
|
27
|
+
message = process.stderr.strip() or process.stdout.strip() or "MSRA parser failed"
|
|
28
|
+
raise RuntimeError(message)
|
|
29
|
+
return json.loads(process.stdout)
|
msra_codegen/cli.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import shutil
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from .bridge import load_msra_document
|
|
9
|
+
from .msra_serializer import write_merged_msra_document
|
|
10
|
+
from .package_writer import generate_project
|
|
11
|
+
from .project_model import build_project
|
|
12
|
+
from .validation import validate_generated_project
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
16
|
+
parser = argparse.ArgumentParser(
|
|
17
|
+
prog="msra-codegen",
|
|
18
|
+
description="Generate or validate an async Python client and Sphinx docs from an MSRA document.",
|
|
19
|
+
)
|
|
20
|
+
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
21
|
+
|
|
22
|
+
generate_parser = subparsers.add_parser(
|
|
23
|
+
"generate",
|
|
24
|
+
help="Generate an async Python client and Sphinx docs from an MSRA document.",
|
|
25
|
+
)
|
|
26
|
+
generate_parser.add_argument("msra_file", type=Path, help="Path to the source .msra file")
|
|
27
|
+
generate_parser.add_argument(
|
|
28
|
+
"-o",
|
|
29
|
+
"--output",
|
|
30
|
+
type=Path,
|
|
31
|
+
default=Path("generated"),
|
|
32
|
+
help="Output directory for the generated project (default: ./generated)",
|
|
33
|
+
)
|
|
34
|
+
generate_parser.add_argument(
|
|
35
|
+
"--no-cleanup",
|
|
36
|
+
action="store_true",
|
|
37
|
+
help="Keep the existing output directory contents and preserve merged.msra after generation",
|
|
38
|
+
)
|
|
39
|
+
generate_parser.set_defaults(handler=handle_generate)
|
|
40
|
+
|
|
41
|
+
validate_parser = subparsers.add_parser(
|
|
42
|
+
"validate",
|
|
43
|
+
help="Validate a generated project with python syntax, ruff, and mypy.",
|
|
44
|
+
)
|
|
45
|
+
validate_parser.add_argument(
|
|
46
|
+
"output_dir",
|
|
47
|
+
type=Path,
|
|
48
|
+
help="Path to a generated project directory",
|
|
49
|
+
)
|
|
50
|
+
validate_parser.set_defaults(handler=handle_validate)
|
|
51
|
+
return parser
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def main(argv: list[str] | None = None) -> int:
|
|
55
|
+
if hasattr(sys.stdout, "reconfigure"):
|
|
56
|
+
sys.stdout.reconfigure(encoding="utf-8")
|
|
57
|
+
parser = build_parser()
|
|
58
|
+
args = parser.parse_args(argv)
|
|
59
|
+
args.handler(args)
|
|
60
|
+
return 0
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def handle_generate(args: argparse.Namespace) -> None:
|
|
64
|
+
ast = load_msra_document(args.msra_file)
|
|
65
|
+
output_root = args.output.resolve()
|
|
66
|
+
if not args.no_cleanup:
|
|
67
|
+
remove_output_tree(output_root)
|
|
68
|
+
merged_source_path = output_root / "merged.msra"
|
|
69
|
+
write_merged_msra_document(ast, merged_source_path)
|
|
70
|
+
project = build_project(ast, args.msra_file)
|
|
71
|
+
try:
|
|
72
|
+
generate_project(
|
|
73
|
+
project,
|
|
74
|
+
output_dir=args.output,
|
|
75
|
+
source_root=args.msra_file.resolve().parent,
|
|
76
|
+
)
|
|
77
|
+
finally:
|
|
78
|
+
if not args.no_cleanup and merged_source_path.exists():
|
|
79
|
+
merged_source_path.unlink()
|
|
80
|
+
|
|
81
|
+
message = f"Generated {project['app'].get('package_name', '')} into {output_root}"
|
|
82
|
+
if args.no_cleanup:
|
|
83
|
+
message += f" (merged source in {merged_source_path}, docs in {output_root / 'docs'})"
|
|
84
|
+
else:
|
|
85
|
+
message += f" (docs in {output_root / 'docs'}, merged source cleaned)"
|
|
86
|
+
print(message)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def handle_validate(args: argparse.Namespace) -> None:
|
|
90
|
+
output_root = args.output_dir.resolve()
|
|
91
|
+
validate_generated_project(output_root)
|
|
92
|
+
print(f"Validated generated project in {output_root}")
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def remove_output_tree(output_root: Path) -> None:
|
|
96
|
+
if not output_root.exists():
|
|
97
|
+
return
|
|
98
|
+
if output_root.is_dir() and not output_root.is_symlink():
|
|
99
|
+
shutil.rmtree(output_root)
|
|
100
|
+
return
|
|
101
|
+
output_root.unlink()
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
if __name__ == "__main__":
|
|
105
|
+
raise SystemExit(main())
|