Containers¶
Tier 2 wraps Python data shapes with shape-specific ExtendedString,
ExtendedDict, ExtendedList, ExtendedTuple, and
ExtendedSet containers. ExtendedData is their common root and
polymorphic constructor: callers can use one entrypoint while still
receiving the concrete extended type for the incoming value.
Construction and mutation promote nested values, so method chains survive normal Python literals.
from extended_data import ExtendedData, ExtendedDict, ExtendedList, ExtendedString
payload = ExtendedDict({"service": {"name": "api"}, "tags": ["api", "api", ""]})
generic = ExtendedData(payload).merge({"service": {"enabled": True}})
print(payload["service"]["name"].upper_first())
print(generic.as_builtin()["service"]["enabled"])
print(payload["tags"].compact().deduplicate())
print(ExtendedString("HTTP Response Value").to_snake_case())
Polymorphic ExtendedData¶
Use ExtendedData at file, API, workflow, and vendor boundaries where
the payload may be a mapping today, a list tomorrow, or a scalar status
value from a different provider. The constructor returns the concrete
extended subtype when one applies, so normal Python collection behavior
remains native rather than proxied.
from extended_data import ExtendedData, ExtendedDict, ExtendedList, ExtendedString
vendor = ExtendedData({"vendor": "google", "payload": {"names": ["alpha"]}})
vendor["enabled"] = "true"
assert type(vendor) is ExtendedDict
assert isinstance(vendor, ExtendedData)
assert vendor.shape == "mapping"
assert vendor.get("vendor").upper_first() == "Google"
assert vendor["payload"]["names"][0].upper_first() == "Alpha"
merged = vendor.merge({"payload": {"region": "us-east-1"}})
assert merged.as_builtin()["payload"]["region"] == "us-east-1"
assert type(ExtendedData([{"name": "api"}]).append({"name": "worker"})) is ExtendedList
assert type(ExtendedData("HTTP Response Value")) is ExtendedString
The common root exposes broad shape predicates without forcing dict-only code paths:
assert ExtendedData("HTTP Response Value").is_string
assert ExtendedData([{"name": "api"}]).is_sequence
assert ExtendedData({"prod", "api"}).is_set
assert ExtendedData(42).is_scalar
assert ExtendedData().is_none
Downstream packages can subclass ExtendedData for additive facades
without being collapsed by the root factory. Store the promoted payload
with ExtendedData(value) and keep provider or runtime behavior on the
subclass:
class ProviderData(ExtendedData):
def __init__(self, value, *, provider):
self.provider = provider
self._data = ExtendedData(value)
@property
def value(self):
return self._data
provider_data = ProviderData({"service": {"name": "api"}}, provider="vendor")
assert type(provider_data) is ProviderData
assert provider_data.shape == "mapping"
assert provider_data["service"]["name"].upper_first() == "Api"
Facades that need to keep the same outer identity while changing shape
should override cast() and replace their internal ExtendedData
value.
It also provides shared data-boundary helpers:
decoded = ExtendedData.decode('{"service": {"name": "api"}}', suffix="json")
loaded = ExtendedData.read("config/service.yaml")
result = loaded.sync_to_file("build/service.json", encoding="json")
assert decoded["service"]["name"].upper_first() == "Api"
print(result.changed)
Promotion and Lowering¶
from extended_data import extend_data, to_builtin
data = extend_data({"outer": {"inner": ["api"]}})
assert data["outer"]["inner"][0].upper_first() == "Api"
plain = to_builtin(data)
assert plain == {"outer": {"inner": ["api"]}}
Tuples remain tuple-shaped when promoted and lowered. Sets stay set-shaped. Mapping keys are lowered before export so JSON, YAML, TOML, and HCL encoders can hand data to their underlying format libraries safely.