@@ -530,6 +530,7 @@ def test_property_from_data_ref_enum_with_overridden_default(self, enum_property
530
530
prop , new_schemas = property_from_data (
531
531
name = name , required = required , data = data , schemas = schemas , parent_name = "" , config = config
532
532
)
533
+ new_schemas = attr .evolve (new_schemas , models_to_process = []) # intermediate state irrelevant to this test
533
534
534
535
assert prop == enum_property_factory (
535
536
name = "some_enum" ,
@@ -918,15 +919,18 @@ def test_retries_failing_models_while_making_progress(
918
919
919
920
first_model = model_property_factory ()
920
921
second_class_name = ClassName ("second" , "" )
922
+ second_model = model_property_factory ()
923
+ any_prop = any_property_factory ()
921
924
schemas = Schemas (
922
925
classes_by_name = {
923
926
ClassName ("first" , "" ): first_model ,
924
- second_class_name : model_property_factory (),
925
- ClassName ("non-model" , "" ): any_property_factory (),
926
- }
927
+ second_class_name : second_model ,
928
+ ClassName ("non-model" , "" ): any_prop ,
929
+ },
930
+ models_to_process = [first_model , second_model ],
927
931
)
928
932
process_model = mocker .patch (
929
- f"{ MODULE_NAME } .process_model" , side_effect = [PropertyError (), Schemas () , PropertyError ()]
933
+ f"{ MODULE_NAME } .process_model" , side_effect = [PropertyError (), schemas , PropertyError ()]
930
934
)
931
935
process_model_errors = mocker .patch (f"{ MODULE_NAME } ._process_model_errors" , return_value = ["error" ])
932
936
@@ -935,8 +939,8 @@ def test_retries_failing_models_while_making_progress(
935
939
process_model .assert_has_calls (
936
940
[
937
941
call (first_model , schemas = schemas , config = config ),
938
- call (schemas . classes_by_name [ second_class_name ] , schemas = schemas , config = config ),
939
- call (first_model , schemas = result , config = config ),
942
+ call (second_model , schemas = schemas , config = config ),
943
+ call (first_model , schemas = schemas , config = config ),
940
944
]
941
945
)
942
946
assert process_model_errors .was_called_once_with ([(first_model , PropertyError ())])
@@ -950,14 +954,16 @@ def test_detect_recursive_allof_reference_no_retry(self, mocker, model_property_
950
954
recursive_model = model_property_factory (
951
955
class_info = Class (name = class_name , module_name = PythonIdentifier ("module_name" , "" ))
952
956
)
957
+ second_model = model_property_factory ()
953
958
schemas = Schemas (
954
959
classes_by_name = {
955
960
"recursive" : recursive_model ,
956
- "second" : model_property_factory (),
957
- }
961
+ "second" : second_model ,
962
+ },
963
+ models_to_process = [recursive_model , second_model ],
958
964
)
959
965
recursion_error = PropertyError (data = Reference .model_construct (ref = f"#/{ class_name } " ))
960
- process_model = mocker .patch (f"{ MODULE_NAME } .process_model" , side_effect = [recursion_error , Schemas () ])
966
+ process_model = mocker .patch (f"{ MODULE_NAME } .process_model" , side_effect = [recursion_error , schemas ])
961
967
process_model_errors = mocker .patch (f"{ MODULE_NAME } ._process_model_errors" , return_value = ["error" ])
962
968
963
969
result = _process_models (schemas = schemas , config = config )
@@ -972,6 +978,58 @@ def test_detect_recursive_allof_reference_no_retry(self, mocker, model_property_
972
978
assert all (error in result .errors for error in process_model_errors .return_value )
973
979
assert "\n \n Recursive allOf reference found" in recursion_error .detail
974
980
981
+ def test_resolve_reference_to_single_allof_reference (self , config , model_property_factory ):
982
+ # test for https://github.com/openapi-generators/openapi-python-client/issues/1091
983
+ from openapi_python_client .parser .properties import Schemas , build_schemas
984
+
985
+ components = {
986
+ "Model1" : oai .Schema .model_construct (
987
+ type = "object" ,
988
+ properties = {
989
+ "prop1" : oai .Schema .model_construct (type = "string" ),
990
+ },
991
+ ),
992
+ "Model2" : oai .Schema .model_construct (
993
+ allOf = [
994
+ oai .Reference .model_construct (ref = "#/components/schemas/Model1" ),
995
+ ]
996
+ ),
997
+ "Model3" : oai .Schema .model_construct (
998
+ allOf = [
999
+ oai .Reference .model_construct (ref = "#/components/schemas/Model2" ),
1000
+ oai .Schema .model_construct (
1001
+ type = "object" ,
1002
+ properties = {
1003
+ "prop2" : oai .Schema .model_construct (type = "string" ),
1004
+ },
1005
+ ),
1006
+ ],
1007
+ ),
1008
+ }
1009
+ schemas = Schemas ()
1010
+
1011
+ result = build_schemas (components = components , schemas = schemas , config = config )
1012
+
1013
+ assert result .errors == []
1014
+ assert result .models_to_process == []
1015
+
1016
+ # Classes should only be generated for Model1 and Model3
1017
+ assert result .classes_by_name .keys () == {"Model1" , "Model3" }
1018
+
1019
+ # References to Model2 should be resolved to the same class as Model1
1020
+ assert result .classes_by_reference .keys () == {
1021
+ "/components/schemas/Model1" ,
1022
+ "/components/schemas/Model2" ,
1023
+ "/components/schemas/Model3" ,
1024
+ }
1025
+ assert (
1026
+ result .classes_by_reference ["/components/schemas/Model2" ].class_info
1027
+ == result .classes_by_reference ["/components/schemas/Model1" ].class_info
1028
+ )
1029
+
1030
+ # Verify that Model3 extended the properties from Model1
1031
+ assert [p .name for p in result .classes_by_name ["Model3" ].optional_properties ] == ["prop1" , "prop2" ]
1032
+
975
1033
976
1034
class TestPropogateRemoval :
977
1035
def test_propogate_removal_class_name (self ):
0 commit comments