-
-
Notifications
You must be signed in to change notification settings - Fork 55
Description
Description
Description
When configuring multiple fields in the in_fields
array within create_service_dependencies()
, only the last field in the array generates working filter providers. All previous fields fail to create proper CollectionFilter
instances due to a closure variable capture issue in the loop.
Environment
- advanced-alchemy version: 1.4.5
- Python version: 3.12
- Framework: Litestar
Expected Behavior
All fields specified in in_fields
should generate working filter providers that can be used via query parameters like fieldNameIn=value1,value2
.
Actual Behavior
Only the last field in the in_fields
array works correctly. Previous fields don't generate any CollectionFilter
instances in the filters list, causing the filtering to be ignored.
Reproduction Steps
- Configure a controller with multiple fields in
in_fields
:
dependencies = providers.create_service_dependencies(
MyService,
"my_service",
filters={
"in_fields": [
providers.FieldNameType("type", str),
providers.FieldNameType("status", str),
],
},
)
- Make a request with the first field filter:
GET /api/endpoint?typeIn=value
- Observe that no
CollectionFilter
is generated for thetype
field - Make a request with the last field filter:
GET /api/endpoint?statusIn=value
- Observe that
CollectionFilter
works correctly for thestatus
field
Root Cause Analysis
The issue is located in providers.py around lines 516-520:
for field_def in in_fields:
field_def = FieldNameType(name=field_def, type_hint=str) if isinstance(field_def, str) else field_def
def create_in_filter_provider(
field_name: FieldNameType,
) -> Callable[..., Optional[CollectionFilter[field_def.type_hint]]]: # ← Problem here
The closure captures the loop variable field_def
by reference, not by value. When the loop completes, all created functions reference the last value of field_def
, causing previous fields to malfunction.
Workaround
Currently using manual providers for additional fields:
def status_filter_provider(statusIn: list[str] | None = None) -> filters.CollectionFilter:
return filters.CollectionFilter(field_name="status", values=statusIn)
dependencies = providers.create_service_dependencies(
MyService,
"my_service",
filters={
"in_fields": [
providers.FieldNameType("type", str), # Only one field works
],
},
) | {
"status_filter": status_filter_provider, # Manual workaround
}
Suggested Fix
The closure should capture the loop variable by value, for example by passing it as a default parameter:
def create_in_filter_provider(
field_name: FieldNameType = field_def, # Capture by value
) -> Callable[..., Optional[CollectionFilter]]:
Or restructure the function creation to avoid the closure issue entirely.
Additional Notes
- The same issue likely affects
not_in_fields
configuration as well - Single field in
in_fields
works correctly - This is a classic Python closure gotcha that affects any loop creating functions with references to loop variables
URL to code causing the issue
No response
MCVE
# Your MCVE code here
Steps to reproduce
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
Screenshots
"In the format of: 
"
Logs
Package Version
advanced-alchemy version: 1.4.5
Platform
- Linux
- Mac
- Windows
- Other (Please specify in the description above)