code2schema 0.1.2__tar.gz → 0.1.4__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.
- {code2schema-0.1.2 → code2schema-0.1.4}/PKG-INFO +6 -6
- {code2schema-0.1.2 → code2schema-0.1.4}/README.md +5 -5
- {code2schema-0.1.2 → code2schema-0.1.4}/code2schema/__init__.py +1 -1
- {code2schema-0.1.2 → code2schema-0.1.4}/code2schema/analyzer/events.py +29 -23
- {code2schema-0.1.2 → code2schema-0.1.4}/code2schema/cli.py +104 -44
- {code2schema-0.1.2 → code2schema-0.1.4}/code2schema.egg-info/PKG-INFO +6 -6
- {code2schema-0.1.2 → code2schema-0.1.4}/pyproject.toml +1 -1
- {code2schema-0.1.2 → code2schema-0.1.4}/tests/test_code2schema.py +47 -0
- {code2schema-0.1.2 → code2schema-0.1.4}/LICENSE +0 -0
- {code2schema-0.1.2 → code2schema-0.1.4}/code2schema/analyzer/__init__.py +0 -0
- {code2schema-0.1.2 → code2schema-0.1.4}/code2schema/analyzer/cqrs.py +0 -0
- {code2schema-0.1.2 → code2schema-0.1.4}/code2schema/analyzer/graph.py +0 -0
- {code2schema-0.1.2 → code2schema-0.1.4}/code2schema/codegen/__init__.py +0 -0
- {code2schema-0.1.2 → code2schema-0.1.4}/code2schema/codegen/visualizer.py +0 -0
- {code2schema-0.1.2 → code2schema-0.1.4}/code2schema/core/__init__.py +0 -0
- {code2schema-0.1.2 → code2schema-0.1.4}/code2schema/core/extractor.py +0 -0
- {code2schema-0.1.2 → code2schema-0.1.4}/code2schema/core/models.py +0 -0
- {code2schema-0.1.2 → code2schema-0.1.4}/code2schema.egg-info/SOURCES.txt +0 -0
- {code2schema-0.1.2 → code2schema-0.1.4}/code2schema.egg-info/dependency_links.txt +0 -0
- {code2schema-0.1.2 → code2schema-0.1.4}/code2schema.egg-info/entry_points.txt +0 -0
- {code2schema-0.1.2 → code2schema-0.1.4}/code2schema.egg-info/requires.txt +0 -0
- {code2schema-0.1.2 → code2schema-0.1.4}/code2schema.egg-info/top_level.txt +0 -0
- {code2schema-0.1.2 → code2schema-0.1.4}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code2schema
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: Semantic compiler: Code → AST → CQRS Model → Workflow DAG → Proto/Schema
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Keywords: ast,cqrs,static-analysis,code-quality,schema
|
|
@@ -34,13 +34,13 @@ Dynamic: license-file
|
|
|
34
34
|
|
|
35
35
|
## AI Cost Tracking
|
|
36
36
|
|
|
37
|
-
    
|
|
38
|
+
  
|
|
39
39
|
|
|
40
|
-
- 🤖 **LLM usage:** $0.
|
|
41
|
-
- 👤 **Human dev:** ~$
|
|
40
|
+
- 🤖 **LLM usage:** $0.4500 (3 commits)
|
|
41
|
+
- 👤 **Human dev:** ~$350 (3.5h @ $100/h, 30min dedup)
|
|
42
42
|
|
|
43
|
-
Generated on 2026-05-
|
|
43
|
+
Generated on 2026-05-07 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
|
|
44
44
|
|
|
45
45
|
---
|
|
46
46
|
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
|
|
4
4
|
## AI Cost Tracking
|
|
5
5
|
|
|
6
|
-
    
|
|
7
|
+
  
