csp icon indicating copy to clipboard operation
csp copied to clipboard

Cannot call super() inside method with graph/node decorator

Open timkpaine opened this issue 1 year ago • 1 comments

import csp
from datetime import datetime


class MyClass:
    @csp.graph
    def my_graph(self, x: int):
        csp.print("x", csp.const(x))


class MySubClass(MyClass):
    @csp.graph
    def my_graph(self):
        super().my_graph(x=5)


msc = MySubClass()
csp.run(msc.my_graph, realtime=True, starttime=datetime.now())
Traceback (most recent call last):
  File "tmp2.py", line 18, in <module>
    csp.run(msc.my_graph, realtime=True, starttime=datetime.now())
  File "csp/impl/wiring/runtime.py", line 214, in run
    return run(graph, starttime=starttime, endtime=endtime, **engine_settings)
  File "csp/impl/error_handling.py", line 37, in __exit__
    raise exc_val.with_traceback(new_tb)
  File "tmp2.py", line 14, in my_graph
    super().my_graph(x=5)
RuntimeError: super(): __class__ cell not found

Note that this works ok (no decorator):

class MySubClass(MyClass):
    def my_graph(self):
        super().my_graph(x=5)

Note that old style does also not work:

class MySubClass(MyClass):
    @csp.graph
    def my_graph(self):
        super(MySubClass, self).my_graph(x=5)
name 'MySubClass' is not defined. Did you mean: `MyClass`?

timkpaine avatar Apr 03 '24 16:04 timkpaine

Some experimentation, documenting here:

graph.py

def __get__(self, instance, owner):
    if instance is not None:
        c = self._func.__code__
        new_code = types.CodeType(c.co_argcount, c.co_posonlyargcount, c.co_kwonlyargcount, c.co_nlocals, c.co_stacksize, c.co_flags, c.co_code, c.co_consts, c.co_names, c.co_varnames, c.co_filename, c.co_name, c.co_qualname, c.co_firstlineno, c.co_lnotab, c.co_exceptiontable, c.co_freevars + ('__class__',), c.co_cellvars)
        new_closure = (self._func.__closure__ or ()) + (instance.__class__,)
        self._func = types.FunctionType(new_code, self._func.__globals__, self._func.__name__, self._func.__defaults__, new_closure)
        return types.MethodType(self, instance)
    return self

     

I think the best course of action is probably:

  • try to enable old-style classes properly by injecting the class name into scope
  • detect the presence of super() and throw an error early, to avoid cryptic default error message

timkpaine avatar Apr 18 '24 03:04 timkpaine