From 1330708abe003585ee1b82a9b185c3ecb8cfa392 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Sat, 7 Sep 2024 15:26:28 +0100 Subject: [PATCH] refactor(typing): Fake immutability in `SchemaInfo` --- tools/generate_schema_wrapper.py | 3 ++- tools/schemapi/utils.py | 30 +++++++++++++++++++----------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/tools/generate_schema_wrapper.py b/tools/generate_schema_wrapper.py index bc2ba62e7..14cf34586 100644 --- a/tools/generate_schema_wrapper.py +++ b/tools/generate_schema_wrapper.py @@ -533,7 +533,8 @@ def get_field_datum_value_defs( propschema: SchemaInfo, root: dict[str, Any] ) -> dict[str, str]: def_dict: dict[str, str | None] = dict.fromkeys(("field", "datum", "value")) - schema = propschema.schema + _schema = propschema.schema + schema = _schema if isinstance(_schema, dict) else dict(_schema) if propschema.is_reference() and "properties" in schema: if "field" in schema["properties"]: def_dict["field"] = propschema.ref diff --git a/tools/schemapi/utils.py b/tools/schemapi/utils.py index cf6e9bac6..f86175c00 100644 --- a/tools/schemapi/utils.py +++ b/tools/schemapi/utils.py @@ -302,13 +302,13 @@ class SchemaProperties: def __init__( self, - properties: dict[str, Any], - schema: dict[str, Any], - rootschema: dict[str, Any] | None = None, + properties: Mapping[str, Any], + schema: Mapping[str, Any], + rootschema: Mapping[str, Any] | None = None, ) -> None: - self._properties: dict[str, Any] = properties - self._schema: dict[str, Any] = schema - self._rootschema: dict[str, Any] = rootschema or schema + self._properties: Mapping[str, Any] = properties + self._schema: Mapping[str, Any] = schema + self._rootschema: Mapping[str, Any] = rootschema or schema def __bool__(self) -> bool: return bool(self._properties) @@ -334,7 +334,7 @@ def __len__(self) -> int: def items(self) -> Iterator[tuple[str, SchemaInfo]]: return ((key, self[key]) for key in self) - def keys(self) -> dict_keys[str, Any]: + def keys(self) -> KeysView: return self._properties.keys() def values(self) -> Iterator[SchemaInfo]: @@ -347,13 +347,20 @@ class SchemaInfo: _remap_title: ClassVar[dict[str, str]] = {} def __init__( - self, schema: dict[str, Any], rootschema: dict[str, Any] | None = None + self, schema: Mapping[str, Any], rootschema: Mapping[str, Any] | None = None ) -> None: if not rootschema: rootschema = schema - self.raw_schema: dict[str, Any] = schema - self.rootschema: dict[str, Any] = rootschema - self.schema: dict[str, Any] = resolve_references(schema, rootschema) + self.raw_schema: Mapping[str, Any] + self.rootschema: Mapping[str, Any] + self.schema: Mapping[str, Any] + object.__setattr__(self, "raw_schema", schema) + object.__setattr__(self, "rootschema", rootschema) + object.__setattr__(self, "schema", resolve_references(schema, rootschema)) # type: ignore + + def __setattr__(self, name: str, value: Any) -> Never: + msg = f"{type(self).__name__!r} is immutable.\nCould not assign self.{name} = {value}" + raise TypeError(msg) def child(self, schema: dict[str, Any]) -> SchemaInfo: return self.__class__(schema, rootschema=self.rootschema) @@ -452,6 +459,7 @@ def to_type_repr( # noqa: C901 options = [] subschema = SchemaInfo(dict(**self.schema)) for typ_ in self.type: + # FIXME: Rewrite this to not mutate `SchemaInfo.schema` subschema.schema["type"] = typ_ # We always use title if possible for nested objects options.append(