diff --git a/joj3_config_generator/loader.py b/joj3_config_generator/loader.py index eff0c83..1678a31 100644 --- a/joj3_config_generator/loader.py +++ b/joj3_config_generator/loader.py @@ -5,7 +5,7 @@ from typing import Any, Dict, Tuple, Type, cast import inquirer import tomli import yaml -from pydantic import AliasChoices, BaseModel +from pydantic import AliasChoices, BaseModel, ValidationError from joj3_config_generator.models import answer, joj1, repo, task from joj3_config_generator.models.common import Memory, Time @@ -166,10 +166,22 @@ def load_joj3_toml( repo_obj = tomli.loads(repo_toml_path.read_text()) task_obj = tomli.loads(task_toml_path.read_text()) - repo_conf = repo.Config(**repo_obj) + try: + repo_conf = repo.Config(**repo_obj) + except ValidationError as e: + logger.error( + f"Error parsing {repo_toml_path}, most likely to be unknown fields, check the latest sample toml carefully:\n{e}" + ) + raise repo_conf.root = root_path repo_conf.path = repo_toml_path.relative_to(root_path) - task_conf = task.Config(**task_obj) + try: + task_conf = task.Config(**task_obj) + except ValidationError as e: + logger.error( + f"Error parsing {task_toml_path}, most likely to be unknown fields, check the latest sample toml carefully:\n{e}" + ) + raise task_conf.root = root_path task_conf.path = task_toml_path.relative_to(root_path) check_unnecessary_fields(repo.Config, repo_obj, repo_toml_path) diff --git a/joj3_config_generator/main.py b/joj3_config_generator/main.py index c1b65f4..107a3ce 100644 --- a/joj3_config_generator/main.py +++ b/joj3_config_generator/main.py @@ -94,6 +94,7 @@ def convert( """ app.pretty_exceptions_enable = False logger.info(f"Converting files in {root.absolute()}") + error_json_paths = [] for repo_toml_path in root.glob("**/repo.toml"): if not any(p != repo_toml_path for p in repo_toml_path.parent.glob("*.toml")): fallback_toml_path = repo_toml_path.parent / "conf.toml" @@ -109,7 +110,13 @@ def convert( logger.info( f"Converting {repo_toml_path} & {task_toml_path} to {result_json_path}" ) - repo_conf, task_conf = load_joj3_toml(root, repo_toml_path, task_toml_path) + try: + repo_conf, task_conf = load_joj3_toml( + root, repo_toml_path, task_toml_path + ) + except Exception: + error_json_paths.append(result_json_path) + continue result_model = convert_joj3_conf(repo_conf, task_conf) result_dict = result_model.model_dump( mode="json", by_alias=True, exclude_none=True @@ -117,3 +124,8 @@ def convert( with result_json_path.open("w", newline="") as result_file: json.dump(result_dict, result_file, ensure_ascii=False, indent=4) result_file.write("\n") + if error_json_paths: + logger.error( + f"Failed to convert {len(error_json_paths)} file(s): {', '.join(str(json_path) for json_path in error_json_paths)}. Check previous errors for details." + ) + raise typer.Exit(code=1) diff --git a/tests/convert/extra-field/repo.toml b/tests/convert/extra-field/repo.toml new file mode 100644 index 0000000..e69de29 diff --git a/tests/convert/extra-field/task.toml b/tests/convert/extra-field/task.toml new file mode 100644 index 0000000..c547a5d --- /dev/null +++ b/tests/convert/extra-field/task.toml @@ -0,0 +1,4 @@ +name = "extra-field" +extra-field = "extra-field value" +extra-dict.extra-field = "extra-dict.extra-field value" +limit.extra-field = "limit.extra-field value" diff --git a/tests/convert/test_convert_cases.py b/tests/convert/test_convert_cases.py index 0f9137b..284043a 100644 --- a/tests/convert/test_convert_cases.py +++ b/tests/convert/test_convert_cases.py @@ -1,3 +1,6 @@ +import pytest +from pydantic import ValidationError + from tests.convert.utils import load_case @@ -29,6 +32,11 @@ def test_empty() -> None: load_case("empty") +def test_extra_field() -> None: + with pytest.raises(ValidationError): + load_case("extra-field") + + def test_full() -> None: load_case("full")