{"record":{"id":"f6b1ce1fc9a638d0","repo":"PaddlePaddle/PaddleOCR","slug":"you-cannot-use-update-on-a-self-class-n","errorCode":null,"errorMessage":"You cannot use ``update`` on a {self.__class__.__name__} instance.","messagePattern":"You cannot use ``update`` on a (.+?) instance\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"warning","filePath":"ppocr/modeling/heads/rec_unimernet_head.py","lineNumber":121,"sourceCode":"                    self[field.name] = v\n\n    def __delitem__(self, *args, **kwargs):\n        raise Exception(\n            f\"You cannot use ``__delitem__`` on a {self.__class__.__name__} instance.\"\n        )\n\n    def setdefault(self, *args, **kwargs):\n        raise Exception(\n            f\"You cannot use ``setdefault`` on a {self.__class__.__name__} instance.\"\n        )\n\n    def pop(self, *args, **kwargs):\n        raise Exception(\n            f\"You cannot use ``pop`` on a {self.__class__.__name__} instance.\"\n        )\n\n    def update(self, *args, **kwargs):\n        raise Exception(\n            f\"You cannot use ``update`` on a {self.__class__.__name__} instance.\"\n        )\n\n    def __getitem__(self, k):\n        if isinstance(k, str):\n            inner_dict = dict(self.items())\n            return inner_dict[k]\n        else:\n            return self.to_tuple()[k]\n\n    def __setattr__(self, name, value):\n        if name in self.keys() and value is not None:\n            super().__setitem__(name, value)\n        super().__setattr__(name, value)\n\n    def __setitem__(self, key, value):\n        super().__setitem__(key, value)\n        super().__setattr__(key, value)","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/PaddlePaddle/PaddleOCR/blob/2661c7c0ef5c613e8f93c6e93b2e052399f0f854/ppocr/modeling/heads/rec_unimernet_head.py#L103-L139","documentation":"update is blocked because a bulk dict update could inject undeclared keys into the typed output object. ModelOutput raises on any .update() call to keep field/dict consistency.","triggerScenarios":"Calling output.update(other_dict) or output.update(**kwargs) on a ModelOutput, e.g. merging extra metrics into the head's output.","commonSituations":"Accumulating loss/metric dicts across modules and update()-ing them into the model output; generic logging code that enriches any dict-like return value; merging outputs of two heads.","solutions":["Merge at the dict level: merged = {**output.to_dict(), **extra} and construct a new ModelOutput if needed","Set individual attributes instead: output.some_metric = value (typed assignment keeps the invariant)","Return a plain dict from your wrapper if callers need mutable dict semantics"],"exampleFix":"# before\nout.update({'cer': 0.02})\n# after\nmerged = {**dict(out.items()), 'cer': 0.02}","handlingStrategy":"type-guard","validationCode":"def merge_output(output, extra: dict) -> dict:\n    return {**dict(output.items()), **extra}\n# merged = merge_output(out, {'cer': 0.02}) instead of out.update(...)","typeGuard":"def is_model_output(obj) -> bool:\n    return hasattr(obj, '__dataclass_fields__') and hasattr(obj, 'to_tuple')","tryCatchPattern":"try:\n    out.update(extra)\nexcept Exception as e:\n    if 'update' in str(e):\n        out = {**dict(out.items()), **extra}\n    else:\n        raise","preventionTips":["Accumulate metrics in a plain dict, not on the output object","Assign typed attributes one by one when enrichment is required","Return dicts from wrappers that callers may mutate"],"tags":["model-output","immutable","unimernet","api-misuse"],"backgroundTag":null,"analyzedSha":"2661c7c0ef5c613e8f93c6e93b2e052399f0f854","analyzedAt":"2026-08-14T20:17:30.180Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}