Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Install Python metadata through pip #8

Merged
merged 33 commits into from
Nov 4, 2021

Conversation

diegoferigo
Copy link
Contributor

@diegoferigo diegoferigo commented Oct 18, 2021

Checklist

  • Used a personal fork of the feedstock to propose changes
  • Bumped the build number (if the version is unchanged)
  • Reset the build number to 0 (if the version changed)
  • Re-rendered with the latest conda-smithy (Use the phrase @conda-forge-admin, please rerender in a comment in this PR for automated rerendering)
  • Ensured the license file is being packaged.

Requires robotology/idyntree#922 and conda-forge/staged-recipes#16572. cc @traversaro

@conda-forge-linter
Copy link

Hi! This is the friendly automated conda-forge-linting service.

I just wanted to let you know that I linted all conda-recipes in your PR (recipe) and found it was in an excellent condition.

@diegoferigo
Copy link
Contributor Author

@conda-forge-admin please rerender

@traversaro
Copy link
Contributor

Requires robotology/idyntree#922 and conda-forge/staged-recipes#16572. cc @traversaro

While we wait for those PRs to go through, can you explain the rationale for this change? From what I understand we are mixing Python bindings compiled with setup.py and the rest of iDynTree libraries compiled via CMake, with no mechanism in place to make sure that the same CMake options are set to both builds.

@diegoferigo
Copy link
Contributor Author

diegoferigo commented Oct 18, 2021

Requires robotology/idyntree#922 and conda-forge/staged-recipes#16572. cc @traversaro

While we wait for those PRs to go through, can you explain the rationale for this change? From what I understand we are mixing Python bindings compiled with setup.py and the rest of iDynTree libraries compiled via CMake, with no mechanism in place to make sure that the same CMake options are set to both builds.

Rationale:

  • Have a 1:1 match between what is deployed to PyPI and what is distributed through conda-forge.
  • The setup.py file becomes the entrypoint for both PyPI and conda-forge to enable / disable features.
  • If needed, the python files can become a subpackage and passing through this new method would be simpler to maintain.
  • The idyntree Python package metadata gets included in the idyntree conda-forge package, meaning that pip list would show that idyntree is installed and can be imported.
  • If the user installs with pip a package from PyPI that has idyntree as its dependency, the files already part of the environment but now tracked by pip will get no longer overridden.

@traversaro
Copy link
Contributor

The setup.py file becomes the entrypoint for both PyPI and conda-forge to enable / disable features.

That was the part I was afraid of. To enable/disable features in conda-forge we have the options listed in the bld.bat/build.sh . I am a bit afraid that if we duplicate those options in yet another place (that my the way is not part of the recipe, so it can easily change without being clear in the version bump PR) this may lead to inconsistencies.

  • The idyntree Python package metadata gets included in the idyntree conda-forge package, meaning that pip list would show that idyntree is installed and can be imported.
  • If the user installs with pip a package from PyPI that has idyntree as its dependency, the files already part of the environment but now tracked by pip will get no longer overridden.

That seems the interesting feature we are looking for. If I understand well, this can be implemented simply by having something in ${SP_DIR}/idyntree-<version>.dist-info/METADATA file, where most of that METADATA is already in https://github.com/robotology/idyntree/blob/c2010240a1d56fe01e1be5ab20e3b16bcc568856/setup.py#L15 . Do you know if there is a way for generate just the METADATA that we need from setup.py, without the need to re-compile all the library?

@traversaro
Copy link
Contributor

Some pointers for future reference:

@traversaro
Copy link
Contributor

Related PR: conda-forge/nlopt-feedstock#37 (even if perhaps not ideal as it just installs an empty METADATA file, not fully compliant to https://packaging.python.org/specifications/recording-installed-packages/ and https://packaging.python.org/specifications/core-metadata/#core-metadata where at least a non-empty METADATA with the Metadata-Version, Name and Version fiels are required).

