AttributeError observed in sample_func when executed from a different python source file

1. Severity of the issue: (select one)
Medium: Significantly affects my productivity but can find a workaround.

2. Environment:

  • Ray version: 2.43.0
  • Python version: 3.11
  • OS: WSL (Ubuntu-22.04-LTS)
  • Cloud/Infrastructure: NA
  • Other libs/tools (if relevant): NA

3. What happened vs. what you expected:

  • Expected: Results should not be dependent upon how the source is organized
  • Actual: Results are dependent on how the source is organized

I am observing a strange issue - when I execute my code from a single source file there are no issues observed. When I try to distribute the source code into different files I am observing a strange AttributeError

I have tried to isolate & explain the issue via a minimal example. Request if community could review and suggest what could be the potential problem

WORKING CASE: working_main.py

# Minimal example: Working scenario
# Single source file 
import functools
import ray

# Decorator 
def test(f):
    print(f"{f.__name__} registered")
    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        wrapper.some_attribute = 42
        f(*args, **kwargs)
        return wrapper
    return wrapper

# Sample function: to be executed in a remote process
@test
def sample_func():
    print("This is a test function")

# Utility function
def run(custom_func: callable = None):
    ray.init()

    remote_actor = ray.remote(custom_func)
    sample_out = ray.get(remote_actor.remote())

    # Check if the attribute is available
    print(f"{sample_out.some_attribute=}")

if __name__ == "__main__":
    run(sample_func)

Results:

$ python working_main.py
sample_func registered
2025-03-25 20:38:47,801 INFO worker.py:1852 – Started a local Ray instance.
sample_out.some_attribute=42
(sample_func pid=694106) This is a test function

PROBLEM SCENARIO: Source code in two files (problem_main.py and problem_helper.py)

File: problem_main.py

# Minimal example: Problem scenario
# Some source in a helper file
from problem_helper import run
from problem_helper import sample_func

if __name__ == "__main__":
    run(sample_func)

File: problem_helper.py

import functools
import ray

# Decorator 
def test(f):
    print(f"{f.__name__} registered")
    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        wrapper.some_attribute = 42
        f(*args, **kwargs)
        return wrapper
    return wrapper

# Sample function: to be executed in a remote process
@test
def sample_func():
    print("This is a test function")

# Utility function
def run(custom_func: callable = None):
    ray.init()

    remote_actor = ray.remote(custom_func)
    sample_out = ray.get(remote_actor.remote())

    # Check if the attribute is available
    print(f"{sample_out.some_attribute=}")

Results:

$ python problem_main.py
sample_func registered
2025-03-25 20:39:05,564 INFO worker.py:1852 – Started a local Ray instance.
Traceback (most recent call last):
File “/path/problem_main.py”, line 7, in
run(sample_func)
File “/path/problem_helper.py”, line 27, in run
print(f"{sample_out.some_attribute=}")
^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: ‘function’ object has no attribute ‘some_attribute’
(pid=694632) sample_func registered
(sample_func pid=694632) This is a test function

SUMMARY: I am confused why the attribute in the second case is missing

Does it work if you don’t use Ray?

Hello @jjyao

Thanks for your response. It works without ray - refer to the minimal example which has been updated to work with / without ray

I would appreciate if you could describe what could be the possible issue as this same example works when all the source code is put into a single file

File: problem_main.py

# Minimal example: Problem scenario
# Some source in a helper file
import argparse
from problem_helper import run
from problem_helper import sample_func

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Run sample_func with or without Ray.")
    parser.add_argument(
        "--use_ray",
        action="store_true",
        help="Use Ray for execution if this flag is set."
    )
    args = parser.parse_args()

    run(sample_func, use_ray=args.use_ray)

File: problem_helper.py

import functools
import ray

# Decorator 
def test(f):
    print(f"{f.__name__} registered")
    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        wrapper.some_attribute = 42
        f(*args, **kwargs)
        return wrapper
    return wrapper

# Sample function: to be executed in a remote process
@test
def sample_func():
    print("This is a test function")

# Utility function
def run(custom_func: callable = None, use_ray: bool = True):

    if use_ray:
        ray.init()

        remote_actor = ray.remote(custom_func)
        sample_out = ray.get(remote_actor.remote())

        # Check if the attribute is available
        print(f"{sample_out.some_attribute=}")

    else:
        # Execute the function locally
        custom_func()

        # Check if the attribute is available
        print(f"{custom_func.some_attribute=}")

Sample output

Without ray

$ python problem_main.py
sample_func registered
This is a test function
custom_func.some_attribute=42

With Ray

$ python problem_main.py --use_ray
sample_func registered
2025-04-20 12:38:01,909 INFO worker.py:1841 -- Started a local Ray instance.
(pid=72175) sample_func registered
(sample_func pid=72175) This is a test function
Traceback (most recent call last):
  File "/path/problem_main.py", line 16, in <module>
    run(sample_func, use_ray=args.use_ray)
  File "/path/problem_helper.py", line 29, in run
    print(f"{sample_out.some_attribute=}")
             ^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'function' object has no attribute 'some_attribute'