Summary
Running pip wheel --global-option ARG calls setup.py ARG bdist_wheel, but running setuptools.build_meta.build_wheel(config_settings={"--global-option": ["ARG"]}) calls setup.py bdist_wheel ARG! Can we make pip and setuptools behave the same?
Details
setuptools.build_meta:__legacy__ (I will drop __legacy__ since it is just a wrapper around build_meta) supports the --global-option value in config_settings, but places it at a different location in constructed setup.py invocations than pip does. pip supports a --build-option parameter for post-command args, which matches the current setuptools.build_meta --global-option behavior.
This can be shown with the following script
t.sh
#!/bin/sh
cd "$(mktemp -d)"
python -V
echo ============== Installing prereqs ==============
python -m venv env
./env/bin/python -m pip install --upgrade pip setuptools wheel pep517
./env/bin/python -m pip freeze --all
cat <<EOF > setup.py
import sys
from setuptools import setup
print(sys.argv)
setup(name="example")
EOF
echo ============== Running pip wheel ==============
./env/bin/python -m pip wheel \
--disable-pip-version-check \
--global-option --quiet \
--build-option --plat-name=foo \
-v .
cat <<EOF > pyproject.toml
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta:__legacy__"
EOF
# invoke backend directly because pip doesn't currently support
# `config_settings` (see pypa/pip#5771)
cat <<EOF > build.py
from pep517.envbuild import build_wheel
config_settings = {
"--global-option": ["--quiet"],
"--build-option": ["--plat-name=foo"],
}
build_wheel(".", ".", config_settings)
EOF
echo ============== Running setuptools.build_meta ==============
./env/bin/python build.py
Here is the output of the script on my machine (Ubuntu 18.04, Python 3.8.0)
Output
Python 3.8.0
============== Installing prereqs ==============
Collecting pip
Using cached https://files.pythonhosted.org/packages/00/b6/9cfa56b4081ad13874b0c6f96af8ce16cfbc1cb06bedf8e9164ce5551ec1/pip-19.3.1-py2.py3-none-any.whl
Collecting setuptools
Using cached https://files.pythonhosted.org/packages/54/28/c45d8b54c1339f9644b87663945e54a8503cfef59cf0f65b3ff5dd17cf64/setuptools-42.0.2-py2.py3-none-any.whl
Collecting wheel
Using cached https://files.pythonhosted.org/packages/00/83/b4a77d044e78ad1a45610eb88f745be2fd2c6d658f9798a15e384b7d57c9/wheel-0.33.6-py2.py3-none-any.whl
Collecting pep517
Using cached https://files.pythonhosted.org/packages/f4/9b/82910c0f01f29c7bdd8fc4306ed03e1742256612e2cfca8f05ebb21958ab/pep517-0.8.1-py2.py3-none-any.whl
Collecting toml (from pep517)
Using cached https://files.pythonhosted.org/packages/a2/12/ced7105d2de62fa7c8fb5fce92cc4ce66b57c95fb875e9318dba7f8c5db0/toml-0.10.0-py2.py3-none-any.whl
Installing collected packages: pip, setuptools, wheel, toml, pep517
Found existing installation: pip 19.2.3
Uninstalling pip-19.2.3:
Successfully uninstalled pip-19.2.3
Found existing installation: setuptools 41.2.0
Uninstalling setuptools-41.2.0:
Successfully uninstalled setuptools-41.2.0
Successfully installed pep517-0.8.1 pip-19.3.1 setuptools-42.0.2 toml-0.10.0 wheel-0.33.6
pep517==0.8.1
pip==19.3.1
setuptools==42.0.2
toml==0.10.0
wheel==0.33.6
============== Running pip wheel ==============
/tmp/user/1000/tmp.wXBXX6X4IO/env/lib/python3.8/site-packages/pip/_internal/commands/wheel.py:115: UserWarning: Disabling all use of wheels due to the use of --build-options / --global-options / --install-options.
cmdoptions.check_install_build_global(options)
Created temporary directory: /tmp/user/1000/pip-ephem-wheel-cache-prtj7mer
Created temporary directory: /tmp/user/1000/pip-req-tracker-9vt687l5
Created requirements tracker '/tmp/user/1000/pip-req-tracker-9vt687l5'
Created temporary directory: /tmp/user/1000/pip-wheel-2cug6fql
Processing /tmp/user/1000/tmp.wXBXX6X4IO
Created temporary directory: /tmp/user/1000/pip-req-build-ukgu7746
Added file:///tmp/user/1000/tmp.wXBXX6X4IO to build tracker '/tmp/user/1000/pip-req-tracker-9vt687l5'
Running setup.py (path:/tmp/user/1000/pip-req-build-ukgu7746/setup.py) egg_info for package from file:///tmp/user/1000/tmp.wXBXX6X4IO
Running command python setup.py egg_info
['/tmp/user/1000/pip-req-build-ukgu7746/setup.py', 'egg_info', '--egg-base', '/tmp/user/1000/pip-req-build-ukgu7746/pip-egg-info']
running egg_info
creating /tmp/user/1000/pip-req-build-ukgu7746/pip-egg-info/example.egg-info
writing /tmp/user/1000/pip-req-build-ukgu7746/pip-egg-info/example.egg-info/PKG-INFO
writing dependency_links to /tmp/user/1000/pip-req-build-ukgu7746/pip-egg-info/example.egg-info/dependency_links.txt
writing top-level names to /tmp/user/1000/pip-req-build-ukgu7746/pip-egg-info/example.egg-info/top_level.txt
writing manifest file '/tmp/user/1000/pip-req-build-ukgu7746/pip-egg-info/example.egg-info/SOURCES.txt'
reading manifest file '/tmp/user/1000/pip-req-build-ukgu7746/pip-egg-info/example.egg-info/SOURCES.txt'
writing manifest file '/tmp/user/1000/pip-req-build-ukgu7746/pip-egg-info/example.egg-info/SOURCES.txt'
Source in /tmp/user/1000/pip-req-build-ukgu7746 has version 0.0.0, which satisfies requirement example==0.0.0 from file:///tmp/user/1000/tmp.wXBXX6X4IO
Removed example==0.0.0 from file:///tmp/user/1000/tmp.wXBXX6X4IO from build tracker '/tmp/user/1000/pip-req-tracker-9vt687l5'
Building wheels for collected packages: example
Created temporary directory: /tmp/user/1000/pip-wheel-zvwa52k1
Building wheel for example (setup.py) ... Destination directory: /tmp/user/1000/pip-wheel-zvwa52k1
Running command /tmp/user/1000/tmp.wXBXX6X4IO/env/bin/python -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/user/1000/pip-req-build-ukgu7746/setup.py'"'"'; __file__='"'"'/tmp/user/1000/pip-req-build-ukgu7746/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' --quiet bdist_wheel -d /tmp/user/1000/pip-wheel-zvwa52k1 --plat-name=foo
['/tmp/user/1000/pip-req-build-ukgu7746/setup.py', '--quiet', 'bdist_wheel', '-d', '/tmp/user/1000/pip-wheel-zvwa52k1', '--plat-name=foo']
done
Created wheel for example: filename=example-0.0.0-py3-none-foo.whl size=991 sha256=2ba2632248ed833ce1744288e2b271aed52d917c9e5e513c1bca6ab86ae9b6c3
Stored in directory: /tmp/user/1000/tmp.wXBXX6X4IO
Successfully built example
Cleaning up...
Removing source in /tmp/user/1000/pip-req-build-ukgu7746
Removed build tracker '/tmp/user/1000/pip-req-tracker-9vt687l5'
============== Running setuptools.build_meta ==============
['/tmp/user/1000/tmp.wXBXX6X4IO/env/lib/python3.8/site-packages/pep517/_in_process.py', 'egg_info', '--quiet']
running egg_info
creating example.egg-info
writing example.egg-info/PKG-INFO
writing dependency_links to example.egg-info/dependency_links.txt
writing top-level names to example.egg-info/top_level.txt
writing manifest file 'example.egg-info/SOURCES.txt'
reading manifest file 'example.egg-info/SOURCES.txt'
writing manifest file 'example.egg-info/SOURCES.txt'
['/tmp/user/1000/tmp.wXBXX6X4IO/env/lib/python3.8/site-packages/pep517/_in_process.py', 'bdist_wheel', '--dist-dir', '/tmp/user/1000/tmp.wXBXX6X4IO/tmpdhxoqdx2', '--quiet']
running bdist_wheel
running build
installing to build/bdist.linux-x86_64/wheel
running install
running install_egg_info
running egg_info
writing example.egg-info/PKG-INFO
writing dependency_links to example.egg-info/dependency_links.txt
writing top-level names to example.egg-info/top_level.txt
reading manifest file 'example.egg-info/SOURCES.txt'
writing manifest file 'example.egg-info/SOURCES.txt'
Copying example.egg-info to build/bdist.linux-x86_64/wheel/example-0.0.0-py3.8.egg-info
running install_scripts
creating build/bdist.linux-x86_64/wheel/example-0.0.0.dist-info/WHEEL
creating '/tmp/user/1000/tmp.wXBXX6X4IO/tmpdhxoqdx2/example-0.0.0-py3-none-any.whl' and adding 'build/bdist.linux-x86_64/wheel' to it
adding 'example-0.0.0.dist-info/METADATA'
adding 'example-0.0.0.dist-info/WHEEL'
adding 'example-0.0.0.dist-info/top_level.txt'
adding 'example-0.0.0.dist-info/RECORD'
removing build/bdist.linux-x86_64/wheel
Note that with the pip invocations, the args are:
['/tmp/user/1000/pip-req-build-ukgu7746/setup.py', 'egg_info', '--egg-base', '/tmp/user/1000/pip-req-build-ukgu7746/pip-egg-info']
['/tmp/user/1000/pip-req-build-ukgu7746/setup.py', '--quiet', 'bdist_wheel', '-d', '/tmp/user/1000/pip-wheel-zvwa52k1', '--plat-name=foo']
whereas invoking setuptools.build_meta results in
['/tmp/user/1000/tmp.wXBXX6X4IO/env/lib/python3.8/site-packages/pep517/_in_process.py', 'egg_info', '--quiet']
['/tmp/user/1000/tmp.wXBXX6X4IO/env/lib/python3.8/site-packages/pep517/_in_process.py', 'bdist_wheel', '--dist-dir', '/tmp/user/1000/tmp.wXBXX6X4IO/tmpdhxoqdx2', '--quiet']
The differences:
passing --global-options to setup.py egg_info
pip doesn't do this - it is tracked by Add --global-option to egg_info command too pip#4383
setuptools.build_meta passes them after egg_info
passing --global-options to setup.py bdist_wheel
pip places them before bdist_wheel
setuptools.build_meta places them after bdist_wheel
passing --build-options to setup.py bdist_wheel
pip places them after bdist_wheel
setuptools.build_meta does not use this value
For where in code this is happening, see:
setuptools.build_meta here , where config_settings["--global-option"] comes after the command name
pip here and here , where we create the initial set of arguments followed by the name of the command followed by build_options
We would like to eventually transition away from having setuptools-specific code in pip by e.g. delegating to the legacy backend (pypa/pip#5204 ). In that context, can we discuss how to resolve these differences and pass the arguments to the backend appropriately?
Summary
Running
pip wheel --global-option ARGcallssetup.py ARG bdist_wheel, but runningsetuptools.build_meta.build_wheel(config_settings={"--global-option": ["ARG"]})callssetup.py bdist_wheel ARG! Can we make pip and setuptools behave the same?Details
setuptools.build_meta:__legacy__(I will drop__legacy__since it is just a wrapper aroundbuild_meta) supports the--global-optionvalue inconfig_settings, but places it at a different location in constructedsetup.pyinvocations than pip does. pip supports a--build-optionparameter for post-command args, which matches the currentsetuptools.build_meta--global-optionbehavior.This can be shown with the following script
t.sh
Here is the output of the script on my machine (Ubuntu 18.04, Python 3.8.0)
Output
Note that with the pip invocations, the args are:
whereas invoking
setuptools.build_metaresults inThe differences:
--global-options tosetup.py egg_infosetuptools.build_metapasses them afteregg_info--global-options tosetup.py bdist_wheelbdist_wheelsetuptools.build_metaplaces them afterbdist_wheel--build-options tosetup.py bdist_wheelbdist_wheelsetuptools.build_metadoes not use this valueFor where in code this is happening, see:
setuptools.build_metahere, whereconfig_settings["--global-option"]comes after the command namebuild_optionsWe would like to eventually transition away from having setuptools-specific code in pip by e.g. delegating to the legacy backend (pypa/pip#5204). In that context, can we discuss how to resolve these differences and pass the arguments to the backend appropriately?