Skip to content

Commit b06eca8

Browse files
SolitaryThinkerpcmoritz
authored andcommitted
[core] Fix ActorClass.remote return typing and expose Actor class methods to static analysis (#53986)
<!-- Thank you for your contribution! Please review https://github.com/ray-project/ray/blob/master/CONTRIBUTING.rst before opening a pull request. --> <!-- Please add a reviewer to the assignee section when you create a PR. If you don't have the access to it, we will shortly find a reviewer and assign them to your PR. --> ## Why are these changes needed? Changes in this PR are inspired by https://github.com/zen-xu/sunray Calling `remote()` on an Actor class incorrectly returns an `ObjectRef[...]` type. Also, the Actor class's methods are not available to IDEs, as the type is incorrect. This PR makes `ActorHandle` a generic type `ActorHandle[T]` and also creates an type alias: `ActorProxy = Union["ActorHandle[T]", type[T]]` to expose the method signatures from the Actor class. Here are some other possible candidates for the type name instead of `ActorProxy` from claude: ActorInterface TypedActorHandle RemoteActorType ActorProxy ActorT cc @richardliaw @pcmoritz We'll add better type hints for actor methods in a follow up PR. The following are screenshots demonstrating the type hints in Cursor before and after this PR: **Before this PR** ![image](https://github.com/user-attachments/assets/681a6572-b27d-46fb-aa7e-f2d4fddc55a0) ![image](https://github.com/user-attachments/assets/3e0f2a3f-33dd-41e9-bd05-657efd1e6f59) ![image](https://github.com/user-attachments/assets/da45eb6e-479e-4114-b4cc-cefd4cefafb2) --- **After this PR** ![image](https://github.com/user-attachments/assets/c60943a8-7e9e-4baa-88aa-57122e617889) ![image](https://github.com/user-attachments/assets/55afe9bf-282f-45cf-b615-4facde9e1623) ![image](https://github.com/user-attachments/assets/73b65613-800a-4c24-968c-7062b3956410) ## Related issue number <!-- For example: "Closes #1234" --> ## Checks - [x] I've signed off every commit(by using the -s flag, i.e., `git commit -s`) in this PR. - [x] I've run `scripts/format.sh` to lint the changes in this PR. - [ ] I've included any doc changes needed for https://docs.ray.io/en/master/. - [ ] I've added any new APIs to the API Reference. For example, if I added a method in Tune, I've added it in `doc/source/tune/api/` under the corresponding `.rst` file. - [ ] I've made sure the tests are passing. Note that there might be a few flaky tests, see the recent failures at https://flakey-tests.ray.io/ - Testing Strategy - [ ] Unit tests - [ ] Release tests - [ ] This PR is not tested :( --------- Signed-off-by: will.lin <will.lin@anyscale.com> Signed-off-by: Philipp Moritz <pcmoritz@gmail.com> Co-authored-by: Philipp Moritz <pcmoritz@gmail.com> Signed-off-by: elliot-barn <elliot.barnwell@anyscale.com>
1 parent 370d8a3 commit b06eca8

File tree

3 files changed

+30
-12
lines changed

3 files changed

+30
-12
lines changed

doc/source/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
# for additional context.
130130
nitpicky = True
131131
nitpick_ignore_regex = [
132+
("py:obj", "ray.actor.T"),
132133
("py:class", ".*"),
133134
# Workaround for https://github.com/sphinx-doc/sphinx/issues/10974
134135
("py:obj", "ray\\.data\\.datasource\\.datasink\\.WriteReturnType"),

python/ray/_private/worker.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
Protocol,
3131
Sequence,
3232
Tuple,
33+
Type,
3334
TypeVar,
3435
Union,
3536
overload,
@@ -79,6 +80,7 @@
7980
TaskID,
8081
raise_sys_exit_with_custom_error_message,
8182
)
83+
from ray.actor import ActorClass
8284
from ray.exceptions import ObjectStoreFullError, RayError, RaySystemError, RayTaskError
8385
from ray.experimental import tqdm_ray
8486
from ray.experimental.compiled_dag_ref import CompiledDAGRef
@@ -3332,6 +3334,11 @@ def __call__(self, __t: type) -> Any:
33323334
...
33333335

33343336

3337+
@overload
3338+
def remote(__t: Type[T]) -> ActorClass[T]:
3339+
...
3340+
3341+
33353342
@overload
33363343
def remote(__function: Callable[[], R]) -> RemoteFunctionNoArgs[R]:
33373344
...
@@ -3401,13 +3408,6 @@ def remote(
34013408
...
34023409

34033410

3404-
# Pass on typing actors for now. The following makes it so no type errors
3405-
# are generated for actors.
3406-
@overload
3407-
def remote(__t: type) -> Any:
3408-
...
3409-
3410-
34113411
# Passing options
34123412
@overload
34133413
def remote(

python/ray/actor.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
import inspect
22
import logging
3-
from typing import Any, Dict, List, Literal, Optional, Tuple, Union, TYPE_CHECKING
3+
from typing import (
4+
Any,
5+
Dict,
6+
List,
7+
Literal,
8+
Optional,
9+
Tuple,
10+
Union,
11+
TYPE_CHECKING,
12+
TypeVar,
13+
Generic,
14+
)
415

516
import ray._private.ray_constants as ray_constants
617
import ray._private.signature as signature
@@ -51,6 +62,12 @@
5162
# Hook to call with (actor, resources, strategy) on each local actor creation.
5263
_actor_launch_hook = None
5364

65+
# TypeVar for generic ActorHandle
66+
T = TypeVar("T")
67+
68+
# return type of ActorClass[T].remote()
69+
ActorProxy = Union["ActorHandle[T]", type[T]]
70+
5471

5572
@PublicAPI
5673
@client_mode_hook
@@ -761,7 +778,7 @@ def _process_option_dict(actor_options):
761778

762779

763780
@PublicAPI
764-
class ActorClass:
781+
class ActorClass(Generic[T]):
765782
"""An actor class.
766783
767784
This is a decorated class. It can be used to create actors.
@@ -901,7 +918,7 @@ def _ray_from_function_descriptor(
901918
self._default_options["runtime_env"] = self.__ray_metadata__.runtime_env
902919
return self
903920

904-
def remote(self, *args, **kwargs):
921+
def remote(self, *args, **kwargs) -> ActorProxy[T]:
905922
"""Create an actor.
906923
907924
Args:
@@ -1052,7 +1069,7 @@ class or functions.
10521069

10531070
@wrap_auto_init
10541071
@_tracing_actor_creation
1055-
def _remote(self, args=None, kwargs=None, **actor_options):
1072+
def _remote(self, args=None, kwargs=None, **actor_options) -> ActorProxy[T]:
10561073
"""Create an actor.
10571074
10581075
This method allows more flexibility than the remote method because
@@ -1434,7 +1451,7 @@ class or functions.
14341451

14351452

14361453
@PublicAPI
1437-
class ActorHandle:
1454+
class ActorHandle(Generic[T]):
14381455
"""A handle to an actor.
14391456
14401457
The fields in this class are prefixed with _ray_ to hide them from the user

0 commit comments

Comments
 (0)