@diegoferigo
Copy link
Contributor Author

The setup.py file becomes the entrypoint for both PyPI and conda-forge to enable / disable features.

That was the part I was afraid of. To enable/disable features in conda-forge we have the options listed in the bld.bat/build.sh . I am a bit afraid that if we duplicate those options in yet another place (that my the way is not part of the recipe, so it can easily change without being clear in the version bump PR) this may lead to inconsistencies.

Yep I totally understand the duplication concern, but I want to bring two more points to your attention because this change imo goes in the direction of simplifying rather the duplicating:

  • Having a 1:1 feature match between PyPI and conda-forge is fundamental to have Python code (bindings in this way) that provide the same number of features, making all downstream projects compatible regardless of the mean of installation. The simplest way is for conda-forge to pass through setuptools (instead of the other way around). Currently, setup.py contains the default CMake configuration used to package for PyPI, however diegoferigo/cmake-build-extension allows to override them from the command line, as done in this PR for BUILD_SHARED_LIBRARIES. This means that 1) we start with the same features of PyPI and 2) if we need to modify / add features, we can do it in the build.* scripts as it already happens right now. This way, we don't have to mind in most cases to keep aligned the cmake options used for Python because they are already specified in setup.py.
  • Passing through pip or pypa/build would be in any case necessary in the case where other Python resources that are not generated by CMake are involved. And I'm thinking of a possible future high-level Python wrappers of iDynTree classes, or similar. I think that passing through these tools would make the recipe more generic and consistent.
  • The idyntree Python package metadata gets included in the idyntree conda-forge package, meaning that pip list would show that idyntree is installed and can be imported.
  • If the user installs with pip a package from PyPI that has idyntree as its dependency, the files already part of the environment but now tracked by pip will get no longer overridden.

That seems the interesting feature we are looking for. If I understand well, this can be implemented simply by having something in ${SP_DIR}/idyntree-<version>.dist-info/METADATA file, where most of that METADATA is already in https://github.com/robotology/idyntree/blob/c2010240a1d56fe01e1be5ab20e3b16bcc568856/setup.py#L15 . Do you know if there is a way for generate just the METADATA that we need from setup.py, without the need to re-compile all the library?

