chiliu chiliu commited on
Commit
0b67acf
·
unverified ·
1 Parent(s): e9db9c1

Optimize _make_optional_parameter_nullable and _adjust_union_types functions (#1321)

Browse files
Files changed (1) hide show
  1. src/fastmcp/utilities/openapi.py +42 -28
src/fastmcp/utilities/openapi.py CHANGED
@@ -1122,16 +1122,17 @@ def _make_optional_parameter_nullable(schema: dict[str, Any]) -> dict[str, Any]:
1122
 
1123
  if isinstance(original_type, str):
1124
  # Single type - make it a union with null
1125
- nullable_schema = schema.copy()
1126
-
1127
  nested_non_nullable_schema = {
1128
  "type": original_type,
1129
  }
 
1130
 
1131
- # If the original type is an array, move the array-specific properties into the now-nested schema
1132
- # https://json-schema.org/understanding-json-schema/reference/array
1133
  if original_type == "array":
1134
- for array_property in [
 
1135
  "items",
1136
  "prefixItems",
1137
  "unevaluatedItems",
@@ -1141,17 +1142,10 @@ def _make_optional_parameter_nullable(schema: dict[str, Any]) -> dict[str, Any]:
1141
  "minItems",
1142
  "maxItems",
1143
  "uniqueItems",
1144
- ]:
1145
- if array_property in nullable_schema:
1146
- nested_non_nullable_schema[array_property] = nullable_schema[
1147
- array_property
1148
- ]
1149
- del nullable_schema[array_property]
1150
-
1151
- # If the original type is an object, move the object-specific properties into the now-nested schema
1152
- # https://json-schema.org/understanding-json-schema/reference/object
1153
  elif original_type == "object":
1154
- for object_property in [
 
1155
  "properties",
1156
  "patternProperties",
1157
  "additionalProperties",
@@ -1160,17 +1154,18 @@ def _make_optional_parameter_nullable(schema: dict[str, Any]) -> dict[str, Any]:
1160
  "propertyNames",
1161
  "minProperties",
1162
  "maxProperties",
1163
- ]:
1164
- if object_property in nullable_schema:
1165
- nested_non_nullable_schema[object_property] = nullable_schema[
1166
- object_property
1167
- ]
1168
- del nullable_schema[object_property]
1169
 
1170
- nullable_schema["anyOf"] = [nested_non_nullable_schema, {"type": "null"}]
 
 
 
 
 
 
 
1171
 
1172
- # Remove the original type since we're using anyOf
1173
- del nullable_schema["type"]
1174
  return nullable_schema
1175
 
1176
  return schema
@@ -1394,12 +1389,31 @@ def _adjust_union_types(
1394
  ) -> dict[str, Any] | list[Any]:
1395
  """Recursively replace 'oneOf' with 'anyOf' in schema to handle overlapping unions."""
1396
  if isinstance(schema, dict):
1397
- # Work on a copy to avoid mutating the input
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1398
  result = schema.copy()
1399
- if "oneOf" in result:
1400
  result["anyOf"] = result.pop("oneOf")
1401
- for k, v in result.items():
1402
- result[k] = _adjust_union_types(v)
 
 
 
 
 
1403
  return result
1404
  elif isinstance(schema, list):
1405
  return [_adjust_union_types(item) for item in schema]
 
1122
 
1123
  if isinstance(original_type, str):
1124
  # Single type - make it a union with null
1125
+ # Optimize: avoid full schema copy by building directly
 
1126
  nested_non_nullable_schema = {
1127
  "type": original_type,
1128
  }
1129
+ nullable_schema = {}
1130
 
1131
+ # Define type-specific properties that should move to nested schema
1132
+ type_specific_properties = set()
1133
  if original_type == "array":
1134
+ # https://json-schema.org/understanding-json-schema/reference/array
1135
+ type_specific_properties = {
1136
  "items",
1137
  "prefixItems",
1138
  "unevaluatedItems",
 
1142
  "minItems",
1143
  "maxItems",
1144
  "uniqueItems",
1145
+ }
 
 
 
 
 
 
 
 
1146
  elif original_type == "object":
1147
+ # https://json-schema.org/understanding-json-schema/reference/object
1148
+ type_specific_properties = {
1149
  "properties",
1150
  "patternProperties",
1151
  "additionalProperties",
 
1154
  "propertyNames",
1155
  "minProperties",
1156
  "maxProperties",
1157
+ }
 
 
 
 
 
1158
 
1159
+ # Efficiently distribute properties without copying the entire schema
1160
+ for key, value in schema.items():
1161
+ if key == "type":
1162
+ continue # Already handled
1163
+ elif key in type_specific_properties:
1164
+ nested_non_nullable_schema[key] = value
1165
+ else:
1166
+ nullable_schema[key] = value
1167
 
1168
+ nullable_schema["anyOf"] = [nested_non_nullable_schema, {"type": "null"}]
 
1169
  return nullable_schema
1170
 
1171
  return schema
 
1389
  ) -> dict[str, Any] | list[Any]:
1390
  """Recursively replace 'oneOf' with 'anyOf' in schema to handle overlapping unions."""
1391
  if isinstance(schema, dict):
1392
+ # Optimize: only copy if we need to modify something
1393
+ has_one_of = "oneOf" in schema
1394
+ needs_recursive_processing = False
1395
+
1396
+ # Check if we need recursive processing
1397
+ for v in schema.values():
1398
+ if isinstance(v, dict | list):
1399
+ needs_recursive_processing = True
1400
+ break
1401
+
1402
+ # If nothing to change, return original
1403
+ if not has_one_of and not needs_recursive_processing:
1404
+ return schema
1405
+
1406
+ # Work on a copy only when modification is needed
1407
  result = schema.copy()
1408
+ if has_one_of:
1409
  result["anyOf"] = result.pop("oneOf")
1410
+
1411
+ # Only recurse where needed
1412
+ if needs_recursive_processing:
1413
+ for k, v in result.items():
1414
+ if isinstance(v, dict | list):
1415
+ result[k] = _adjust_union_types(v)
1416
+
1417
  return result
1418
  elif isinstance(schema, list):
1419
  return [_adjust_union_types(item) for item in schema]