[feature] Packageable pip installable Python venv based utilities
See original GitHub issueDescription
What if Conan had the capability to capture/package pip installable python utilities (e.g. Sphinx) or thunked scripts and turn them into a package a project could build_requires for use during builds?
My coworker @puetzk has developed a couple nifty little utility packages that allows us to do just that.
Would there be any interest in adding first class support for such a capability in Conan? Maybe under conan.tools.* ?
It’s bending Conan’s packaging model a little, but the capability is powerful. Feel free to close the issue if it’s not in alignment with your project goals – totally understand.
But we’re doing something cool, if not a little outside the box, and I figured it’d be worth floating the concept to see what you think.
As always, thanks for all your hard work! Conan is now an integral part of our workflow. And everyone does an amazing job delivering such a high quality tool! Keep up the great work!
Motivation
One of the unforseen benefits of moving to Conan, has been the mandatory requirement that Python is now a first class prerequisite for most of our C++ projects. This actually gives us greater flexibility in developing build and other utility scripts in Python (instead of bash or bat) for use throughout our build process.
But sometimes utility scripts depend on other pip packages, etc. How do we share utility scripts and make sure everyone has the right packages installed?
Our solution was to leverage Python virtual environments and package them with Conan.
We started by developing a Python venv generator, that would install any pip installable script as a python venv inside your build folder using the same version of Python Conan was using – that way we could ensure you had a Python environment capable of running our utility script.
But this was a little inefficient. It meant that if you had multiple projects depending on the same “python-*” venv utility, you’d install the same utility into multiple build folders. Totally works, but is a little bit heavy.
Is there a way to better leverage Conan to avoid re-creating these packages?
The bit of a “hack” we settled on, was making these Python venv based utility packages to have a build_policy="missing". That way the package was created once, and lives in your Conan cache. Packages binaries are never uploaded / shared, but are built once, locally, on a given developer’s machine and can then be re-used across projects.
- Pros ✔️ Easy create a package from a pip installable library or tool ✔️ Easy to create a package from a python utility script (for problems that can’t easily be solved in CMake)
- Cons ❌ Package binaries can’t be uploaded because it depends on creating a Python venv locally in your build cache. ❌ Obviously, uninstalling Python (perhaps because you’re upgrading to a newer version), could break existing venvs packages sitting in your package cache built against an older version.
But for us, the benefits far outweighed the cons.
We’ve developed python packages for Sphinx, for processing a custom InnoSetup style template (git ignore style pattern matching for matching Conan dependencies and creating InnoSetup install rules), generating WinSparkle style appcast snippets (including DSA signature checks over our binaries, etc.). If you can write it in Python, you can get at it from Conan.
And again, each of these utility scripts likely depends on a variety of Python packages/libraries that need pip installed, but these venv packages handle all the dependency mess in a convenient way.
Example
For example, my project uses Sphinx to build our documentation.
In my conanfile.py, I have the following:
build_requires = (
...
"python-sphinx/3.2.1@user/channel",
...
)
And our package has a Modules/python-sphinx-config.cmake, which helps CMake find sphinx-build relative to its package_folder.
cmake_minimum_required(VERSION 3.12)
if(NOT TARGET python3::sphinx-build)
add_executable(python3::sphinx-build IMPORTED)
set_target_properties(python3::sphinx-build PROPERTIES
IMPORTED_LOCATION "${CMAKE_CURRENT_LIST_DIR}/../bin/sphinx-build.exe"
)
endif()
if(NOT TARGET python3::sphinx-apidoc)
add_executable(python3::sphinx-apidoc IMPORTED)
set_target_properties(python3::sphinx-apidoc PROPERTIES
IMPORTED_LOCATION "${CMAKE_CURRENT_LIST_DIR}/../bin/sphinx-apidoc.exe"
)
endif()
if(NOT TARGET python3::sphinx-autogen)
add_executable(python3::sphinx-autogen IMPORTED)
set_target_properties(python3::sphinx-autogen PROPERTIES
IMPORTED_LOCATION "${CMAKE_CURRENT_LIST_DIR}/../bin/sphinx-autogen.exe"
)
endif()
if(NOT TARGET python3::sphinx-quickstart)
add_executable(python3::sphinx-quickstart IMPORTED)
set_target_properties(python3::sphinx-quickstart PROPERTIES
IMPORTED_LOCATION "${CMAKE_CURRENT_LIST_DIR}/../bin/sphinx-quickstart.exe"
)
endif()
So that way from my CMakeLists.txt, I can reference the target python3::sphinx-build in custom commands, etc. to build my documentation.
add_custom_command(
...
COMMAND python3::sphinx-build # ${python3::sphinx-build}
${_args_SOURCEDIR}
...
)
No need to install sphinx manually. I just add the conan package reference. And everything “magically” works.
- I’ve read the CONTRIBUTING guide.
Issue Analytics
- State:
- Created 3 years ago
- Comments:11 (11 by maintainers)

Top Related StackOverflow Question
I’m not sure that this should be the concern of python facilities at this level of abstraction within conan. In order to deal with that, we would need to essentially write a recipe for each individual python package, or around something like pipenv.
Even so, it is still possible to ensure reproducibility with tools like
pip-tools. Specifically,pip-compilecan be used to resolve the dependency tree for a list of high level dependencies specified in arequirements.infile, and generate arequirements.txtfile. The output of a tool like this is sorted alphabetically, so when used with thepython-virtualenvpackage I developed an exemplar for above, you can do something like this:Because all the versions are pinned (even hashed if you want OS independence), and it’s alphabetical, you can have confidence that the json string that’s being generated here will only vary if there’s a meaningful change to
requirements.txt, and get a reasonably reproducible environment. It’s a soft guarantee and certainly well within the domain of good user behaviour, though.I think that this is probably resolved by part of the refactor I did, which was to utilise
python_requiresto share the key functional classes around, and would also be resolved if these facilities were merged into the conan codebase.Yeah, I think this is just a danger associated with upgrading python and using virtualenvs generally. Again, I think that this should probably be outside of the consideration of conan. That is, and I haven’t looked into this, unless there’s a way of building a python interpreter using conan - is that something that the cpython recipe provides? That would help us gain some separation from any system installation.
@samuel-emrys and @memsharded , I’ve got an example repo setup here to illustrate our approach to having conan packageable pip venv based utilities: https://github.com/thorntonryan/conan-pyvenv
It requires CMake and Ninja and I’ve only tested it with MSVC compiler
But I think the project is simple enough to illustrate the point of our approach
We haven’t moved to the new
cmake_find_packagegenerator, so forgive the use of the oldcmakegenerator. I’ll need to figure out why the new generator doesn’t work with the packaged / supporting CMake files.