From my knowledge of python, this means that std_msgs.msg is a module name (i.e. a .py file) and there should be a class definition for String inside that file.
[..]
I looked through the documentation and it says that rospy do create python source code for msg files, so there must be this std_msgs.msg.py file somewhere [..]
While it is true that Python modules are contained in a single file (ie: one with the same name as the module + .py
), there is a second construct called a package that is what is used here in this case.
Any directory with a __init__.py
file in it will be considered a package by the Python interpreter. Any files inside that directory (apart from __init__.py
) are again modules (which can contain classes and other Python entities), and sub directories of a package's directory will be considered sub packages (as long as they also contain a __init__.py
file).
In the case of std_msgs
, this is what that looks like:
└── /opt/ros/kinetic/lib/python2.7/dist-packages
└── std_msgs
├── __init__.py
└── msg
├── _Bool.py
├── _ByteMultiArray.py
├── _Byte.py
├── ..
├── __init__.py
├── ..
├── _String.py
├── ..
├── _UInt8MultiArray.py
└── _UInt8.py
So all ROS Python (2) packages (note: not necessarily ROS packages, as a single ROS package may contain multiple Python packages) are located in /opt/ros/kinetic/lib/python2.7/dist-packages
, in which there is a sub directory called std_msgs
. This contains a __init__.py
file, marking it as a sub package. This has a sub directory msg
, which then contains both a __init__.py
as well as all the files that contain the implementations of all the message classes (and which were generated by genpy
(not rospy
).
When you write from std_msgs.msg import String
, the Python interpreter will traverse this directory structure and end up at _String.py
, load it and make all the contained symbols available to the session.