Pip: Config settings support in PEP 517

Created on 8 Sep 2018  路  8Comments  路  Source: pypa/pip

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.

PEP implementation

All 8 comments

Command line interface for config_settings (my view: a minimal --build-settings key:value for now)

The config_settings is likely to be specific to a package, so we might want to directly provide: --build-settings package:key:value ?

I'm just going to go ahead and pin this, because we should really remember that this has to be done still.

I still don't think this is urgent. There's been little or no movement on backends making use of the config settings options, and essentially no demand from pip's end users. I'm inclined to think that it might have been better if PEP 517 hadn't included config_settings, treating it as YAGNI until genuine use cases came up.

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.

I'm inclined to think that it might have been better if PEP 517 hadn't included config_settings, treating it as YAGNI until genuine use cases came up.

Perhaps, but we've crossed that bridge now. :(

TBH, I don't think most users would discover that unimplemented functionality that is "only documented in a PEP", which could be the reason for the lack of end-user demand -- I don't know that I want something, if I don't know that thing exists.

What about: --config-setting=pkg:{"setting1": "value1"}? That is:

  • name of the project
  • a colon
  • a JSON object containing the config settings to be used for that package

and we can accept it multiple times.

This gives us a few nice properties:

  1. supports arbitrary keys/values without us needing to define a mini-language or escape characters
  2. values that are "invalid" package names can be used for communicating non-package-specific config settings (e.g. __global__ or *)
  3. PEP 517 currently states that frontends should provide a way for users to provide arbitrary string key and string value parameters, but if this is ever updated in the future to allow more complex nested structures then it will be straightforward to support it
  4. we can easily distinguish between a package being specified and not (whether the value starts with {). This would let us support a shorter syntax in requirements files or simple command-lines without ambiguity, like pkg --config-setting={"setting1": "value1"}
  5. using JSON gives us automatic support for unicode escapes (\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 environments

There are also a few downsides:

  1. JSON requires double-quotes, which on the Windows command-prompt will require being escaped (by putting them twice)
  2. Opportunity for usage errors on shells that support escape characters. If the shell expands \n in an argument for example, we could get
    {"setting1":"va lue1"}
    when the user intended
    {"setting1":"va\nlue1"}
  3. Requirements files, which don't do any of the above interpretation, may look different than the equivalent command-line on the user's platform

This could be mitigated by only supporting --config-setting in requirements files.

A few other things to consider, in general:

  1. using the config settings applicable to a project as part of our wheel cache key
  2. explicitly failing if config settings are provided but the resolved project doesn't use PEP 517
  3. explicitly failing if config settings are provided that do not match any given project (probably not a great idea, given conditional dependencies)
  4. normalizing the project name before comparing against resolved packages
  5. "config setting" may not be so meaningful to end users, so we should consider alternate argument names

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.

Is there a specific reason why build_options and global_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 one pip wheel call. It also avoids another tool for dependency management during building, as the Cython dependency is declared through build-system/requires.

@pskopnik I think it's a matter of designing + implementing the behavior in pip's implementation.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kkom picture kkom  路  3Comments

reynoldsnlp picture reynoldsnlp  路  3Comments

dmfigol picture dmfigol  路  3Comments

dstufft picture dstufft  路  3Comments

therefromhere picture therefromhere  路  3Comments