{"record":{"id":"1673c891c81599eb","repo":"aosabook/500lines","slug":"fieldname-1673c8","errorCode":null,"errorMessage":"fieldname","messagePattern":"fieldname","errorType":"exception","errorClass":"AttributeError","httpStatus":null,"severity":"error","filePath":"objmodel/code/03-customizable/objmodel.py","lineNumber":25,"sourceCode":"        \"\"\" Every object has a class. \"\"\"\n        self.cls = cls\n        self._fields = fields\n\n\n    def read_attr(self, fieldname):\n        \"\"\" read field 'fieldname' out of the object \"\"\"\n        result = self._read_dict(fieldname)\n        if result is not MISSING:\n            return result\n        result = self.cls._read_from_class(fieldname)\n        if _is_bindable(result):\n            return _make_boundmethod(result, self)\n        if result is not MISSING:\n            return result\n        meth = self.cls._read_from_class(\"__getattr__\")\n        if meth is not MISSING:\n            return meth(self, fieldname)\n        raise AttributeError(fieldname)\n\n    def write_attr(self, fieldname, value):\n        \"\"\" write field 'fieldname' into the object \"\"\"\n        meth = self.cls._read_from_class(\"__setattr__\")\n        return meth(self, fieldname, value)\n\n    def isinstance(self, cls):\n        \"\"\" return True if the object is an instance of class cls \"\"\"\n        return self.cls.issubclass(cls)\n\n    def callmethod(self, methname, *args):\n        \"\"\" call method 'methname' with arguments 'args' on object \"\"\"\n        meth = self.read_attr(methname)\n        return meth(*args)\n\n    def _read_dict(self, fieldname):\n        \"\"\" read an field 'fieldname' out of the object's dict \"\"\"\n        return self._fields.get(fieldname, MISSING)","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/aosabook/500lines/blob/fba689d101eb5600f5c8f4d7fd79912498e950e2/objmodel/code/03-customizable/objmodel.py#L7-L43","documentation":"Raised by Base.read_attr in the 03-customizable objmodel. The full lookup order is: instance dict -> class MRO (bindable callables become bound methods) -> a class-level __getattr__. AttributeError(fieldname) is reached only if none resolve the field, meaning the instance lacks the field, the class MRO lacks the attribute/method, AND no __getattr__ is defined on the class (or it re-raised).","triggerScenarios":"Reading an attribute that is absent from the instance dict, absent from the class and base classes, and the class defines no __getattr__ to cover it (or its __getattr__ raises AttributeError itself).","commonSituations":"Implementing __getattr__ but forgetting to handle certain names; deleting an attribute previously set; typos in fieldname; a __getattr__ that itself raises for unknown names.","solutions":["Define a __getattr__ method on the Class to supply a default or computed value for the missing field.","Store the field with write_attr or declare it in the Class fields.","Verify the fieldname and that the MRO includes the expected base classes."],"exampleFix":"// before\nobj.read_attr('missing')   # AttributeError: missing\n// after\n# add a class-level __getattr__\nMyClass = Class('MyClass', OBJECT, {\n    '__getattr__': lambda self, name: 'default',\n}, TYPE)","handlingStrategy":"fallback","validationCode":"MISSING = object()\n\ndef safe_read(obj, fieldname, default=None):\n    if obj._read_dict(fieldname) is not MISSING:\n        return obj._read_dict(fieldname)\n    if obj.cls._read_from_class(fieldname) is not MISSING:\n        return obj.cls._read_from_class(fieldname)\n    return default","typeGuard":"def has_field_or_getattr(obj, name):\n    MISSING = object()\n    return (obj._fields.get(name, MISSING) is not MISSING\n            or obj.cls._read_from_class(name) is not MISSING\n            or obj.cls._read_from_class('__getattr__') is not MISSING)","tryCatchPattern":"try:\n    val = obj.read_attr(fieldname)\nexcept AttributeError:\n    val = <default>","preventionTips":["Define a class-level __getattr__ to return a default for unknown names.","Validate field existence via _read_dict / _read_from_class before read_attr.","Keep field-name constants to avoid typos."],"tags":["attribute-access","object-model","python","getattr"],"backgroundTag":null,"analyzedSha":"fba689d101eb5600f5c8f4d7fd79912498e950e2","analyzedAt":"2026-08-13T06:26:32.792Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}