|
|
8
8
|
|
|
9
|
-
- 🤖 **LLM usage:** $0.
|
|
10
|
-
- 👤 **Human dev:** ~$
|
|
9
|
+
- 🤖 **LLM usage:** $0.4500 (3 commits)
|
|
10
|
+
- 👤 **Human dev:** ~$350 (3.5h @ $100/h, 30min dedup)
|
|
11
11
|
|
|
12
|
-
Generated on 2026-05-
|
|
12
|
+
Generated on 2026-05-07 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
@@ -72,39 +72,33 @@ class EventModel:
|
|
|
72
72
|
|
|
73
73
|
# ── Inference ─────────────────────────────────────────────────────────────────
|
|
74
74
|
|
|
75
|
-
def
|
|
76
|
-
"""
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
all_funcs: dict[str, FunctionIR] = {}
|
|
80
|
-
for mod in modules:
|
|
81
|
-
for f in mod.functions:
|
|
82
|
-
all_funcs[f.qualified_name] = f
|
|
83
|
-
all_funcs[f.name] = f # short alias
|
|
84
|
-
|
|
85
|
-
# Krok 1: znajdź emiterów
|
|
86
|
-
emitters: dict[str, DomainEvent] = {}
|
|
75
|
+
def _find_emitters(modules: List[ModuleIR]) -> List[DomainEvent]:
|
|
76
|
+
"""Krok 1: znajdź funkcje emitujące zdarzenia."""
|
|
77
|
+
events: List[DomainEvent] = []
|
|
87
78
|
for mod in modules:
|
|
88
79
|
for f in mod.functions:
|
|
89
80
|
if _EVENT_EMIT_PATTERNS.search(f.name) or any(
|
|
90
81
|
_EVENT_EMIT_PATTERNS.search(c) for c in f.calls
|
|
91
82
|
):
|
|
92
83
|
event_name = _derive_event_name(f.name)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
model.events.append(ev)
|
|
84
|
+
events.append(DomainEvent(name=event_name, emitted_by=f.qualified_name))
|
|
85
|
+
return events
|
|
96
86
|
|
|
97
|
-
|
|
87
|
+
|
|
88
|
+
def _find_handlers(events: List[DomainEvent], modules: List[ModuleIR]) -> None:
|
|
89
|
+
"""Krok 2: dopasuj handlery do zdarzeń (mutuje events in-place)."""
|
|
98
90
|
for mod in modules:
|
|
99
91
|
for f in mod.functions:
|
|
100
92
|
if _EVENT_HANDLER_PATTERNS.search(f.name):
|
|
101
|
-
|
|
102
|
-
for ev in model.events:
|
|
93
|
+
for ev in events:
|
|
103
94
|
keyword = ev.name.lower().replace("event", "").strip()
|
|
104
95
|
if keyword and keyword in f.name.lower():
|
|
105
96
|
ev.handled_by.append(f.qualified_name)
|
|
106
97
|
|
|
107
|
-
|
|
98
|
+
|
|
99
|
+
def _find_command_handlers(modules: List[ModuleIR]) -> List[CommandHandler]:
|
|
100
|
+
"""Krok 3: znajdź command handlery i ich emitowane zdarzenia."""
|
|
101
|
+
commands: List[CommandHandler] = []
|
|
108
102
|
for mod in modules:
|
|
109
103
|
for f in mod.functions:
|
|
110
104
|
if f.role == CQRSRole.COMMAND or _AGGREGATE_PATTERNS.search(f.name):
|
|
@@ -114,24 +108,36 @@ def infer_event_model(modules: List[ModuleIR]) -> EventModel:
|
|
|
114
108
|
if _EVENT_EMIT_PATTERNS.search(c)
|
|
115
109
|
]
|
|
116
110
|
if emits or f.role == CQRSRole.COMMAND:
|
|
117
|
-
|
|
111
|
+
commands.append(
|
|
118
112
|
CommandHandler(
|
|
119
113
|
name=f.qualified_name,
|
|
120
114
|
command=f.name,
|
|
121
115
|
emits=emits,
|
|
122
116
|
)
|
|
123
117
|
)
|
|
118
|
+
return commands
|
|
119
|
+
|
|
124
120
|
|
|
125
|
-
|
|
121
|
+
def _find_aggregates(modules: List[ModuleIR]) -> List[str]:
|
|
122
|
+
"""Krok 4: znajdź moduły będące agregatami (CRUD score >= 2)."""
|
|
123
|
+
aggregates: List[str] = []
|
|
126
124
|
for mod in modules:
|
|
127
125
|
crud_score = sum(
|
|
128
126
|
1 for f in mod.functions
|
|
129
127
|
if _AGGREGATE_PATTERNS.search(f.name)
|
|
130
128
|
)
|
|
131
129
|
if crud_score >= 2:
|
|
132
|
-
|
|
130
|
+
aggregates.append(mod.name)
|
|
131
|
+
return aggregates
|
|
133
132
|
|
|
134
|
-
|
|
133
|
+
|
|
134
|
+
def infer_event_model(modules: List[ModuleIR]) -> EventModel:
|
|
135
|
+
"""Przechodzi po IR i buduje model zdarzeń."""
|
|
136
|
+
events = _find_emitters(modules)
|
|
137
|
+
_find_handlers(events, modules)
|
|
138
|
+
commands = _find_command_handlers(modules)
|
|
139
|
+
aggregates = _find_aggregates(modules)
|
|
140
|
+
return EventModel(commands=commands, events=events, aggregates=aggregates)
|
|
135
141
|
|
|
136
142
|
|
|
137
143
|
def _derive_event_name(func_name: str) -> str:
|
|
@@ -20,22 +20,28 @@ from code2schema.codegen.visualizer import write_html
|
|
|
20
20
|
from code2schema.core.extractor import extract_project
|
|
21
21
|
|
|
22
22
|
|
|
23
|
+
_SPECIAL_PROJECT_DIRS = {"backend", "frontend", "src", "app", "api"}
|
|
24
|
+
_GENERIC_PATH_PARTS = {"home", "github", "workspace", "projects", "src"}
|
|
25
|
+
|
|
26
|
+
|
|
23
27
|
def _project_name_from_path(path: Path) -> str:
|
|
24
28
|
"""Extract project name from path (e.g., /path/to/c2004/backend -> c2004)."""
|
|
25
29
|
# Try to find a meaningful name from the path
|
|
26
30
|
parts = path.parts
|
|
27
31
|
for i, part in enumerate(reversed(parts)):
|
|
28
|
-
if part in
|
|
32
|
+
if part in _SPECIAL_PROJECT_DIRS:
|
|
29
33
|
# Use parent directory name
|
|
30
34
|
if i < len(parts) - 1:
|
|
31
35
|
return parts[-(i + 2)]
|
|
32
36
|
# Skip common generic names
|
|
33
|
-
if part not in
|
|
37
|
+
if part not in _GENERIC_PATH_PARTS:
|
|
34
38
|
return part
|
|
35
39
|
return path.name or "project"
|
|
36
40
|
|
|
37
41
|
|
|
38
|
-
def
|
|
42
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
43
|
+
"""Build CLI argument parser."""
|
|
44
|
+
from code2schema import __version__
|
|
39
45
|
parser = argparse.ArgumentParser(prog="code2schema",
|
|
40
46
|
description="Semantic Compiler: Code → CQRS → Schema / Proto / Graph")
|
|
41
47
|
parser.add_argument("path")
|
|
@@ -54,41 +60,65 @@ def main(argv=None):
|
|
|
54
60
|
parser.add_argument("--no-rules", action="store_true")
|
|
55
61
|
parser.add_argument("--exclude", nargs="*", default=[])
|
|
56
62
|
parser.add_argument("-q", "--quiet", action="store_true")
|
|
57
|
-
|
|
63
|
+
parser.add_argument("-V", "--version", action="version",
|
|
64
|
+
version=f"%(prog)s {__version__}")
|
|
65
|
+
return parser
|
|
58
66
|
|
|
59
|
-
root = Path(args.path)
|
|
60
|
-
if not root.exists():
|
|
61
|
-
print(f"ERROR: {root}", file=sys.stderr)
|
|
62
|
-
return 1
|
|
63
67
|
|
|
64
|
-
|
|
68
|
+
def _resolve_output_dir(root: Path) -> Path:
|
|
69
|
+
if not root.is_dir():
|
|
70
|
+
return root.parent
|
|
71
|
+
if root.name in _SPECIAL_PROJECT_DIRS:
|
|
72
|
+
return root.parent
|
|
73
|
+
return root
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _resolve_required_path(out_dir: Path, value: str | None, default_name: str) -> Path:
|
|
77
|
+
return out_dir / (value or default_name)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _resolve_optional_path(
|
|
81
|
+
out_dir: Path,
|
|
82
|
+
value: str | bool | None,
|
|
83
|
+
default_name: str,
|
|
84
|
+
) -> Path | None:
|
|
85
|
+
if isinstance(value, str):
|
|
86
|
+
return out_dir / value
|
|
87
|
+
if value is True:
|
|
88
|
+
return out_dir / default_name
|
|
89
|
+
return None
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _resolve_paths(
|
|
93
|
+
args: argparse.Namespace,
|
|
94
|
+
) -> tuple[Path, Path, Path | None, Path | None, Path | None]:
|
|
95
|
+
"""Resolve root, project name and output file paths from CLI args."""
|
|
96
|
+
root = Path(args.path)
|
|
65
97
|
proj_name = _project_name_from_path(root)
|
|
66
|
-
|
|
67
|
-
if root.is_dir() and root.name in ("backend", "frontend", "src", "app", "api"):
|
|
68
|
-
out_dir = root.parent
|
|
69
|
-
else:
|
|
70
|
-
out_dir = root if root.is_dir() else root.parent
|
|
98
|
+
out_dir = _resolve_output_dir(root)
|
|
71
99
|
|
|
72
|
-
out_path = (out_dir
|
|
73
|
-
proto_path = out_dir
|
|
74
|
-
md_path = out_dir
|
|
75
|
-
html_path = out_dir
|
|
100
|
+
out_path = _resolve_required_path(out_dir, args.out, f"{proj_name}_schema.json")
|
|
101
|
+
proto_path = _resolve_optional_path(out_dir, args.proto, f"{proj_name}_api.proto")
|
|
102
|
+
md_path = _resolve_optional_path(out_dir, args.md, f"{proj_name}_report.md")
|
|
103
|
+
html_path = _resolve_optional_path(out_dir, args.html, f"{proj_name}_viz.html")
|
|
104
|
+
return root, out_path, proto_path, md_path, html_path
|
|
76
105
|
|
|
77
|
-
t0 = time.perf_counter()
|
|
78
|
-
if not args.quiet:
|
|
79
|
-
print(f"⏳ Parsing: {root}")
|
|
80
106
|
|
|
107
|
+
def _run_extraction(args, root):
|
|
108
|
+
"""Parse project and run CQRS analysis. Returns (modules, schema, G) or None on failure."""
|
|
81
109
|
modules = extract_project(root, exclude=args.exclude or None)
|
|
82
110
|
if not modules:
|
|
83
111
|
print("ERROR: Brak plików .py.", file=sys.stderr)
|
|
84
|
-
return
|
|
85
|
-
|
|
112
|
+
return None
|
|
86
113
|
schema = analyze(modules)
|
|
87
114
|
if args.no_rules:
|
|
88
115
|
schema.rules = []
|
|
89
|
-
|
|
90
116
|
G = build_rich_graph(schema)
|
|
117
|
+
return modules, schema, G
|
|
118
|
+
|
|
91
119
|
|
|
120
|
+
def _run_reports(args, modules, schema, G):
|
|
121
|
+
"""Print optional reports: cycles, graph summary, events."""
|
|
92
122
|
if args.cycles:
|
|
93
123
|
cycles = detect_cycles(G)
|
|
94
124
|
if cycles:
|
|
@@ -107,6 +137,9 @@ def main(argv=None):
|
|
|
107
137
|
print("\n── Event Model ────────────────────────")
|
|
108
138
|
print(em.summary())
|
|
109
139
|
|
|
140
|
+
|
|
141
|
+
def _write_outputs(args, schema, G, out_path, proto_path, md_path, html_path):
|
|
142
|
+
"""Write all output files (JSON, proto, md, html, graphml, dot)."""
|
|
110
143
|
write_json(schema, out_path)
|
|
111
144
|
if proto_path:
|
|
112
145
|
write_proto(schema, proto_path)
|
|
@@ -119,27 +152,54 @@ def main(argv=None):
|
|
|
119
152
|
if args.dot:
|
|
120
153
|
write_dot(G, Path(args.dot))
|
|
121
154
|
|
|
155
|
+
|
|
156
|
+
def _print_summary(modules, schema, G, t0, out_path, proto_path, md_path, html_path):
|
|
157
|
+
"""Print final summary with metrics and output file names."""
|
|
158
|
+
funcs = schema.all_functions()
|
|
159
|
+
outputs = [f" → {out_path.name}"]
|
|
160
|
+
if proto_path:
|
|
161
|
+
outputs.append(f" → {proto_path.name}")
|
|
162
|
+
if md_path:
|
|
163
|
+
outputs.append(f" → {md_path.name}")
|
|
164
|
+
if html_path:
|
|
165
|
+
outputs.append(f" → {html_path.name}")
|
|
166
|
+
print(
|
|
167
|
+
f"\n✅ Gotowe ({time.perf_counter()-t0:.2f}s)\n"
|
|
168
|
+
f" Modules : {len(modules)}\n"
|
|
169
|
+
f" Functions: {len(funcs)}\n"
|
|
170
|
+
f" Queries : {len(schema.queries())}\n"
|
|
171
|
+
f" Commands : {len(schema.commands())}\n"
|
|
172
|
+
f" Orchest. : {len(schema.orchestrators())}\n"
|
|
173
|
+
f" Workflows: {len(schema.workflows)}\n"
|
|
174
|
+
f" Rules : {len(schema.rules)}\n"
|
|
175
|
+
f" Graph : {G.number_of_nodes()}N / {G.number_of_edges()}E\n"
|
|
176
|
+
+ "\n".join(outputs)
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def main(argv=None):
|
|
181
|
+
parser = _build_parser()
|
|
182
|
+
args = parser.parse_args(argv)
|
|
183
|
+
|
|
184
|
+
root, out_path, proto_path, md_path, html_path = _resolve_paths(args)
|
|
185
|
+
if not root.exists():
|
|
186
|
+
print(f"ERROR: {root}", file=sys.stderr)
|
|
187
|
+
return 1
|
|
188
|
+
|
|
189
|
+
t0 = time.perf_counter()
|
|
190
|
+
if not args.quiet:
|
|
191
|
+
print(f"⏳ Parsing: {root}")
|
|
192
|
+
|
|
193
|
+
result = _run_extraction(args, root)
|
|
194
|
+
if result is None:
|
|
195
|
+
return 1
|
|
196
|
+
modules, schema, G = result
|
|
197
|
+
|
|
198
|
+
_run_reports(args, modules, schema, G)
|
|
199
|
+
_write_outputs(args, schema, G, out_path, proto_path, md_path, html_path)
|
|
200
|
+
|
|
122
201
|
if not args.quiet:
|
|
123
|
-
|
|
124
|
-
outputs = [f" → {out_path.name}"]
|
|
125
|
-
if proto_path:
|
|
126
|
-
outputs.append(f" → {proto_path.name}")
|
|
127
|
-
if md_path:
|
|
128
|
-
outputs.append(f" → {md_path.name}")
|
|
129
|
-
if html_path:
|
|
130
|
-
outputs.append(f" → {html_path.name}")
|
|
131
|
-
print(
|
|
132
|
-
f"\n✅ Gotowe ({time.perf_counter()-t0:.2f}s)\n"
|
|
133
|
-
f" Modules : {len(modules)}\n"
|
|
134
|
-
f" Functions: {len(funcs)}\n"
|
|
135
|
-
f" Queries : {len(schema.queries())}\n"
|
|
136
|
-
f" Commands : {len(schema.commands())}\n"
|
|
137
|
-
f" Orchest. : {len(schema.orchestrators())}\n"
|
|
138
|
-
f" Workflows: {len(schema.workflows)}\n"
|
|
139
|
-
f" Rules : {len(schema.rules)}\n"
|
|
140
|
-
f" Graph : {G.number_of_nodes()}N / {G.number_of_edges()}E\n"
|
|
141
|
-
+ "\n".join(outputs)
|
|
142
|
-
)
|
|
202
|
+
_print_summary(modules, schema, G, t0, out_path, proto_path, md_path, html_path)
|
|
143
203
|
return 0
|
|
144
204
|
|
|
145
205
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code2schema
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: Semantic compiler: Code → AST → CQRS Model → Workflow DAG → Proto/Schema
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Keywords: ast,cqrs,static-analysis,code-quality,schema
|
|
@@ -34,13 +34,13 @@ Dynamic: license-file
|
|
|
34
34
|
|
|
35
35
|
## AI Cost Tracking
|
|
36
36
|
|
|
37
|
-
    
|
|
38
|
+
  
|
|
39
39
|
|
|
40
|
-
- 🤖 **LLM usage:** $0.
|
|
41
|
-
- 👤 **Human dev:** ~$
|
|
40
|
+
- 🤖 **LLM usage:** $0.4500 (3 commits)
|
|
41
|
+
- 👤 **Human dev:** ~$350 (3.5h @ $100/h, 30min dedup)
|
|
42
42
|
|
|
43
|
-
Generated on 2026-05-
|
|
43
|
+
Generated on 2026-05-07 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
|
|
44
44
|
|
|
45
45
|
---
|
|
46
46
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Testy jednostkowe code2schema."""
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
|
+
import argparse
|
|
4
5
|
import ast
|
|
5
6
|
import textwrap
|
|
6
7
|
from pathlib import Path
|
|
@@ -10,6 +11,7 @@ import pytest
|
|
|
10
11
|
from code2schema.core.models import CQRSRole, SideEffect
|
|
11
12
|
from code2schema.core.extractor import extract_module
|
|
12
13
|
from code2schema.analyzer.cqrs import _infer_role, analyze, build_call_graph
|
|
14
|
+
from code2schema.cli import _resolve_paths
|
|
13
15
|
from code2schema.codegen import to_json, to_proto, to_markdown
|
|
14
16
|
|
|
15
17
|
|
|
@@ -216,3 +218,48 @@ def test_event_model_summary(sample_module):
|
|
|
216
218
|
summary = em.summary()
|
|
217
219
|
assert "Commands" in summary
|
|
218
220
|
assert "Domain Events" in summary
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
# ── CLI Paths ─────────────────────────────────────────────────────────────────
|
|
224
|
+
|
|
225
|
+
def test_resolve_paths_for_special_project_dir(tmp_path: Path):
|
|
226
|
+
backend_dir = tmp_path / "c2004" / "backend"
|
|
227
|
+
backend_dir.mkdir(parents=True)
|
|
228
|
+
|
|
229
|
+
args = argparse.Namespace(
|
|
230
|
+
path=str(backend_dir),
|
|
231
|
+
out=None,
|
|
232
|
+
proto=True,
|
|
233
|
+
md=True,
|
|
234
|
+
html=True,
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
root, out_path, proto_path, md_path, html_path = _resolve_paths(args)
|
|
238
|
+
|
|
239
|
+
assert root == backend_dir
|
|
240
|
+
assert out_path == backend_dir.parent / "c2004_schema.json"
|
|
241
|
+
assert proto_path == backend_dir.parent / "c2004_api.proto"
|
|
242
|
+
assert md_path == backend_dir.parent / "c2004_report.md"
|
|
243
|
+
assert html_path == backend_dir.parent / "c2004_viz.html"
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def test_resolve_paths_for_file_input_with_custom_outputs(tmp_path: Path):
|
|
247
|
+
file_path = tmp_path / "repo" / "main.py"
|
|
248
|
+
file_path.parent.mkdir(parents=True)
|
|
249
|
+
file_path.write_text("def main():\n pass\n")
|
|
250
|
+
|
|
251
|
+
args = argparse.Namespace(
|
|
252
|
+
path=str(file_path),
|
|
253
|
+
out="schema.json",
|
|
254
|
+
proto="api.proto",
|
|
255
|
+
md=None,
|
|
256
|
+
html=None,
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
root, out_path, proto_path, md_path, html_path = _resolve_paths(args)
|
|
260
|
+
|
|
261
|
+
assert root == file_path
|
|
262
|
+
assert out_path == file_path.parent / "schema.json"
|
|
263
|
+
assert proto_path == file_path.parent / "api.proto"
|
|
264
|
+
assert md_path is None
|
|
265
|
+
assert html_path is None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|