{"record":{"id":"f5eadd1c1f97e6e5","repo":"aosabook/500lines","slug":"the-abstract-node-class-doesn-t-define-render-sel","errorCode":null,"errorMessage":"The Abstract Node Class doesn't define 'render_self'","messagePattern":"The Abstract Node Class doesn't define 'render_self'","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"modeller/modeller.markdown","lineNumber":308,"sourceCode":"\n    def render(self):\n        \"\"\" renders the item to the screen \"\"\"\n        glPushMatrix()\n        glMultMatrixf(numpy.transpose(self.translation_matrix))\n        glMultMatrixf(self.scaling_matrix)\n        cur_color = color.COLORS[self.color_index]\n        glColor3f(cur_color[0], cur_color[1], cur_color[2])\n        if self.selected:  # emit light if the node is selected\n            glMaterialfv(GL_FRONT, GL_EMISSION, [0.3, 0.3, 0.3])\n        \n        self.render_self()\n\n        if self.selected:\n            glMaterialfv(GL_FRONT, GL_EMISSION, [0.0, 0.0, 0.0])\n        glPopMatrix()\n\n    def render_self(self):\n        raise NotImplementedError(\n            \"The Abstract Node Class doesn't define 'render_self'\")\n\nclass Primitive(Node):\n    def __init__(self):\n        super(Primitive, self).__init__()\n        self.call_list = None\n\n    def render_self(self):\n        glCallList(self.call_list)\n\n\nclass Sphere(Primitive):\n    \"\"\" Sphere primitive \"\"\"\n    def __init__(self):\n        super(Sphere, self).__init__()\n        self.call_list = G_OBJ_SPHERE\n\n","sourceCodeStart":290,"sourceCodeEnd":326,"githubUrl":"https://github.com/aosabook/500lines/blob/fba689d101eb5600f5c8f4d7fd79912498e950e2/modeller/modeller.markdown#L290-L326","documentation":"Raised by Node.render_self in the modeller scene-graph (a 500 Lines OpenGL example). Node is an abstract base: its render_self raises NotImplementedError to enforce that every concrete node type supplies its own drawing logic. Subclasses such as Primitive override render_self (here calling glCallList). The error fires only when a node reaches rendering without an overriding render_self.","triggerScenarios":"Instantiating Node directly and adding it to the scene; subclassing Node (or a non-Primitive intermediate) and forgetting to implement render_self; a node whose render_self was renamed or deleted so the base method resolves.","commonSituations":"Adding a new node subclass to the scene graph but leaving rendering stubbed; refactoring that accidentally reintroduces the abstract base into the node list; copy-paste inheritance where a subclass still calls super().render_self().","solutions":["Confirm the offending node is a concrete subclass, not Node itself.","Implement render_self in the subclass that performs the OpenGL drawing.","If using abc, decorate Node.render_self with @abstractmethod and inherit ABC so instantiation fails early instead of at render time.","Search the node list for any Node() or un-overridden subclass instance."],"exampleFix":"# before: subclass added without overriding render_self\nclass Cube(Node):\n    pass\nscene.append(Cube())   # render -> NotImplementedError\n\n# after: implement render_self (or delegate to a call list)\nclass Cube(Primitive):\n    def __init__(self):\n        super(Cube, self).__init__()\n        self.call_list = build_cube_list()\n    # Primitive.render_self calls glCallList(self.call_list)","handlingStrategy":"type-guard","validationCode":"# ensure every scene node can render before adding it\nfrom abc import ABCMeta, abstractmethod\n\nclass Node(object, metaclass=ABCMeta):\n    @abstractmethod\n    def render_self(self):\n        raise NotImplementedError","typeGuard":"def can_render(node):\n    return node is not None and getattr(type(node).render_self, '__isabstractmethod__', False) is False","tryCatchPattern":"try:\n    node.render_self()\nexcept NotImplementedError:\n    log.error('abstract node %r in scene', type(node).__name__)","preventionTips":["Use abc.ABCMeta/@abstractmethod so abstract subclasses fail at construction, not render.","Keep a single Primitive base for call-list nodes and inherit drawing from it.","Add a test that walks the scene graph and asserts every node implements render_self.","Never insert Node() or partially-implemented subclasses into the node list."],"tags":[],"backgroundTag":null,"analyzedSha":"fba689d101eb5600f5c8f4d7fd79912498e950e2","analyzedAt":"2026-08-13T06:26:32.792Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}