@@ -48,6 +48,24 @@ public abstract class AbstractPythonPydanticV1Codegen extends DefaultCodegen imp
4848
4949 public static final String MAP_NUMBER_TO = "mapNumberTo" ;
5050
51+ /**
52+ * Names which should never be treated as model imports for Python.
53+ * <p>
54+ * These can leak into {@code CodegenModel.imports} from generic container/import collection logic
55+ * (e.g. schema keywords like {@code array} or typing/builtin names), and then later get
56+ * incorrectly converted into model import statements.
57+ */
58+ private static final Set <String > PYTHON_NON_MODEL_IMPORTS = Collections .unmodifiableSet (new HashSet <>(
59+ Arrays .asList (
60+ // OpenAPI schema keywords (should never be imported)
61+ "array" , "map" , "set" , "object" ,
62+ // Python builtins
63+ "list" , "dict" , "tuple" , "set" , "type" ,
64+ // typing names (capitalized)
65+ "List" , "Dict" , "Tuple" , "Set" , "Type"
66+ )
67+ ));
68+
5169 protected String packageName = "openapi_client" ;
5270 @ Setter protected String packageVersion = "1.0.0" ;
5371 @ Setter protected String projectName ; // for setup.py, e.g. petstore-api
@@ -91,8 +109,6 @@ public AbstractPythonPydanticV1Codegen() {
91109 languageSpecificPrimitives .add ("float" );
92110 languageSpecificPrimitives .add ("list" );
93111 languageSpecificPrimitives .add ("dict" );
94- languageSpecificPrimitives .add ("List" );
95- languageSpecificPrimitives .add ("Dict" );
96112 languageSpecificPrimitives .add ("bool" );
97113 languageSpecificPrimitives .add ("str" );
98114 languageSpecificPrimitives .add ("datetime" );
@@ -136,6 +152,21 @@ public AbstractPythonPydanticV1Codegen() {
136152 regexModifiers .put ('x' , "VERBOSE" );
137153 }
138154
155+ @ Override
156+ protected boolean shouldAddImport (String type ) {
157+ if (type == null ) {
158+ return false ;
159+ }
160+ // Reject type expressions (e.g. list[str], dict[str, Foo]) and other non-symbol entries early.
161+ if (type .indexOf ('[' ) >= 0 || type .indexOf (']' ) >= 0 || type .indexOf ('<' ) >= 0 || type .indexOf ('>' ) >= 0 ) {
162+ return false ;
163+ }
164+ if (PYTHON_NON_MODEL_IMPORTS .contains (type )) {
165+ return false ;
166+ }
167+ return super .shouldAddImport (type );
168+ }
169+
139170 @ Override
140171 public void processOpts () {
141172 super .processOpts ();
@@ -843,7 +874,6 @@ private ModelsMap postProcessModelsMap(ModelsMap objs) {
843874 if (!model .oneOf .isEmpty ()) { // oneOfValidationError
844875 codegenProperties = model .getComposedSchemas ().getOneOf ();
845876 typingImports .add ("Any" );
846- typingImports .add ("List" );
847877 pydanticImports .add ("Field" );
848878 pydanticImports .add ("StrictStr" );
849879 pydanticImports .add ("ValidationError" );
@@ -879,7 +909,6 @@ private ModelsMap postProcessModelsMap(ModelsMap objs) {
879909 if (model .oneOf .isEmpty () && model .anyOf .isEmpty ()
880910 && !model .isEnum
881911 && !this .disallowAdditionalPropertiesIfNotPresent ) {
882- typingImports .add ("Dict" );
883912 typingImports .add ("Any" );
884913 }
885914
@@ -1070,8 +1099,7 @@ private String getPydanticType(CodegenParameter cp,
10701099 getPydanticType (cp .items , typingImports , pydanticImports , datetimeImports , modelImports , exampleImports , postponedModelImports , postponedExampleImports , classname ),
10711100 constraints );
10721101 } else if (cp .isMap ) {
1073- typingImports .add ("Dict" );
1074- return String .format (Locale .ROOT , "Dict[str, %s]" ,
1102+ return String .format (Locale .ROOT , "dict[str, %s]" ,
10751103 getPydanticType (cp .items , typingImports , pydanticImports , datetimeImports , modelImports , exampleImports , postponedModelImports , postponedExampleImports , classname ));
10761104 } else if (cp .isString ) {
10771105 if (cp .hasValidation ) {
@@ -1266,9 +1294,8 @@ private String getPydanticType(CodegenParameter cp,
12661294 } else if (cp .isUuid ) {
12671295 return cp .dataType ;
12681296 } else if (cp .isFreeFormObject ) { // type: object
1269- typingImports .add ("Dict" );
12701297 typingImports .add ("Any" );
1271- return "Dict [str, Any]" ;
1298+ return "dict [str, Any]" ;
12721299 } else if (!cp .isPrimitiveType ) {
12731300 // add model prefix
12741301 hasModelsToImport = true ;
@@ -1351,13 +1378,11 @@ private String getPydanticType(CodegenProperty cp,
13511378 constraints += ", unique_items=True" ;
13521379 }
13531380 pydanticImports .add ("conlist" );
1354- typingImports .add ("List" ); // for return type
13551381 return String .format (Locale .ROOT , "conlist(%s%s)" ,
13561382 getPydanticType (cp .items , typingImports , pydanticImports , datetimeImports , modelImports , exampleImports , postponedModelImports , postponedExampleImports , classname ),
13571383 constraints );
13581384 } else if (cp .isMap ) {
1359- typingImports .add ("Dict" );
1360- return String .format (Locale .ROOT , "Dict[str, %s]" , getPydanticType (cp .items , typingImports , pydanticImports , datetimeImports , modelImports , exampleImports , postponedModelImports , postponedExampleImports , classname ));
1385+ return String .format (Locale .ROOT , "dict[str, %s]" , getPydanticType (cp .items , typingImports , pydanticImports , datetimeImports , modelImports , exampleImports , postponedModelImports , postponedExampleImports , classname ));
13611386 } else if (cp .isString ) {
13621387 if (cp .hasValidation ) {
13631388 List <String > fieldCustomization = new ArrayList <>();
@@ -1550,9 +1575,8 @@ private String getPydanticType(CodegenProperty cp,
15501575 } else if (cp .isUuid ) {
15511576 return cp .dataType ;
15521577 } else if (cp .isFreeFormObject ) { // type: object
1553- typingImports .add ("Dict" );
15541578 typingImports .add ("Any" );
1555- return "Dict [str, Any]" ;
1579+ return "dict [str, Any]" ;
15561580 } else if (!cp .isPrimitiveType || cp .isModel ) { // model
15571581 // skip import if it's a circular reference
15581582 if (classname == null ) {
0 commit comments