Martin Melka commited on
Commit
be25dfa
·
unverified ·
1 Parent(s): 27106b0

Fix nesting when making OpenAPI arrays and objects optional (#1178)

Browse files
src/fastmcp/utilities/openapi.py CHANGED
@@ -1114,10 +1114,56 @@ def _make_optional_parameter_nullable(schema: dict[str, Any]) -> dict[str, Any]:
1114
  # Create a new schema that allows null in addition to the original type
1115
  if "type" in schema:
1116
  original_type = schema["type"]
 
1117
  if isinstance(original_type, str):
1118
  # Single type - make it a union with null
1119
  nullable_schema = schema.copy()
1120
- nullable_schema["anyOf"] = [{"type": original_type}, {"type": "null"}]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1121
  # Remove the original type since we're using anyOf
1122
  del nullable_schema["type"]
1123
  return nullable_schema
 
1114
  # Create a new schema that allows null in addition to the original type
1115
  if "type" in schema:
1116
  original_type = schema["type"]
1117
+
1118
  if isinstance(original_type, str):
1119
  # Single type - make it a union with null
1120
  nullable_schema = schema.copy()
1121
+
1122
+ nested_non_nullable_schema = {
1123
+ "type": original_type,
1124
+ }
1125
+
1126
+ # If the original type is an array, move the array-specific properties into the now-nested schema
1127
+ # https://json-schema.org/understanding-json-schema/reference/array
1128
+ if original_type == "array":
1129
+ for array_property in [
1130
+ "items",
1131
+ "prefixItems",
1132
+ "unevaluatedItems",
1133
+ "contains",
1134
+ "minContains",
1135
+ "maxContains",
1136
+ "minItems",
1137
+ "maxItems",
1138
+ "uniqueItems",
1139
+ ]:
1140
+ if array_property in nullable_schema:
1141
+ nested_non_nullable_schema[array_property] = nullable_schema[
1142
+ array_property
1143
+ ]
1144
+ del nullable_schema[array_property]
1145
+
1146
+ # If the original type is an object, move the object-specific properties into the now-nested schema
1147
+ # https://json-schema.org/understanding-json-schema/reference/object
1148
+ elif original_type == "object":
1149
+ for object_property in [
1150
+ "properties",
1151
+ "patternProperties",
1152
+ "additionalProperties",
1153
+ "unevaluatedProperties",
1154
+ "required",
1155
+ "propertyNames",
1156
+ "minProperties",
1157
+ "maxProperties",
1158
+ ]:
1159
+ if object_property in nullable_schema:
1160
+ nested_non_nullable_schema[object_property] = nullable_schema[
1161
+ object_property
1162
+ ]
1163
+ del nullable_schema[object_property]
1164
+
1165
+ nullable_schema["anyOf"] = [nested_non_nullable_schema, {"type": "null"}]
1166
+
1167
  # Remove the original type since we're using anyOf
1168
  del nullable_schema["type"]
1169
  return nullable_schema
tests/server/openapi/test_optional_parameters.py CHANGED
@@ -95,8 +95,6 @@ async def test_optional_parameter_allows_null_for_type(param_schema):
95
  # Should have anyOf with the original type and null
96
  assert "anyOf" in optional_param_schema
97
  assert {"type": "null"} in optional_param_schema["anyOf"]
98
- # Check that original schema is preserved (either simple type or complex schema)
99
- if "type" in param_schema:
100
- assert {"type": param_schema["type"]} in optional_param_schema["anyOf"]
101
- else:
102
- assert param_schema in optional_param_schema["anyOf"]
 
95
  # Should have anyOf with the original type and null
96
  assert "anyOf" in optional_param_schema
97
  assert {"type": "null"} in optional_param_schema["anyOf"]
98
+
99
+ # Check that original schema is fully preserved under anyOf
100
+ assert param_schema in optional_param_schema["anyOf"]