Strange <package>.msg import behavior: "ModuleNotFoundError: No module named '<package>.msg'" Is this a ROS bug?
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()