aosabook/500lines · error · NotImplementedError
The Abstract Node Class doesn't define 'render_self'
Error message
The Abstract Node Class doesn't define 'render_self'
What it means
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.
Source
Thrown at modeller/modeller.markdown:308
def render(self):
""" renders the item to the screen """
glPushMatrix()
glMultMatrixf(numpy.transpose(self.translation_matrix))
glMultMatrixf(self.scaling_matrix)
cur_color = color.COLORS[self.color_index]
glColor3f(cur_color[0], cur_color[1], cur_color[2])
if self.selected: # emit light if the node is selected
glMaterialfv(GL_FRONT, GL_EMISSION, [0.3, 0.3, 0.3])
self.render_self()
if self.selected:
glMaterialfv(GL_FRONT, GL_EMISSION, [0.0, 0.0, 0.0])
glPopMatrix()
def render_self(self):
raise NotImplementedError(
"The Abstract Node Class doesn't define 'render_self'")
class Primitive(Node):
def __init__(self):
super(Primitive, self).__init__()
self.call_list = None
def render_self(self):
glCallList(self.call_list)
class Sphere(Primitive):
""" Sphere primitive """
def __init__(self):
super(Sphere, self).__init__()
self.call_list = G_OBJ_SPHERE
View on GitHub (pinned to fba689d101)
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.
Example fix
# before: subclass added without overriding render_self
class Cube(Node):
pass
scene.append(Cube()) # render -> NotImplementedError
# after: implement render_self (or delegate to a call list)
class Cube(Primitive):
def __init__(self):
super(Cube, self).__init__()
self.call_list = build_cube_list()
# Primitive.render_self calls glCallList(self.call_list) Defensive patterns
Strategy: type-guard
Validate before calling
# ensure every scene node can render before adding it
from abc import ABCMeta, abstractmethod
class Node(object, metaclass=ABCMeta):
@abstractmethod
def render_self(self):
raise NotImplementedError Type guard
def can_render(node):
return node is not None and getattr(type(node).render_self, '__isabstractmethod__', False) is False Try / catch
try:
node.render_self()
except NotImplementedError:
log.error('abstract node %r in scene', type(node).__name__) Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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().
AI-assisted analysis of aosabook/500lines@fba689d101 (2026-08-13).
Data as JSON: /api/errors/f5eadd1c1f97e6e5.
Report an issue: GitHub.