Open jandaa opened 3 years ago
same problem with anaconda
Same problem on galactic
In short, python venvs with Python installed in the venv are never going to work using the installed ROS 2 binaries. The problem boils down to the fact that building a Python package as a Debian hard-codes the default python path in the console script (namely /usr/bin/python3
).
However, what should work is having a Python venv with just pip packages installed. That is, if you rely on the system version of Python, but just make a venv where you pip install a bunch of dependencies, that should work just fine. That said, ROS 2 expects certain versions of pip dependencies/APIs to be present, so it may be the case that you cannot use newer versions of pip packages while doing this.
Thank you so much @clalancette for your response, that makes sense! What you describe as using just the pip packages would work just fine. In this case, how would we point our environment to these separate site packages contained in our venv?
Thank you so much @clalancette for your response, that makes sense! What you describe as using just the pip packages would work just fine. In this case, how would we point our environment to these separate site packages contained in our venv?
Just running source venv/bin/activate
, then source /opt/ros/foxy/setup.bash
should do it, though I haven't personally tried this out yet.
Thank you so much @clalancette for your response, that makes sense! What you describe as using just the pip packages would work just fine. In this case, how would we point our environment to these separate site packages contained in our venv?
Just running
source venv/bin/activate
, thensource /opt/ros/foxy/setup.bash
should do it, though I haven't personally tried this out yet.
I tried doing precisely this, though ros2 run
still seems to be using either wrong interpreter or is otherwise disregarding venv packges and thus isn't finding the pip-installed packages the node requires.
colcon build
executedros2 run
finds and attempts to execute the node, but fails because it fails to find the pip-installed package.Console output provided. console.log
It's possible that sourcing install/setup.zsh
is overwriting the PYTHONPATH that the venv setup. Since you don't actually need the venv to build, then I'll suggest trying the other order:
It's possible that sourcing
install/setup.zsh
is overwriting the PYTHONPATH that the venv setup. Since you don't actually need the venv to build, then I'll suggest trying the other order:* source /opt/ros/foxy/setup.zsh * colcon build * source install/local_setup.zsh * source venv/bin/activate * ros2 run pkg exe
~/projects/skool/rover/next/science/osiris_turret_ros2 ⌚ 12:57:43
$ source /opt/ros/foxy/setup.zsh
~/projects/skool/rover/next/science/osiris_turret_ros2 ⌚ 12:57:51
$ colcon build
Starting >>> osiris_turret
Finished <<< osiris_turret [0.50s]
Summary: 1 package finished [0.66s]
~/projects/skool/rover/next/science/osiris_turret_ros2 ⌚ 12:57:54
$ source install/local_setup.zsh
~/projects/skool/rover/next/science/osiris_turret_ros2 ⌚ 12:57:56
$ source venv/bin/activate
(venv)
~/projects/skool/rover/next/science/osiris_turret_ros2 ⌚ 12:57:59
$ ros2 run osiris_turret service
Traceback (most recent call last):
File "/home/orion/projects/skool/rover/next/science/osiris_turret_ros2/install/osiris_turret/lib/osiris_turret/service", line 6, in <module>
from pkg_resources import load_entry_point
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 3254, in <module>
def _initialize_master_working_set():
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 3237, in _call_aside
f(*args, **kwargs)
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 3266, in _initialize_master_working_set
working_set = WorkingSet._build_master()
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 584, in _build_master
ws.require(__requires__)
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 901, in require
needed = self.resolve(parse_requirements(requirements))
File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 787, in resolve
raise DistributionNotFound(req, requirers)
pkg_resources.DistributionNotFound: The 'turret_python_interface' distribution was not found and is required by osiris-turret
(venv)
~/projects/skool/rover/next/science/osiris_turret_ros2 ⌚ 12:58:02
$
@theunkn0wn1 can you do a printenv
and check what PYTHONPATH
is set to?
@aprotyas it seems venv
isn't adding anything to the PYTHONPATH
, but rather extending PATH
and setting the VIRTUAL_ENV
key.
~/projects/skool/rover/next/science/osiris_turret_ros2 ⌚ 13:16:50
$ printenv | grep -i venv
~/projects/skool/rover/next/science/osiris_turret_ros2 ⌚ 13:16:54
$ printenv | grep -i pythonpath
~/projects/skool/rover/next/science/osiris_turret_ros2 ⌚ 13:16:59
$ source /opt/ros/foxy/setup.zsh
~/projects/skool/rover/next/science/osiris_turret_ros2 ⌚ 13:17:03
$ printenv | grep -i pythonpath
PYTHONPATH=/opt/ros/foxy/lib/python3.8/site-packages
~/projects/skool/rover/next/science/osiris_turret_ros2 ⌚ 13:17:06
$ printenv | grep -i venv
~/projects/skool/rover/next/science/osiris_turret_ros2 ⌚ 13:17:14
$ source ./install/local_setup.zsh
~/projects/skool/rover/next/science/osiris_turret_ros2 ⌚ 13:17:21
$ printenv | grep -i venv
~/projects/skool/rover/next/science/osiris_turret_ros2 ⌚ 13:17:24
$ printenv | grep -i pythonpath
PYTHONPATH=/home/orion/projects/skool/rover/next/science/osiris_turret_ros2/install/osiris_turret/lib/python3.8/site-packages:/opt/ros/foxy/lib/python3.8/site-packages
~/projects/skool/rover/next/science/osiris_turret_ros2 ⌚ 13:17:26
$ source venv/bin/activate
(venv)
~/projects/skool/rover/next/science/osiris_turret_ros2 ⌚ 13:17:31
$ printenv | grep -i pythonpath
PYTHONPATH=/home/orion/projects/skool/rover/next/science/osiris_turret_ros2/install/osiris_turret/lib/python3.8/site-packages:/opt/ros/foxy/lib/python3.8/site-packages
(venv)
~/projects/skool/rover/next/science/osiris_turret_ros2 ⌚ 13:17:34
$ printenv | grep -i venv
PATH=/home/orion/projects/skool/rover/next/science/osiris_turret_ros2/venv/bin:/opt/ros/foxy/bin:/home/orion/gems/bin:/home/orion/.cargo/bin:/home/orion/.cargo/bin:/home/orion/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
VIRTUAL_ENV=/home/orion/projects/skool/rover/next/science/osiris_turret_ros2/venv
PS1=(venv)
(venv)
~/projects/skool/rover/next/science/osiris_turret_ros2 ⌚ 13:17:37
$
OK, I see what is happening here. The issue is in the script that python generates when we do the install. For instance, in the original case in this PR, the build process ends up generating install/venv/lib/venv/venv
. Inside of that script, the preamble looks something like:
#!/usr/bin/python3
# EASY-INSTALL-ENTRY-SCRIPT: 'venv==0.0.0','console_scripts','venv'
import re
import sys
Because that is a hard-coded path to /usr/bin/python3
, it isn't even looking inside of the virtual environment for packages. What that really should be is #!/usr/bin/env python3
so that it would pick up the venv properly.
I'm really not sure how we can fix that; that script is totally generated by Python itself. We'll have to look into whether there is a way to have EASY-INSTALL-ENTRY-SCRIPT
honor the venv, in a cross-platform way.
One possible solution would be for ros2 run
to detect if the specified executable is a python target, and run the entry-point using the environment's interpreter directly instead of depending on the shebang line. While this is a workaround, it would resolve the immediate issue.
I am not entirely familiar with how ROS2's py build process works, but if EASY-INSTALL-ENTRY-SCRIPT
is referring to easy-install
, that is depricated.
Another possible option I am considering is running a post-processing script over the generated entry-points to programmatically replace the generated shebang lines.
Caused by https://github.com/colcon/colcon-core/issues/181
Fixed by, but not merged, https://github.com/colcon/colcon-core/pull/183.
I tried the fix in https://github.com/colcon/colcon-core/pull/188 but that seems to not effect the core issue.
I applied the fix in 183 against my local ROS2 python package's setup.cfg
and it fixes the shebang bug.
I think I also encounter this issue, after running this "sudo apt install ros-foxy-desktop", the pythonpath will have additional path "opt/ros/foxy/lib/python3.8/site-packages", then the right virtual python env can't be recognized correctly.
Here are some steps to creating a suitable venv:
python3 -m venv venv --system-site-packages --symlinks
In terms of creating Python ROS2 packages, create it as normal but add apply the fix in https://github.com/colcon/colcon-core/pull/183 to your setup.cfg
When building your nodes, be sure you've sourced both ros's setup as well as the venv's, BEFORE invoking colcon build
.
thanks to @theunkn0wn1 , it works
Since we are working with (potentially single vens). Instead of adding the "fixed" version, colcon already extracts the correct interpreter if built from your workspace or when it is reinstalled in your venv using something like
pip install --force-reinstall colcon-core setuptools==$(pip list --no-index --format=json | jq -r '.[] | select(.name=="setuptools").version')
Of course you can not auto maintain multiple installations along side it (single colcon install). You need it for every venv. Which is a reasonable compromise, I guess. The above setuptools limit is only needed if an upgraded version causes issues. For example the current (py)torch still accesses features of distutils at runtime which have been removed in newer versions. But pip auto upgrades it for some reason although it is not required. Only-if-needed does still install a newer version.
When colcon core is being rebuilt it will your sys.executable path and add it to your python scripts as shebang. In case of a venv or any python env this is the interpreter path of your executable. No need to manually set the PYTHONPATH or using the specific fix. If you want to work with a single install of colcon though this may be the version to go.
This thread was super helpful. I couldn't get @theunkn0wn1 's solution to work for me, but I might be doing something different (like using virtualenv
instead of venv
, not sure how/why that would be different)
My application is simple for now, and I can just rely on the system python and install my packages there. However, is there a long term cleaner solution even possible for this? Could we try to update documentation here to reflect the current behavior and/or the fix?
Thanks!
EDIT:
@theunkn0wn1 's solution does work with virtualenv
too... After an hour+ of trying other things, upon trying this I forgot to actually install the package at all in my virtualenv xD
However, I'm still at the mercy of including the change in setup.cfg
for all my packages and the order in which I source setup files.
Would this also be fixed by addressing colcon using the deprecated method of installing by directly invoking setup.py
?
Just to follow up on this, I found everything works well if I just run python -m colcon
instead of colcon
when the virtualenv is active. No need to change any files in your packages.
I found a way that you can use virtual python's package like torch.
import sys
sys.path.append('{YOUR VIRTUAL PYTHON PATH}/lib/python3.10/site-packages')
import torch
I found a way that you can use virtual python's package like torch.
import sys sys.path.append('{YOUR VIRTUAL PYTHON PATH}/lib/python3.10/site-packages') import torch
Note: path hacks make the code very brittle, break isolation, and make environments difficult to reproduce. I encourage you to find a better solution.
2. python3 -m venv venv --system-site-packages --symlinks
This doesn't work, still can't find lark
, despite it being installed.
--- stderr: nav2_msgs
Traceback (most recent call last):
File "/home/ryan/Development/ros2_rolling/install/rosidl_generator_type_description/lib/rosidl_generator_type_description/rosidl_generator_type_description", line 21, in <module>
from rosidl_generator_type_description import generate_type_hash
File "/home/ryan/Development/ros2_rolling/install/rosidl_generator_type_description/lib/python3.11/site-packages/rosidl_generator_type_description/__init__.py", line 24, in <module>
from rosidl_parser.parser import parse_idl_file
File "/home/ryan/Development/ros2_rolling/install/rosidl_parser/lib/python3.11/site-packages/rosidl_parser/parser.py", line 20, in <module>
from lark import Lark
(.rolling) ryan@ryan-B650-970:~/Development/nav2_ws/src/navigation2$ python3 -m pip list | grep lark
lark 1.1.5
python -m colcon
This doesn't work because:
$ which colcon
/usr/bin/colcon
- python3 -m venv venv --system-site-packages --symlinks
This doesn't work, still can't find
lark
, despite it being installed.--- stderr: nav2_msgs Traceback (most recent call last): File "/home/ryan/Development/ros2_rolling/install/rosidl_generator_type_description/lib/rosidl_generator_type_description/rosidl_generator_type_description", line 21, in <module> from rosidl_generator_type_description import generate_type_hash File "/home/ryan/Development/ros2_rolling/install/rosidl_generator_type_description/lib/python3.11/site-packages/rosidl_generator_type_description/__init__.py", line 24, in <module> from rosidl_parser.parser import parse_idl_file File "/home/ryan/Development/ros2_rolling/install/rosidl_parser/lib/python3.11/site-packages/rosidl_parser/parser.py", line 20, in <module> from lark import Lark
(.rolling) ryan@ryan-B650-970:~/Development/nav2_ws/src/navigation2$ python3 -m pip list | grep lark lark 1.1.5
python -m colcon
This doesn't work because:
$ which colcon /usr/bin/colcon
Have you tried reinstalling colcon-core to your env?
- python3 -m venv venv --system-site-packages --symlinks
This doesn't work, still can't find
lark
, despite it being installed.--- stderr: nav2_msgs Traceback (most recent call last): File "/home/ryan/Development/ros2_rolling/install/rosidl_generator_type_description/lib/rosidl_generator_type_description/rosidl_generator_type_description", line 21, in <module> from rosidl_generator_type_description import generate_type_hash File "/home/ryan/Development/ros2_rolling/install/rosidl_generator_type_description/lib/python3.11/site-packages/rosidl_generator_type_description/__init__.py", line 24, in <module> from rosidl_parser.parser import parse_idl_file File "/home/ryan/Development/ros2_rolling/install/rosidl_parser/lib/python3.11/site-packages/rosidl_parser/parser.py", line 20, in <module> from lark import Lark
(.rolling) ryan@ryan-B650-970:~/Development/nav2_ws/src/navigation2$ python3 -m pip list | grep lark lark 1.1.5
python -m colcon
This doesn't work because:
$ which colcon /usr/bin/colcon
Have you tried reinstalling colcon-core to your env?
I've removed the use of colcon
through apt and will now try through python instead.
Here's the latest progress of using venv
with Ubuntu 23 and ROS 2 humble:
https://github.com/Ryanf55/ros-on-lunar/blob/add-lunar-dockerfile/Dockerfile
So... is it recommended to use venv in ros2 development? ros2 document shows a way to use venv, but simply its not working....
python -m colcon
This doesn't work because:
$ which colcon /usr/bin/colcon
The purpose of using python -m colcon
is exactly that it doesn't invoke /usr/bin/colcon
. If you run colcon explicitly through your virtual env interpreter version then setuptools will use that one inside the generated console scripts instead of /usr/bin/python3
.
I'm not sure if it was mentioned above, but it also works to pip install colcon-common-extensions
into your virtualenv and make sure which colcon
points to that one. In both cases, the main limitation is that you have to have the virtualenv active when you build the workspace.
I have been facing same issue while building ros2 examples on pyenv virtual environment (colcon installed to pyenv pip) & ROS2 nightly build.
Applied the following work around.
#old
cmake_minimum_required(VERSION 3.5)
#new
cmake_minimum_required(VERSION 3.15) # this ensures find_package(Python3) to use <package_name>_ROOT
sift -inl --err-skip-line-length '/usr/lib/x86_64-linux-gnu/libpython3.10.so' /mnt/work/ros2-linux/|xargs -n1 sed -i 's|/usr/lib/x86_64-linux-gnu/libpython3.10.so|${Python3_LIBRARIES}|'
#old
find_package(Python3 REQUIRED COMPONENTS Interpreter)
#new
find_package(Python3 REQUIRED COMPONENTS Interpreter Development)
pyenv shell 3.10-dev
source /mnt/work/ros2-linux/setup.bash
colcon build --symlink-install --cmake-args ' -DPython3_ROOT_DIR=/home/user/.pyenv/versions/3.10-dev'
Try this solution:
[build_scripts]
executable = /usr/bin/env python3
ros2 run ....
, which will be able to identify the right virtual python environment and installed package in it.@123swk123
I think the issue is due to the --symlin-install
option.
@jjdengjj
It works for me without the --symlin-install
option. But not with the --symlin-install
option. Do you have a clue?
@hugoyvrn I didn't use --symlink-install flag. I believe the key issue is that without specify the executable as /usr/bin/env python3 in setup.cfg, the ros2 run will use the default python in the os system, which can only find the system wise package (including those ones installed with rosdep).
So far, my solution works fine on ros2 humble, and it is easy to debug those ros python codes in virtual environment with vscode.
Thank you @jjdengjj for your quick reply. I understood what you said, and it works fine for me.
But I do want to use the --symlink-install
flag. When I do, my python node runs on the default python, not in the virtual env as I expect.
Sorry but how can such a fundamental issue be 3 years old? Is this not applicant for all users, do we overlook sth? Are majority just install their packages on the plain machine? Are they just using rosdep?
I think the 'Installing via a virtual environment' section of https://docs.ros.org/en/jazzy/How-To-Guides/Using-Python-Packages.html should be removed or point to this issue to prevent wasted effort.
I am confused on best practices now to integrate an external/custom Python package with ROS2 code, specifically one that is not installable via package manager (apt/pip).
Is the only way forward to strip the package in to a module within a ROS2 node and maintain the standalone package/module version separately...? Any tips from others who have met this issue?
Dear maintainers, is there any plan to address this issue?
With Ubuntu24 + Jazzy (and therefore Python 3.12) it is not possible to pip install software outside of a virtualenv without "breaking system packages" as you know. This makes solving this issue pretty critical. Or am I missing something?
is there any plan to address this issue?
Yes and no. Yes, there is an open set of PRs that I need to get back to that will improve the situation.
However, it will probably not be possible to solve this in the general case. In particular, if you have a custom version of Python and/or pip packages installed that are compiled in a venv, that is pretty much fundamentally incompatible with ROS 2 binaries. It may possible to make that scenario work in a pure from-source build, which I'll look into when I open the documentation PR that corresponds to https://github.com/ros2/ros2/pull/1524
Dear maintainers, is there any plan to address this issue?
With Ubuntu24 + Jazzy (and therefore Python 3.12) it is not possible to pip install software outside of a virtualenv without "breaking system packages" as you know. This makes solving this issue pretty critical. Or am I missing something?
I’m currently facing this same issue (with the same setup), and all the proposed solutions seem to be more of a workaround than a robust solution. Why is it not possible to just specify the shebang in the Python scripts inside an ament_python
package and be done with it? I tried this approach, but the shebang seems to be ignored in ament_python
packages.
Using Python scripts in ament_cmake
packages with shebangs (#!/usr/bin/env python3
) inside virtual environments works seamlessly. However, in theory, ament_python
packages should be better suited for handling pure Python packages.
Considering that all Linux systems (and possibly other systems) have an environment variable pointing to a Python interpreter, it's strange that ROS simply ignores it and uses a predefined interpreter.
Bug report
I'm trying to use a python virtual environment in my colcon workspace to separate system level and node level dependencies. I'm following the instructions given in this tutorial in the ros2 documentation (Specifically installing via a virtual environment). However, when I check what python interpreter is being used inside the node, it returns the system level one instead of the virtual environment. This can be further verified by installing a package in the virtual environment that is not present in the system environment and try importing it from inside the node.
I have tried doing a clean build with and without sourcing the virtual environment in the build shell. I have also tried using virtualenv as in the tutorial and also python -m venv. I also call my virtual environment "venv" as in the tutorial.
Required Info:
Steps to reproduce issue
cd src && ros2 pkg create venv --build-type ament_python
venv.py
under src/venv/venv with the following codeclass ExampleNode(Node): def init(self): super().init('sensors') self.get_logger().info("ExampleNode started") self.get_logger().info(f"python path: {sys.executable}")
def main(args=None): rclpy.init(args=args) node = ExampleNode() rclpy.spin(node) rclpy.shutdown()
if name == 'main': main()
entry_points={ 'console_scripts': [ 'venv = venv.venv:main' ], },
source ./venv/bin/activate source /opt/ros/foxy/setup.bash colcon build source install/setup.sh