Skip to content

Commit f14e3f4

Browse files
#391 sz_explorer: strip null/empty entries from UNMAPPED_DATA (#392)
* #391 * #391 add changelog entry under Unreleased * #391 cut 0.0.41 with sz_explorer UNMAPPED_DATA null/empty strip --------- Co-authored-by: Michael Dockter <michael@dockter.com>
1 parent 369c33b commit f14e3f4

3 files changed

Lines changed: 53 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ This project adheres to [Semantic Versioning].
77

88
## [Unreleased]
99

10+
## [0.0.41] - 2026-05-18
11+
12+
### Fixed in 0.0.41
13+
14+
- `sz_explorer`: mappable attributes with null/empty values no longer appear in Additional Data (#391)
15+
1016
## [0.0.40] - 2026-04-23
1117

1218
### Fixed in 0.0.40

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "sz-python-tools"
3-
version = "0.0.40"
3+
version = "0.0.41"
44
description = "Senzing Python Tools"
55
authors = [{ name = "senzing", email = "support@senzing.com" }]
66
readme = "README.md"

sz_tools/sz_explorer

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,6 +1543,50 @@ class EdaReports:
15431543
)
15441544

15451545

1546+
def _strip_null_values(value):
1547+
"""Recursively drop None and empty-string entries from nested dicts/lists.
1548+
1549+
Keeps 0, False, and other non-null values. Returns None if the container
1550+
collapses to empty so callers can drop it from a parent.
1551+
"""
1552+
if isinstance(value, dict):
1553+
cleaned = {}
1554+
for k, v in value.items():
1555+
if v is None or v == "":
1556+
continue
1557+
cv = _strip_null_values(v)
1558+
if cv is None:
1559+
continue
1560+
cleaned[k] = cv
1561+
return cleaned or None
1562+
if isinstance(value, list):
1563+
cleaned = []
1564+
for item in value:
1565+
if item is None or item == "":
1566+
continue
1567+
ci = _strip_null_values(item)
1568+
if ci is None:
1569+
continue
1570+
cleaned.append(ci)
1571+
return cleaned or None
1572+
return value
1573+
1574+
1575+
def _clean_unmapped_data(node):
1576+
"""Walk a parsed engine response and strip null/empty entries from every
1577+
UNMAPPED_DATA dict found anywhere in the structure. Mutates in place.
1578+
"""
1579+
if isinstance(node, dict):
1580+
if "UNMAPPED_DATA" in node:
1581+
cleaned = _strip_null_values(node["UNMAPPED_DATA"])
1582+
node["UNMAPPED_DATA"] = cleaned if cleaned else {}
1583+
for v in node.values():
1584+
_clean_unmapped_data(v)
1585+
elif isinstance(node, list):
1586+
for item in node:
1587+
_clean_unmapped_data(item)
1588+
1589+
15461590
class EdaSdkWrapper:
15471591

15481592
def __init__(self, engine_config, **kwargs):
@@ -1693,6 +1737,8 @@ class EdaSdkWrapper:
16931737
except SzError as err:
16941738
raise SzError(f"{api_name}: {err}") from None
16951739

1740+
_clean_unmapped_data(response_data)
1741+
16961742
if self.mask_pii:
16971743
mask_json_pii(response_data, self.mask_pii)
16981744

0 commit comments

Comments
 (0)