Skip to content

Commit 5ff5894

Browse files
feat: Prepare For Multi-Command CLI Interface (#121)
* put current command into subfolder * update cli.py to new structure * remove unused imports * add module docstring * streamline command * update cli commands in README --------- Co-authored-by: konstantin <[email protected]>
1 parent 578eef1 commit 5ff5894

File tree

5 files changed

+85
-62
lines changed

5 files changed

+85
-62
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ ORDER BY sort_path;
208208
<details>
209209
<summary>Finde heraus, welche Zeilen in einem Prüfidentifikator zwischen zwei Versionen hinzukommen</summary>
210210
<br>
211-
211+
212212
```sql
213213
with fv2504 as (SELECT *
214214
FROM ahb_hierarchy_materialized
@@ -236,11 +236,11 @@ pip install fundamend[cli]
236236
```
237237
Kann ein CLI-Tool in der entsprechenden venv installiert werden, das einzelne MIG- und AHB-XML-Dateien in entsprechende JSONs konvertiert:
238238
```bash
239-
(myvenv): xml2json --xml-path path/to/mig.xml
239+
(myvenv): fundamend xml2json --xml-path path/to/mig.xml
240240
```
241241
erzeugt `path/to/mig.json`. Und
242242
```bash
243-
(myvenv): xml2json --xml-path path/to/my/directory
243+
(myvenv): fundamend xml2json --xml-path path/to/my/directory
244244
```
245245
konvertiert alle XML-Dateien im entsprechenden Verzeichnis.
246246

src/fundamend/cli.py

Lines changed: 4 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,20 @@
11
"""contains the entrypoint for the command line interface"""
22

3-
import json
4-
from pathlib import Path
5-
63
import typer
7-
from pydantic import RootModel
84
from rich.console import Console
9-
from typing_extensions import Annotated
105

11-
from fundamend import AhbReader, Anwendungshandbuch, MessageImplementationGuide, MigReader
6+
from fundamend.commands import app as commands_app
127

13-
app = typer.Typer(name="xml2json", help="Convert XML(s) by BDEW to JSON(s)")
8+
app = typer.Typer(name="fundamend", help="CLI tool to work with XML files by BDEW", no_args_is_help=True)
149
err_console = Console(stderr=True) # https://typer.tiangolo.com/tutorial/printing/#printing-to-standard-error
1510

1611

17-
def _convert_to_json_file(xml_file_path: Path) -> Path:
18-
"""converts the given XML file to a JSON file and returns the path of the latter"""
19-
if not xml_file_path.is_file():
20-
raise ValueError(f"The given path {xml_file_path.absolute()} is not a file")
21-
is_ahb = "ahb" in xml_file_path.stem.lower()
22-
is_mig = "mig" in xml_file_path.stem.lower()
23-
if is_ahb and is_mig:
24-
raise ValueError(f"Cannot detect if {xml_file_path} is an AHB or MIG")
25-
root_model: RootModel[Anwendungshandbuch] | RootModel[MessageImplementationGuide]
26-
if is_ahb:
27-
ahb_model = AhbReader(xml_file_path).read()
28-
root_model = RootModel[Anwendungshandbuch](ahb_model)
29-
elif is_mig:
30-
mig_model = MigReader(xml_file_path).read()
31-
root_model = RootModel[MessageImplementationGuide](mig_model)
32-
else:
33-
raise ValueError(f"Seems like {xml_file_path} is neither an AHB nor a MIG")
34-
out_dict = root_model.model_dump(mode="json")
35-
json_file_path = xml_file_path.with_suffix(".json")
36-
with open(json_file_path, encoding="utf-8", mode="w") as outfile:
37-
json.dump(out_dict, outfile, indent=True, ensure_ascii=False)
38-
print(f"Successfully converted {xml_file_path} file to JSON {json_file_path}")
39-
return json_file_path
40-
41-
42-
@app.command()
43-
def main(
44-
xml_path: Annotated[
45-
Path,
46-
typer.Option(
47-
exists=True,
48-
file_okay=True,
49-
dir_okay=True,
50-
writable=True,
51-
readable=True,
52-
resolve_path=True,
53-
),
54-
],
55-
) -> None:
56-
"""
57-
converts the xml file from xml_in_path to a json file next to the .xml
58-
"""
59-
assert xml_path.exists() # ensured by typer
60-
if xml_path.is_dir():
61-
for _xml_path in xml_path.rglob("*.xml"):
62-
_convert_to_json_file(_xml_path)
63-
else:
64-
_convert_to_json_file(xml_path)
12+
app.add_typer(commands_app)
6513

6614

6715
def cli() -> None:
6816
"""entry point of the script defined in pyproject.toml"""
69-
typer.run(main)
17+
typer.run(app)
7018

7119

7220
if __name__ == "__main__":

src/fundamend/commands/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
"""
2+
Contains the commands for the CLI.
3+
"""
4+
5+
import typer
6+
7+
from fundamend.commands.xml2json import app as xml2json_app
8+
9+
app = typer.Typer()
10+
11+
app.add_typer(xml2json_app)

src/fundamend/commands/xml2json.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
"""
2+
Contains the command to convert XML files to JSON files.
3+
"""
4+
5+
import json
6+
from pathlib import Path
7+
8+
import typer
9+
from pydantic import RootModel
10+
from typing_extensions import Annotated
11+
12+
from fundamend import AhbReader, Anwendungshandbuch, MessageImplementationGuide, MigReader
13+
14+
app = typer.Typer()
15+
16+
17+
def _convert_to_json_file(xml_file_path: Path) -> Path:
18+
"""converts the given XML file to a JSON file and returns the path of the latter"""
19+
if not xml_file_path.is_file():
20+
raise ValueError(f"The given path {xml_file_path.absolute()} is not a file")
21+
is_ahb = "ahb" in xml_file_path.stem.lower()
22+
is_mig = "mig" in xml_file_path.stem.lower()
23+
if is_ahb and is_mig:
24+
raise ValueError(f"Cannot detect if {xml_file_path} is an AHB or MIG")
25+
root_model: RootModel[Anwendungshandbuch] | RootModel[MessageImplementationGuide]
26+
if is_ahb:
27+
ahb_model = AhbReader(xml_file_path).read()
28+
root_model = RootModel[Anwendungshandbuch](ahb_model)
29+
elif is_mig:
30+
mig_model = MigReader(xml_file_path).read()
31+
root_model = RootModel[MessageImplementationGuide](mig_model)
32+
else:
33+
raise ValueError(f"Seems like {xml_file_path} is neither an AHB nor a MIG")
34+
out_dict = root_model.model_dump(mode="json")
35+
json_file_path = xml_file_path.with_suffix(".json")
36+
with open(json_file_path, encoding="utf-8", mode="w") as outfile:
37+
json.dump(out_dict, outfile, indent=True, ensure_ascii=False)
38+
print(f"Successfully converted {xml_file_path} file to JSON {json_file_path}")
39+
return json_file_path
40+
41+
42+
@app.command()
43+
def xml2json(
44+
xml_path: Annotated[
45+
Path,
46+
typer.Option(
47+
exists=True,
48+
file_okay=True,
49+
dir_okay=True,
50+
writable=True,
51+
readable=True,
52+
resolve_path=True,
53+
),
54+
],
55+
) -> None:
56+
"""
57+
converts the xml file from xml_in_path to a json file next to the .xml
58+
"""
59+
assert xml_path.exists() # ensured by typer
60+
if xml_path.is_dir():
61+
for _xml_path in xml_path.rglob("*.xml"):
62+
_convert_to_json_file(_xml_path)
63+
else:
64+
_convert_to_json_file(xml_path)

unittests/test_cli.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def test_cli_single_file_mig(tmp_path: Path) -> None:
2424
original_mig_file = Path(__file__).parent / "example_files" / "UTILTS_MIG_1.1c_Lesefassung_2023_12_12.xml"
2525
tmp_mig_path = tmp_path / "my_mig.xml"
2626
_copy_xml_file(original_mig_file, tmp_mig_path)
27-
result = runner.invoke(app, ["--xml-path", str(tmp_mig_path.absolute())])
27+
result = runner.invoke(app, ["xml2json", "--xml-path", str(tmp_mig_path.absolute())])
2828
assert result.exit_code == 0
2929
assert (tmp_path / "my_mig.json").exists()
3030

@@ -35,7 +35,7 @@ def test_cli_single_file_ahb(tmp_path: Path) -> None:
3535
original_ahb_file = Path(__file__).parent / "example_files" / "UTILTS_AHB_1.1d_Konsultationsfassung_2024_04_02.xml"
3636
tmp_ahb_path = tmp_path / "my_ahb.xml"
3737
_copy_xml_file(original_ahb_file, tmp_ahb_path)
38-
result = runner.invoke(app, ["--xml-path", str(tmp_ahb_path)])
38+
result = runner.invoke(app, ["xml2json", "--xml-path", str(tmp_ahb_path.absolute())])
3939
assert result.exit_code == 0
4040
assert (tmp_path / "my_ahb.json").exists()
4141

@@ -49,7 +49,7 @@ def test_cli_directory(tmp_path: Path) -> None:
4949
tmp_ahb_path = tmp_path / "my_ahb.xml"
5050
_copy_xml_file(original_ahb_file, tmp_ahb_path)
5151
_copy_xml_file(original_mig_file, tmp_mig_path)
52-
result = runner.invoke(app, ["--xml-path", str(tmp_path)])
52+
result = runner.invoke(app, ["xml2json", "--xml-path", str(tmp_path.absolute())])
5353
assert result.exit_code == 0
5454
assert (tmp_path / "my_mig.json").exists()
5555
assert (tmp_path / "my_ahb.json").exists()

0 commit comments

Comments
 (0)