Runtime_env "py_modules" fails for modules which aren't packages

Hi all,
I’m developing a tool which allows users to run their own compute plugins which uses Ray as a remote backend.

I’m trying to improve the developer experience for plugin writers so that they can easily test that their code is working. The runtime_env recommendations have been very helpful:
https://docs.ray.io/en/latest/handling-dependencies.html#library-development

A problem I’m running into right now is that, if I try to create a runtime environment with a module which is not a package, then the connection attempt fails with the following error:

...
    conn = ray.connect(
  File "/.../lib/python3.9/site-packages/ray/util/client/__init__.py", line 228, in connect
    conn = self.get_context().connect(*args, **kw_args)
  File "/.../lib/python3.9/site-packages/ray/util/client/__init__.py", line 88, in connect
    self.client_worker._server_init(job_config, ray_init_kwargs)
  File "/.../lib/python3.9/site-packages/ray/util/client/worker.py", line 681, in _server_init
    runtime_env = upload_py_modules_if_needed(
  File "/.../lib/python3.9/site-packages/ray/_private/runtime_env/py_modules.py", line 59, in upload_py_modules_if_needed
    if len(module.__path__) > 1:
AttributeError: module 'my_module' has no attribute '__path__'

This is the connection logic I’m using:

import my_module

job_config = ray.job_config.JobConfig(
    runtime_env={
        "py_modules": [my_module]
    }
)
ray.util.connect(f"{host}:{port}", metadata=headers, secure=use_tls, job_config=job_config)

Where my_module is an imported python file which is not part of a package. If instead I used something like my_package which is a directory containing an __init__.py, then the upload works properly.

Is this a bug, or a limitation? Or am I just doing something wrong?

Thank you!

1 Like

Yes, right now, it needs __init__.py, because it’s about a module.

I think maybe we can expand this a little bit. We probably can use .__spec__ and use origin and submodule_search_locations.

>>> import ray
ray.>>> ray.__spec__
ModuleSpec(name='ray', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7f2362bd1640>, origin='/mnt/yic/ray/python/ray/__init__.py', submodule_search_locations=['/mnt/yic/ray/python/ray'])

So for the case in the OP, submodule_search_locations shouldn’t be there and we only copy origin.

@architkulkarni Do you have some suggestions about this?

Hi @ncoish, yes, this is a limitation. Could you please make a request for this as a Ray Github issue?

I don’t know too much about the details here, but Yi’s suggestion sounds reasonable and looks like a good place to start.

In the meantime, if your module is just a file, you should be able to upload it as part of the working_dir, or just include the path to the directory containing the file in the py_modules field–does the import work in that case?