pip: Config settings support in PEP 517
PEP 517 provides a method, config settings, for supplying arbitrary configuration to a build backend. There are no defined semantics for this argument, although there is an example in the PEP showing how pip “might” map command line arguments onto config_settings
.
The setuptools backend appears to implement a part of this suggested interface (it processes a --global-option
key in essentially the way the PEP implies). The flit backend completely ignores config_settings
.
Pip needs a user interface (command line options) to allow users to supply config settings to a backend - but without any agreed semantics, there’s probably not much we can do beyond allowing users to specify key/value pairs. It’s possible that PEP 518 (or some similar standard) should be extended to allow projects to specify config_settings
in the project build metadata?
Finally, there’s pip’s --python-tag
option. This currently maps directly to a specific setuptools command line option. Due to the lack of common semantics, there’s currently no way to support this under PEP 517 in a backend-neutral way. It may be worth (for the fallback use of the setuptools backend only? as a “better than nothing” approach for all backends?) mapping it to
config_settings = {'--global-option': ['--python-tag', python_tag]}
So, actions to consider:
- Standardising any semantics for
config_settings
(my view: out of scope for pip) - Letting projects specify config settings in pyproject.toml (my view: needs a standard, out of scope for pip)
- Command line interface for
config_settings
(my view: a minimal--build-settings key:value
for now) - Config settings in
requirements.txt
(my view: allow--build-settings
in there) --python-tag
(my view: translate to--global-option
for now, review later)
Also, apart from the short-term approach for --python-tag
, I propose not implementing any of this until after base PEP 517 support is released. Without more comprehensive buy in from backends, it’s hard to see what form config_settings
usage will ultimately take, and it’s backends that should drive this, not frontends.
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 5
- Comments: 16 (14 by maintainers)
Links to this issue
Commits related to this issue
- drop '--build-ext' option in setup.py for env var This option to build the C extension is only used in the wheel building process. cibuildwheel does not appear to support an ability to pass options t... — committed to darshan-hpc/darshan by shanedsnyder 2 years ago
- MAINT, CI: cibuildwheel support (#741) * pyproject.toml updates to support cibuildwheel * drop '--build-ext' option in setup.py for env var This option to build the C extension is only used in ... — committed to darshan-hpc/darshan by shanedsnyder 2 years ago
I just stumbled upon this issue when I tried to pass some extra arguments to the setuptools backend. It took a while until I released that the config settings have not been implemented at all in pip.
When passing
--build-option
pip will stop processing.https://github.com/pypa/pip/blob/master/src/pip/_internal/operations/build/wheel.py#L27..L31
Anything passed in
--global-option
is silently dropped later on in the process:https://github.com/pypa/pip/blob/master/src/pip/_internal/wheel_builder.py#L191..L206
Is there a specific reason why
build_options
andglobal_options
is not passed on as suggested in the PEP? Are you waiting for a more complete design?Potentially, the documentation could be expanded as well. It still reads as if
--build-option
and--global-option
have the effects described in the PEP.https://github.com/pypa/pip/blob/master/docs/html/reference/pip_wheel.rst#customising-the-build
On a related note, the new config UI should probably be designed to still allow installing wheels of PEP 518 build dependencies (?).
As for my use case: I have a Cython project and have implemented an extra command to transpile the
.pyx
sources to the.cpp
outputs. Performing this operation in the isolated build environment simplifies the build process - it’s onepip wheel
call. It also avoids another tool for dependency management during building, as the Cython dependency is declared throughbuild-system/requires
.That makes sense to me. I’m happy to do this in place of my original proposal, and treat unsetting a key as YAGNI (for now at least).
As far as I can tell,
--install-options
is for install, and--build-options
is for pip wheel, but I didn’t look very closely into the details (as my proposal is effectively to treat them as legacy and disable them if the new option is specified).I don’t intend that it does. I would expect that the settings would be used if a PEP 517 hook is called, but would not change the decision as to whether to call one. If you want to ensure building from source, you should use
--no-binary
.This means that specifying config settings might do nothing, and could end up using a wheel built with different settings. My view is that’s a rare enough situation that I don’t want to worry about it for now. After all, there’s nothing in a built wheel to say what config settings were used, so there’s nothing we could do about it anyway[^1]. On the same principle, I don’t intend to try to warn if config settings get ignored (that is possible, but would require adding checks to a bunch of code paths that don’t currently need to care about config settings). Basically, if you want to be sure, use
--no-binary
, otherwise settings will be used if needed, ignored otherwise. We can revisit this choice later, based on real-life experience. But for now I expect use of config settings to be so rare as to make taking anything other than the easiest choices a waste of effort.[^1]: I personally think that two wheels built with different config settings probably have to be functionally identical anyway - there’s nothing explicit to that effect in any specs I can find, but I’d expect any backend that did make them different would break far too many assumptions to be useful.
I’m looking at (finally) implementing this functionality, at least in part in anticipation of the setuptools PEP 660 support having two modes which the user could select via a config option.
Reviewing the discussion here, what I propose is as follows:
--config-settings
, to the install and wheel commands. The existing--(build|install)-options
flags are only for those commands.--global-options
also applies to download, but I’m going to say YAGNI on that (for now, at least).--config-settings
in a requirements file.--config-settings
is specified, all of--(build|install|global)-options
will be ignored with a warning.--config-settings KEY=VALUE
. This can be repeated multiple times, with later values overriding earlier ones if KEY is the same. Note that PEP 517 states that frontends only need to be able to provide string valued keys and values. So I’m dismissing the idea of letting values be arbitrary JSON, or having special syntax for boolean-valued settings.--config-settings KEY=
will remove KEY from the config dictionary. May be useful for overriding settings froma config file, but I’d happily drop this (in favour of just setting the value to “” following point 3) if anyone said YAGNI.In general, behaviour will follow
--(build|install)-options
.I’d appreciate comments on the design, and on the feasibility of the proposal. However if anyone wants to propose something more complex (such as per-call settings as per item 6, or per-package settings as per 7) then please be prepared to suggest a modified syntax that covers it. The reason I’m keeping things simple is precisely because I don’t know how to make a good UI for more complicated possibilities, so saying “you need to cover X” without explaining how, will probably just result in this getting stalled.
Also, if backend developers want to suggest constraints or features that they need, I’d appreciate such suggestions coming with a proposed syntax (same reason).
/cc @abravalheri for views on whether this will work for setuptools.
That aforementioned PR has landed. 😃
It’s not hard to add an alias, but I’m reluctant to use up a 1-character option for something this uncommon. I suggest not doing so initially, and if users complain that it’s too verbose, we can add an abbreviation later.
That’s essentially down to your shell’s (plus the C runtime’s on Windows), quoting rules, but basically yes:
should work pretty well everywhere. Single quotes, or just quoting the value rather than the whole
OPTION=VALUE
, would be less portable[^1]. For ease of use I’d tend to recommend that config setting names and values avoid spaces or punctuation characters, but that’s just my personal view.[^1]: I’d briefly considered allowing the user to specify config settings via JSON, but correctly quoting JSON on the command line in Powershell is a pain, so I dropped the idea as a bad UI.
What about:
--config-setting=pkg:{"setting1": "value1"}
? That is:and we can accept it multiple times.
This gives us a few nice properties:
__global__
or*
){
). This would let us support a shorter syntax in requirements files or simple command-lines without ambiguity, likepkg --config-setting={"setting1": "value1"}
\uXXXX
), which may be useful since ensuring the terminal properly accepts (and apps properly read) unicode input may be a challenge on some platforms or environmentsThere are also a few downsides:
\n
in an argument for example, we could get when the user intendedThis could be mitigated by only supporting
--config-setting
in requirements files.A few other things to consider, in general:
If implemented this would give us a route to deprecate and remove the special cases we have for
--install-option
,--build-option
, and--global-option
in several places in the code. It is blocked on pypa/setuptools#1928, though, since the way the setuptools backend interprets the options is not currently compatible with the way we do. This also gives us a path to address #2677.