Expand empty parameter filtering and add tests

Builds on PR #1128 by adding comprehensive filtering at parameter selection stage and test coverage for empty arrays/dicts.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Jeremiah Lowin 2025-07-12 09:25:05 -04:00
commit b853bb85f9
2 changed files with 166 additions and 8 deletions

View file

@ -344,18 +344,28 @@ class OpenAPITool(Tool):
suffixed_name = f"{p.name}__{p.location}"
param_value = None
suffixed_value = arguments.get(suffixed_name)
if (
suffixed_name in arguments
and arguments.get(suffixed_name) is not None
and arguments.get(suffixed_name) != ""
and suffixed_value is not None
and suffixed_value != ""
and not (
isinstance(suffixed_value, list | dict)
and len(suffixed_value) == 0
)
):
param_value = arguments[suffixed_name]
elif (
p.name in arguments
and arguments.get(p.name) is not None
and arguments.get(p.name) != ""
):
param_value = arguments[p.name]
else:
name_value = arguments.get(p.name)
if (
p.name in arguments
and name_value is not None
and name_value != ""
and not (
isinstance(name_value, list | dict) and len(name_value) == 0
)
):
param_value = arguments[p.name]
if param_value is not None:
# Handle different parameter styles and types

View file

@ -448,6 +448,154 @@ async def test_array_query_parameter_exploded_format(mock_client):
)
async def test_empty_array_parameter_exclusion(mock_client):
"""Test that empty array parameters are excluded from requests."""
# Create a route with array query parameter
route = HTTPRoute(
path="/search",
method="GET",
operation_id="search-operation",
parameters=[
ParameterInfo(
name="tags",
location="query",
required=False,
schema={
"type": "array",
"items": {"type": "string"},
},
),
ParameterInfo(
name="categories",
location="query",
required=False,
schema={
"type": "array",
"items": {"type": "string"},
},
),
ParameterInfo(
name="limit",
location="query",
required=False,
schema={"type": "integer"},
),
],
)
# Create the tool
tool = OpenAPITool(
client=mock_client,
route=route,
name="search-operation",
description="Search operation",
parameters={},
)
# Test with empty array - should be excluded
await tool.run(
{
"tags": [], # Empty array should be excluded
"categories": ["tech", "news"], # Non-empty array should be included
"limit": 10, # Non-array param should be included
}
)
# Check that empty array is excluded, but others are included
mock_client.request.assert_called_with(
method="GET",
url="/search",
params={
"categories": ["tech", "news"], # Only non-empty array included
"limit": 10,
},
headers={},
json=None,
timeout=None,
)
async def test_empty_deep_object_parameter_exclusion(mock_client):
"""Test that empty dict parameters with deepObject style are excluded from requests."""
# Create a route with deepObject query parameter
route = HTTPRoute(
path="/filter",
method="GET",
operation_id="filter-operation",
parameters=[
ParameterInfo(
name="filters",
location="query",
required=False,
style="deepObject",
explode=True,
schema={
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"},
},
},
),
ParameterInfo(
name="options",
location="query",
required=False,
style="deepObject",
explode=True,
schema={
"type": "object",
"properties": {
"sort": {"type": "string"},
"order": {"type": "string"},
},
},
),
ParameterInfo(
name="page",
location="query",
required=False,
schema={"type": "integer"},
),
],
)
# Create the tool
tool = OpenAPITool(
client=mock_client,
route=route,
name="filter-operation",
description="Filter operation",
parameters={},
)
# Test with empty dict - should be excluded
await tool.run(
{
"filters": {}, # Empty dict should be excluded
"options": {
"sort": "name",
"order": "asc",
}, # Non-empty dict should be included
"page": 1, # Non-dict param should be included
}
)
# Check that empty dict is excluded, but others are included
mock_client.request.assert_called_with(
method="GET",
url="/filter",
params={
"options[sort]": "name", # Deep object style for non-empty dict
"options[order]": "asc",
"page": 1,
},
headers={},
json=None,
timeout=None,
)
def test_parameter_location_enum_handling():
"""Test that ParameterLocation enum values are handled correctly (issue #950)."""
from enum import Enum