5252FixtureRequest = pytest .FixtureRequest
5353
5454
55+ def assert_run_main_with_args_error (args : list [str ], capsys : pytest .CaptureFixture [str ], expected_error : str ) -> None :
56+ """Assert that running the CLI exits with code 2 and emits the expected error."""
57+ with pytest .raises (SystemExit ) as exc_info :
58+ run_main_with_args (args )
59+ assert exc_info .value .code == 2
60+ captured = capsys .readouterr ()
61+ assert expected_error in captured .err
62+
63+
5564def _install_test_my_app (base_dir : Path , monkeypatch : pytest .MonkeyPatch ) -> None :
5665 package_dir = base_dir / "my_app"
5766 package_dir .mkdir ()
@@ -2981,6 +2990,8 @@ def test_main_jsonschema_custom_base_path(output_file: Path) -> None:
29812990- Single: `{"Person": "custom.bases.PersonBase"}`
29822991- Multiple: `{"User": ["mixins.AuditMixin", "mixins.TimestampMixin"]}`
29832992
2993+ You can pass the mapping either inline as JSON or as a path to a JSON file.
2994+
29842995When using multiple base classes, the specified classes are used directly without
29852996adding `BaseModel`. Ensure your mixins inherit from `BaseModel` if needed.""" ,
29862997 input_schema = "jsonschema/base_class_map.json" ,
@@ -3010,6 +3021,87 @@ def test_main_jsonschema_base_class_map(output_file: Path) -> None:
30103021 )
30113022
30123023
3024+ def test_main_jsonschema_base_class_map_from_file (output_file : Path , tmp_path : Path ) -> None :
3025+ """Test base_class_map loaded from a JSON file."""
3026+ mapping_path = tmp_path / "base_class_map.json"
3027+ mapping_path .write_text (
3028+ json .dumps ({"Person" : "custom.bases.PersonBase" , "Animal" : "custom.bases.AnimalBase" }),
3029+ encoding = "utf-8" ,
3030+ )
3031+ run_main_and_assert (
3032+ input_path = JSON_SCHEMA_DATA_PATH / "base_class_map.json" ,
3033+ output_path = output_file ,
3034+ input_file_type = "jsonschema" ,
3035+ assert_func = assert_file_content ,
3036+ expected_file = "base_class_map.py" ,
3037+ extra_args = ["--base-class-map" , str (mapping_path )],
3038+ )
3039+
3040+
3041+ def test_main_jsonschema_base_class_map_from_file_invalid_json (
3042+ tmp_path : Path , capsys : pytest .CaptureFixture [str ]
3043+ ) -> None :
3044+ """Test invalid JSON file passed to --base-class-map."""
3045+ mapping_path = tmp_path / "base_class_map.json"
3046+ mapping_path .write_text ("{invalid json}" , encoding = "utf-8" )
3047+ assert_run_main_with_args_error (
3048+ [
3049+ "--input" ,
3050+ str (JSON_SCHEMA_DATA_PATH / "base_class_map.json" ),
3051+ "--output" ,
3052+ str (tmp_path / "output.py" ),
3053+ "--input-file-type" ,
3054+ "jsonschema" ,
3055+ "--base-class-map" ,
3056+ str (mapping_path ),
3057+ ],
3058+ capsys ,
3059+ "Invalid JSON:" ,
3060+ )
3061+
3062+
3063+ def test_main_jsonschema_base_class_map_from_file_invalid_encoding (
3064+ tmp_path : Path , capsys : pytest .CaptureFixture [str ]
3065+ ) -> None :
3066+ """Test invalid-encoding JSON file passed to --base-class-map."""
3067+ mapping_path = tmp_path / "base_class_map.json"
3068+ mapping_path .write_bytes (b"\x80 " )
3069+ assert_run_main_with_args_error (
3070+ [
3071+ "--input" ,
3072+ str (JSON_SCHEMA_DATA_PATH / "base_class_map.json" ),
3073+ "--output" ,
3074+ str (tmp_path / "output.py" ),
3075+ "--input-file-type" ,
3076+ "jsonschema" ,
3077+ "--base-class-map" ,
3078+ str (mapping_path ),
3079+ ],
3080+ capsys ,
3081+ "Unable to read JSON file" ,
3082+ )
3083+
3084+
3085+ def test_main_jsonschema_base_class_map_inline_requires_json_object (
3086+ tmp_path : Path , capsys : pytest .CaptureFixture [str ]
3087+ ) -> None :
3088+ """Test non-object JSON passed to --base-class-map."""
3089+ assert_run_main_with_args_error (
3090+ [
3091+ "--input" ,
3092+ str (JSON_SCHEMA_DATA_PATH / "base_class_map.json" ),
3093+ "--output" ,
3094+ str (tmp_path / "output.py" ),
3095+ "--input-file-type" ,
3096+ "jsonschema" ,
3097+ "--base-class-map" ,
3098+ '["custom.bases.PersonBase"]' ,
3099+ ],
3100+ capsys ,
3101+ "Expected a JSON object" ,
3102+ )
3103+
3104+
30133105def test_main_jsonschema_custom_base_paths_list (output_file : Path ) -> None :
30143106 """Test customBasePath with list of base classes."""
30153107 run_main_and_assert (
@@ -4527,7 +4619,9 @@ def test_main_typed_dict_no_closed(output_file: Path) -> None:
45274619 option_description = """Override enum/literal generation per-field via JSON mapping.
45284620
45294621The `--enum-field-as-literal-map` option allows per-field control over whether
4530- to generate Literal types or Enum classes. Overrides `--enum-field-as-literal`.""" ,
4622+ to generate Literal types or Enum classes. Overrides `--enum-field-as-literal`.
4623+
4624+ You can pass the mapping either inline as JSON or as a path to a JSON file.""" ,
45314625 input_schema = "jsonschema/enum_field_as_literal_map.json" ,
45324626 cli_args = ["--enum-field-as-literal-map" , '{"status": "literal"}' ],
45334627 golden_output = "jsonschema/enum_field_as_literal_map.py" ,
@@ -4551,6 +4645,20 @@ def test_main_enum_field_as_literal_map(output_file: Path) -> None:
45514645 )
45524646
45534647
4648+ def test_main_enum_field_as_literal_map_from_file (output_file : Path , tmp_path : Path ) -> None :
4649+ """Test enum_field_as_literal_map loaded from a JSON file."""
4650+ mapping_path = tmp_path / "enum_field_as_literal_map.json"
4651+ mapping_path .write_text (json .dumps ({"status" : "literal" }), encoding = "utf-8" )
4652+ run_main_and_assert (
4653+ input_path = JSON_SCHEMA_DATA_PATH / "enum_field_as_literal_map.json" ,
4654+ output_path = output_file ,
4655+ input_file_type = None ,
4656+ assert_func = assert_file_content ,
4657+ expected_file = "enum_field_as_literal_map.py" ,
4658+ extra_args = ["--enum-field-as-literal-map" , str (mapping_path )],
4659+ )
4660+
4661+
45544662def test_main_enum_field_as_literal_map_override_global (output_file : Path ) -> None :
45554663 """Test --enum-field-as-literal-map overrides global --enum-field-as-literal."""
45564664 run_main_and_assert (
@@ -4568,6 +4676,62 @@ def test_main_enum_field_as_literal_map_override_global(output_file: Path) -> No
45684676 )
45694677
45704678
4679+ def test_main_enum_field_as_literal_map_invalid_json_file (tmp_path : Path , capsys : pytest .CaptureFixture [str ]) -> None :
4680+ """Test invalid JSON file passed to --enum-field-as-literal-map."""
4681+ mapping_path = tmp_path / "enum_field_as_literal_map.json"
4682+ mapping_path .write_text ("{invalid json}" , encoding = "utf-8" )
4683+ assert_run_main_with_args_error (
4684+ [
4685+ "--input" ,
4686+ str (JSON_SCHEMA_DATA_PATH / "enum_field_as_literal_map.json" ),
4687+ "--output" ,
4688+ str (tmp_path / "output.py" ),
4689+ "--enum-field-as-literal-map" ,
4690+ str (mapping_path ),
4691+ ],
4692+ capsys ,
4693+ "Invalid JSON:" ,
4694+ )
4695+
4696+
4697+ def test_main_enum_field_as_literal_map_invalid_encoding_json_file (
4698+ tmp_path : Path , capsys : pytest .CaptureFixture [str ]
4699+ ) -> None :
4700+ """Test invalid-encoding JSON file passed to --enum-field-as-literal-map."""
4701+ mapping_path = tmp_path / "enum_field_as_literal_map.json"
4702+ mapping_path .write_bytes (b"\x80 " )
4703+ assert_run_main_with_args_error (
4704+ [
4705+ "--input" ,
4706+ str (JSON_SCHEMA_DATA_PATH / "enum_field_as_literal_map.json" ),
4707+ "--output" ,
4708+ str (tmp_path / "output.py" ),
4709+ "--enum-field-as-literal-map" ,
4710+ str (mapping_path ),
4711+ ],
4712+ capsys ,
4713+ "Unable to read JSON file" ,
4714+ )
4715+
4716+
4717+ def test_main_enum_field_as_literal_map_inline_requires_json_object (
4718+ tmp_path : Path , capsys : pytest .CaptureFixture [str ]
4719+ ) -> None :
4720+ """Test non-object JSON passed to --enum-field-as-literal-map."""
4721+ assert_run_main_with_args_error (
4722+ [
4723+ "--input" ,
4724+ str (JSON_SCHEMA_DATA_PATH / "enum_field_as_literal_map.json" ),
4725+ "--output" ,
4726+ str (tmp_path / "output.py" ),
4727+ "--enum-field-as-literal-map" ,
4728+ '["literal"]' ,
4729+ ],
4730+ capsys ,
4731+ "Expected a JSON object" ,
4732+ )
4733+
4734+
45714735def test_main_x_enum_field_as_literal (output_file : Path ) -> None :
45724736 """Test x-enum-field-as-literal schema extension for per-field control."""
45734737 run_main_and_assert (
0 commit comments