This, with also the other resources you linked in later comments, is another possibility. Though, this would mean adding new logic to the recipe to automatically generate this file, which is already done for us by pip or pypa/build (maybe there's a python function somewhere that takes the setup.cfg and produces the metadata). This being said, although this seems a good option, if I were the maintainer I would prefer going towards this PR, but any solution like the autogeneration of METADATA would work.


As discussed f2f, a problem you raised is how to handle the automatic generation of the PyPI version since it's done from the git archive, and the github release tarball does not have git metadata. In this case, I think that a single sed like that writes to setup.py|cfg the conda-forge version would suffice as a workaround. Though, again, the automatic generation of METADATA has a similar complexity.

@diegoferigo
Copy link
Contributor Author

Update: you can generate the METADATA passing through setup.py:

idyntree on  feature/python_cmake_component via △ v3.21.3 via 🐍 v3.8.10 🅒 /conda  
❯ python setup.py dist_info
running dist_info
writing idyntree.egg-info/PKG-INFO
writing dependency_links to idyntree.egg-info/dependency_links.txt
writing requirements to idyntree.egg-info/requires.txt
writing top-level names to idyntree.egg-info/top_level.txt
adding license file 'LICENSE.LGPL2'
adding license file 'LICENSE.LGPL3'
writing manifest file 'idyntree.egg-info/SOURCES.txt'
creating '/home/dferigo/git/idyntree/idyntree.dist-info'
adding license file "LICENSE.LGPL3" (matched pattern "LICEN[CS]E*")
adding license file "LICENSE.LGPL2" (matched pattern "LICEN[CS]E*")

idyntree on  feature/python_cmake_component via △ v3.21.3 via 🐍 v3.8.10 🅒 /conda  
❯ ls idyntree.dist-info/
LICENSE.LGPL2  LICENSE.LGPL3  METADATA  top_level.txt

@diegoferigo
Copy link
Contributor Author

diegoferigo commented Oct 19, 2021

If your concern is to keep the CMake options consistent, I just realized that I can update this PR as follows:

  1. Revert back to building with CMake the entire project, Python bindings included.
  2. Use setup.py without any CMakeExtension by passing --no-cmake-extension=all option. It would install only the metadata without the need to do it manually, avoiding possible mistakes of operating in low-level.
  3. This still needs the workaround to store the right version in setup.py|cfg, but it is fairly easy to do.

This seems the best trade off to keep a small complexity while preventing ABI-related surprises. What do you think?

Conda build output
[...]
running bdist_wheel
running build
running build_ext
installing to build/bdist.linux-x86_64/wheel
running install
running install_lib
warning: install_lib: 'build/lib.linux-x86_64-3.8' does not exist -- no Python modules to install

running install_egg_info
running egg_info
creating idyntree.egg-info
writing idyntree.egg-info/PKG-INFO
writing dependency_links to idyntree.egg-info/dependency_links.txt
writing entry points to idyntree.egg-info/entry_points.txt
writing requirements to idyntree.egg-info/requires.txt
writing top-level names to idyntree.egg-info/top_level.txt
writing manifest file 'idyntree.egg-info/SOURCES.txt'
adding license file 'LICENSE.LGPL2'
adding license file 'LICENSE.LGPL3'
writing manifest file 'idyntree.egg-info/SOURCES.txt'
Copying idyntree.egg-info to build/bdist.linux-x86_64/wheel/idyntree-4.1.1.dev21-py3.8.egg-info
running install_scripts
adding license file "LICENSE.LGPL2" (matched pattern "LICEN[CS]E*")
adding license file "LICENSE.LGPL3" (matched pattern "LICEN[CS]E*")
creating build/bdist.linux-x86_64/wheel/idyntree-4.1.1.dev21.dist-info/WHEEL
creating '$SRC_DIR/dist/tmp79b2g2ia/idyntree-4.1.1.dev21-cp38-cp38-linux_x86_64.whl' and adding 'build/bdist.linux-x86_64/wheel' to it
adding 'idyntree-4.1.1.dev21.dist-info/LICENSE.LGPL2'
adding 'idyntree-4.1.1.dev21.dist-info/LICENSE.LGPL3'
adding 'idyntree-4.1.1.dev21.dist-info/METADATA'
adding 'idyntree-4.1.1.dev21.dist-info/WHEEL'
adding 'idyntree-4.1.1.dev21.dist-info/entry_points.txt'
adding 'idyntree-4.1.1.dev21.dist-info/top_level.txt'
adding 'idyntree-4.1.1.dev21.dist-info/RECORD'
removing build/bdist.linux-x86_64/wheel
* Building wheel...
Successfully built idyntree-4.1.1.dev21-cp38-cp38-linux_x86_64.whl
Processing ./dist/idyntree-4.1.1.dev21-cp38-cp38-linux_x86_64.whl
Installing collected packages: idyntree
Successfully installed idyntree-4.1.1.dev21

Resource usage statistics from building idyntree:
   Process count: 43
   CPU time: Sys=0:00:22.3, User=0:08:52.2
   Memory: 3.1G
   Disk usage: 500.0K
   Time elapsed: 0:02:38.0

@traversaro
Copy link
Contributor

traversaro commented Oct 19, 2021

This seems the best trade off to keep a small complexity while preventing ABI-related surprises. What do you think?

I think that is by far the best option! We also would not need a iDynTree new release.

@diegoferigo
Copy link
Contributor Author

This seems the best trade off to keep a small complexity while preventing ABI-related surprises. What do you think?

I think that is by far the best option! We also would not need a iDynTree new release.

A new release should not be needed. I just pushed the first attempt of this solution, however this will work only in master since in devel we refactored the python files and we need to move the version workaround from setup.py to setup.cfg. Let's remember as soon as we do a new idyntree release.

@diegoferigo
Copy link
Contributor Author

@conda-forge-admin please rerender

@github-actions
Copy link
Contributor

Hi! This is the friendly automated conda-forge-webservice.
I tried to rerender for you, but it looks like there was nothing to do.

@diegoferigo
Copy link
Contributor Author

diegoferigo commented Oct 19, 2021

Now linux and macOS seems happy, windows instead stills fail very likely because I made mistakes in the bat script, I'm not too familiar with that environment.

@traversaro
Copy link
Contributor

I guess you do not need to escape the last line of the pip command.

@traversaro
Copy link
Contributor

I see that arm64 also failed due to missing diffutils. This is more problematic as with all the NVIDIA SOC that we are starting to use on the robots, I wanted to make sure that idyntree arm64 binaries are readily available if we need them.

@traversaro
Copy link
Contributor

I see that arm64 also failed due to missing diffutils. This is more problematic as with all the NVIDIA SOC that we are starting to use on the robots, I wanted to make sure that idyntree arm64 binaries are readily available if we need them.

Hopefully it will be fixed by conda-forge/conda-forge-pinning-feedstock#2046 .

- restore modified files before finishing
- let pip find the wheel without specifying the name of the file
it returns 0 only if there's no diff
@diegoferigo diegoferigo changed the title Install Python resources through pip Install Python metadata through pip Oct 21, 2021
@diegoferigo
Copy link
Contributor Author

diegoferigo commented Oct 21, 2021

@traversaro I managed to fix also the windows builds, if you want to make a more thorough review I think I'm mostly done now. No prob if you want to wait the finalization of the diffutils migration before merging.

@traversaro
Copy link
Contributor

@traversaro I managed to fix also the windows builds, if you want to make a more thorough review I think I'm mostly done now. No prob if you want to wait the finalization of the diffutils migration before merging.

Great! Yes, thanks, I would prefer for conda-forge/diffutils-feedstock#4 to be merged to verify that CI for aarch64 is working before merging.

@traversaro traversaro closed this Nov 4, 2021
@traversaro traversaro reopened this Nov 4, 2021
@traversaro
Copy link
Contributor

@conda-forge-admin, please rerender

@traversaro
Copy link
Contributor

I switched to cross-compilation to workaround conda-forge/status#122 .

@traversaro
Copy link
Contributor

Cross-compilation has problems described in https://github.com/conda-forge/conda-smithy/issues/1539 .

@traversaro
Copy link
Contributor

@conda-forge-admin, please rerender

@github-actions
Copy link
Contributor

github-actions bot commented Nov 4, 2021

Hi! This is the friendly automated conda-forge-webservice.
I tried to rerender for you but ran into some issues, please ping conda-forge/core
for further assistance. You can also try re-rendering locally.

@traversaro
Copy link
Contributor

@conda-forge-admin, please rerender

@github-actions
Copy link
Contributor

github-actions bot commented Nov 4, 2021

Hi! This is the friendly automated conda-forge-webservice.
I tried to rerender for you but ran into some issues, please ping conda-forge/core
for further assistance. You can also try re-rendering locally.

@traversaro
Copy link
Contributor

@conda-forge-admin, please rerender

@traversaro traversaro added the automerge Merge the PR when CI passes label Nov 4, 2021
@github-actions github-actions bot merged commit 748c0f7 into conda-forge:master Nov 4, 2021
@github-actions
Copy link
Contributor

github-actions bot commented Nov 4, 2021

Hi! This is the friendly conda-forge automerge bot!

I considered the following status checks when analyzing this PR:

  • linter: passed
  • azure: passed

Thus the PR was passing and merged! Have a great day!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
automerge Merge the PR when CI passes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants