def _from_class(cls, base_class: type) -> "VirtualActorClass": """Construct the virtual actor class from a base class.""" # TODO(suquark): we may use more complex name for private functions # to avoid collision with user-defined functions. for attribute in [ "create", "_create", "option", "_construct", "_from_class", ]: if hasattr(base_class, attribute): logger.warning( "Creating an actor from class " f"{base_class.__name__} overwrites " f"attribute {attribute} of that class" ) if not is_function_or_method(getattr(base_class, "__init__", None)): # Add __init__ if it does not exist. # Actor creation will be executed with __init__ together. # Assign an __init__ function will avoid many checks later on. def __init__(self): pass base_class.__init__ = __init__ # Make sure the actor class we are constructing inherits from the # original class so it retains all class properties. class DerivedActorClass(cls, base_class): pass metadata = VirtualActorMetadata(base_class) has_getstate = "__getstate__" in metadata.methods has_setstate = "__setstate__" in metadata.methods if not has_getstate and not has_setstate: # This is OK since we'll use default one defined pass elif not has_getstate: raise ValueError("The class does not have '__getstate__' method") elif not has_setstate: raise ValueError("The class does not have '__setstate__' method") DerivedActorClass.__module__ = metadata.module name = f"VirtualActorClass({metadata.name})" DerivedActorClass.__name__ = name DerivedActorClass.__qualname__ = name # Construct the base object. self = DerivedActorClass.__new__(DerivedActorClass) self._metadata = metadata return self
def modify_class(cls): # cls has been modified. if hasattr(cls, "__ray_actor_class__"): return cls # Give an error if cls is an old-style class. if not issubclass(cls, object): raise TypeError( "The @ray.remote decorator cannot be applied to old-style " "classes. In Python 2, you must declare the class with " "'class ClassName(object):' instead of 'class ClassName:'.") # Modify the class to have an additional method that will be used for # terminating the worker. class Class(cls): __ray_actor_class__ = cls # The original actor class def __ray_terminate__(self): worker = ray.worker.global_worker if worker.mode != ray.LOCAL_MODE: ray.actor.exit_actor() Class.__module__ = cls.__module__ Class.__name__ = cls.__name__ if not is_function_or_method(getattr(Class, "__init__", None)): # Add __init__ if it does not exist. # Actor creation will be executed with __init__ together. # Assign an __init__ function will avoid many checks later on. def __init__(self): pass Class.__init__ = __init__ return Class