Skip to content

clean_http_kwargs strips zero values (0, 0.0) from nested dicts due to 0 == False in Python #2492

@kasperiio

Description

@kasperiio

What happened?

The clean_http_kwargs function in appdaemon/utils.py incorrectly removes integer 0 and float 0.0 values from nested dictionaries when preparing HTTP requests. This is because it uses remove_literals(cleaned, (None, False)) and in Python, 0 == False and 0.0 == False both evaluate to True.

Steps to Reproduce:
`from appdaemon.utils import clean_http_kwargs
import json

test_data = {
'state': '0.08',
'attributes': {
'prices': {
'2025-11-29T00:00:00+02:00': {'price': 0.0, 'intervals': 4},
'2025-11-29T11:00:00+02:00': {'price': 0.08, 'intervals': 4}
}
}
}

result = clean_http_kwargs(test_data)
print(json.dumps(result, indent=2))`

Expected Result:
{ "state": "0.08", "attributes": { "prices": { "2025-11-29T00:00:00+02:00": {"price": 0.0, "intervals": 4}, "2025-11-29T11:00:00+02:00": {"price": 0.08, "intervals": 4} } } }

Actual Result:
{ "state": "0.08", "attributes": { "prices": { "2025-11-29T00:00:00+02:00": {"intervals": 4}, "2025-11-29T11:00:00+02:00": {"price": 0.08, "intervals": 4} } } }

The price key is completely missing from the first entry.

Version

4.5.12

Installation type

Docker container

Relevant log output

Relevant code in the app or config file that caused the issue

In appdaemon/utils.py, the remove_literals function (line ~1102) uses equality comparison:

`def remove_literals(val: Any, literal: Sequence[Any]) -> Any:
    """Remove instances of literals from a nested data structure."""
    match val:
        case str():
            return val
        case Mapping():
            return {k: remove_literals(v, literal) for k, v in val.items() if v not in literal}
        # ...`

The clean_http_kwargs function calls it with (None, False):
`
def clean_http_kwargs(val: Any) -> Any:
    cleaned = clean_kwargs(val, http=True)
    pruned = remove_literals(cleaned, (None, False))
    return pruned
`
The problem is that v not in literal uses == comparison, and in Python:

0 == False → True
0.0 == False → True
0 in (None, False) → True
0.0 in (None, False) → True
Suggested Fix:

Use identity comparison (is) instead of equality (==) in remove_literals

Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions