ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
0

Strange <package>.msg import behavior: "ModuleNotFoundError: No module named '<package>.msg'" Is this a ROS bug?

asked 2022-08-09 22:22:32 -0500

zkytony gravatar image

updated 2022-08-09 22:30:01 -0500

I am using ROS Noetic on Ubuntu 20.04. My Python version is 3.8.10. Here is what I observed.

Suppose we create a package called 'mytest', whose content is as follows

mytest/
|-- CMakeLists.txt
|-- msg
|   `-- MyMessage.msg
|-- package.xml
|-- scripts
|   `-- test_mytest.py
|-- setup.py
`-- src
    |-- mytest
    |   |-- __init__.py
    |   `-- hey.py
    `-- mytest2
        |-- __init__.py
        `-- hey.py

Notice there are two Python packages 'mytest' and 'mytest2', and they both contain a script called 'hey.py', with identical content:

from mytest.msg import MyMessage  # We import mytest/MyMessage

def hello():
    print("HELLO")

Suppose test_mytest.py initially has the following content:

#!/usr/bin/env python
from mytest.hey import hello

hello()

Refer to the content of CMakeLists.txt at the bottom. Build this package with catkin_make -DCATKIN_WHITELIST_PACKAGES='mytest'.

Now, if I do rosrun mytest test_mytest.py, I get the expected output, which is HELLO. However, if I change from mytest.hey import hello to from mytest2.hey import hello, then I get an error:

$ rosrun mytest test_mytest.py
Traceback (most recent call last):
  File "...../ros_ws/src/mytest/scripts/test_mytest.py", line 2, in <module>
    from mytest2.hey import hello
  File "...../ros_ws/src/mytest/src/mytest2/hey.py", line 1, in <module>
    from mytest.msg import MyMessage
ModuleNotFoundError: No module named 'mytest.msg'

How is this possible? "mytest" is built, and "mytest.msg" exists. But I can only access it within "mytest" and not from another pacfkage. I observed this weird behavior that confused me for several hours. Could someone explain what is going on?

Further Observation 1

I printed sys.path and the __file__ attribute of mytest and mytest.msg before the import statement in hey.py for both mytest and mytest2. I notice that the output of sys.path is identical. Notably, I get:

# print(sys.path)
['...../ros_ws/src/mytest/src',  
 '...../ros_ws/src/mytest/scripts',  
 '...../ros_ws/devel/lib/python3/dist-packages', 
 ...]

However, the __file__ attribute differs.

In mytest/hey.py,

import mytest
print(mytest.__file__)
# output: ..../ros_ws/devel/lib/python3/dist-packages/mytest/__init__.py

Whereas, in mytest2/hey.py,

import mytest
print(mytest.__file__)
# output: ..../ros_ws/src/mytest/src/mytest/__init__.py

Further Observation 2

mytest.msg can be imported in a Python shell

$ python
Python 3.8.10 (default, Mar 15 2022, 12:22:08) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import mytest.msg
>>> mytest.msg.__file__
'...../ros_ws/devel/lib/python3/dist-packages/mytest/msg/__init__.py'

The content of CMakeLists.txt is

cmake_minimum_required(VERSION 3.0.2)
project(mytest)

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  genmsg)

catkin_python_setup()

add_message_files(
  DIRECTORY msg
  FILES
  MyMessage.msg
)

generate_messages(
  DEPENDENCIES
  std_msgs
)

catkin_package()
edit retag flag offensive close merge delete

1 Answer

Sort by ยป oldest newest most voted
0

answered 2022-08-10 11:22:16 -0500

Mike Scheutzow gravatar image

updated 2022-08-10 11:24:11 -0500

Not a bug.

What you are missing is your custom messages create a python module mytest in ros_ws/devel/lib/... It has a .py file for each custom message.

So when your mytest2 looks for python module mytest, the first one it finds is ros_ws/src/mytest/src/mytest. This python module has no submodule msg, so an error is thrown.

It's bad practice to name your ros-package the same as a nested python module, and this is the reason why.

edit flag offensive delete link more

Comments

Thanks Mike. I had thought about that actually. But how come import mytest.msg works within hey.py in mytest? The sys.path shows that ros_ws/src/mytest/src/mytest is the first place to look for mytest, and there is no msgsubmodule there. That doesn't make sense to me. Also, regarding the mention of bad practice, I seem to often see ROS packages whose name is also used as an inner python package name. For example, the rospy package https://github.com/ros/ros_comm/tree/... has a 'src/rospy' folder.

zkytony gravatar image zkytony  ( 2022-08-10 11:33:41 -0500 )edit

Question Tools

3 followers

Stats

Asked: 2022-08-09 22:22:32 -0500

Seen: 1,071 times

Last updated: Aug 10 '22