pythonasynchronousjupyter-notebookray

In a Jupyter notebook, create an object from a class referenced using a string to use with ray


My 3.6.3 Jupyterlab notebook is running Python 3.10.11. I am trying to use Ray to implement some asymmetrical code. This would be simple, except that in my remote function I am trying to implement a class object using a string holding the class name.

We have a number of triggers, each trigger causing a specific class to be used. We can't do a bunch of if statements to create the class object as the triggers can change.

The following code is an example of what I am trying to do. "job1" works because I instantiated the class object directly. "job2" does not work because I used eval() to instantiate the class object.

import ray
ray.init(ignore_reinit_error=True)

# Usually imported with a %run class_notebook.ipynb command.
class Test:
    def nothing(self):
        return True
        
@ray.remote
def do_it1():
    x = Test()   # Class object created directly. This works.
    return x.nothing()

@ray.remote
def do_it2():
    x = eval("Test")()   # Class object created using a string. This causes issues later.
    return x.nothing()    
    
job1 = do_it1.remote()

job2 = do_it2.remote()

ray.get(job1)

ray.get(job2)   # Error occurs here

The error message is:

---------------------------------------------------------------------------
RayTaskError(NameError)                   Traceback (most recent call last)
Cell In[9], line 1
----> 1 ray.get(job2)

File /opt/conda/lib/python3.10/site-packages/ray/_private/auto_init_hook.py:24, in wrap_auto_init.<locals>.auto_init_wrapper(*args, **kwargs)
     21 @wraps(fn)
     22 def auto_init_wrapper(*args, **kwargs):
     23     auto_init_ray()
---> 24     return fn(*args, **kwargs)

File /opt/conda/lib/python3.10/site-packages/ray/_private/client_mode_hook.py:103, in client_mode_hook.<locals>.wrapper(*args, **kwargs)
    101     if func.__name__ != "init" or is_client_mode_enabled_by_default:
    102         return getattr(ray, func.__name__)(*args, **kwargs)
--> 103 return func(*args, **kwargs)

File /opt/conda/lib/python3.10/site-packages/ray/_private/worker.py:2493, in get(object_refs, timeout)
   2491     worker.core_worker.dump_object_store_memory_usage()
   2492 if isinstance(value, RayTaskError):
-> 2493     raise value.as_instanceof_cause()
   2494 else:
   2495     raise value

RayTaskError(NameError): ray::do_it2() (pid=25675, ip=172.31.3.78)
  File "/tmp/ipykernel_25494/1701015360.py", line 3, in do_it2
  File "<string>", line 1, in <module>
NameError: name 'Test' is not defined

What do I need to do in the do_it2 function to use a string to create the instance of class object?

[edit]To instantiate my class object I have tried using globals() but that does not work either.

x = globals()['Test']()

[/edit]


Solution

  • I ended up creating my class object outside of the function and then passing it in as a parameter.

    So, the relevant changes look like this...

    @ray.remote
    def doit2(my_object):
       return my_object.nothing()
    
    job2 = do_it2.remote(eval("Test")())