3

I'm using pyproject.toml and setup.cfg per PEP-517.

I have my setup.cfg as follows:

[metadata]
name = Package
version = 1.0.0

[options]
py_modules = ...
python_requires = >=3

I wish to limit the package to work only on CPython, as it solves an implementation-specific issue.

I've tried using the environment markers, but unfortunately they don't work on the python_requires field:

python_requires = >=3; implementation_name == "cpython"

Is there any way to achieve what I wish without resorting to the deprecated setup.py?

Bharel
  • 23,672
  • 5
  • 40
  • 80
  • you could try a hack like `install-requires=this-package-requires-cpython;implementation_name != "cpython"` – anthony sottile Jan 21 '21 at 19:06
  • Yeah I thought of using that hack. Don't like it though. I wonder if there's a real way to do it. – Bharel Jan 22 '21 at 01:40
  • If you are building a wheel, you can restrict the implementation in the compatibility tag, e.g. `python setup.py bdist_wheel --python-tag=cp3` will produce a `--cp3-none-any.whl` which will only be installed with CPython impl. For source dists, I'm afraid you will have to resort to manual checks in the `setup.py` script. – hoefling Jan 22 '21 at 11:01
  • @hoefling Thanks for the tip, but in order to use `bdist_wheel` I need still need a `setup.py` (which is part of your command line). I've tried running the build option using `pip wheel --build-option python-tag=cp3 .` but it seems to be unsupported for PEP 517 builds. I guess the answer is that it's just impossible for the time being. – Bharel Jan 22 '21 at 18:13
  • Ah my fault, not reading your question correctly. This is even easier to manage with `setup.cfg`; just add a `[bdist_wheel]` section with the `python-tag=cp3` entry. This would probably also solve the sdist case, if `setup.cfg` is included in the source dist and used for building wheel when `pip install`ing; not sure though as I don't know how to build an sdist from a PEP 517 declarative configuration. – hoefling Jan 22 '21 at 23:33
  • Ah ok, I found it - using [`build`](https://pypa-build.readthedocs.io/en/latest/), one can also build an sdist from a pure declarative build config; the `setup.cfg` is included and `pip install` from a source dist also works as expected. – hoefling Jan 22 '21 at 23:38
  • @hoefling Oh that's amazing! Exactly what I was looking for. How did you find any documentation about the `[bdist_wheel]` section? I've never gotten around that. Would you please add the documentation source or the way you found it together with your answer? I'd appreciate it. Post as an answer though so I can accept it :-) – Bharel Jan 23 '21 at 00:38
  • @hoefling To be honest I haven't even found the online documentation for the `python-tag` command. Am I missing something? – Bharel Jan 23 '21 at 00:56
  • Check out [my other answer](https://stackoverflow.com/a/52613394/2650249) for the link to the explanation on how to persist subcommand options in `setup.cfg`; you can add sections for any subcommand, not only `bdist_wheel`. As for the options themselves, this is where it gets hairy - the only way to check them that I know of is `python setup.py bdist_wheel --help` :-( proper docs are also missing on that matter. Glad I could help! Will add a proper answer tomorrow. – hoefling Jan 23 '21 at 01:29
  • You might also want to add the appropriate trove classifier: `Programming Language :: Python :: Implementation :: CPython`. It does not really make a difference, but maybe maybe someone out there relies on those classifiers. – sinoroc Jan 23 '21 at 18:18

1 Answers1

3

Unfortunately, you can't restrict the implementation via environment markers and the package metadata doesn't define any suitable field. However, the implementation can be restricted via the language implementation tag in wheel metadata; the format of the tag is defined in PEP 425. The CPython implementation is abbreviated with cp, python_requires = >=3 from your config implies cp3 for the full tag. Set the tag in a [bdist_wheel] section in setup.cfg:

[metadata]
...

[options]
...

[bdist_wheel]
python_tag=cp3

This is not special to bdist_wheel; any distutils subcommand can have a section in setup.cfg where one can persist its command line options. Read through Writing the Setup Configuration File for more details on that.

To answer your question from the comments:

To be honest I haven't even found the online documentation for the python-tag command. Am I missing something?

This is indeed somewhat hidden; wheel's docs don't provide a reference for the bdist_wheel's options. Usually, you list them via python setup.py bdist_wheel --help (just as with any other subcommand), but since you don't have the setup script, you can fake one:

$ python -c "from setuptools import setup; setup()" bdist_wheel --help
Options for 'bdist_wheel' command:
  ...
  --python-tag      Python implementation compatibility tag (default: 'py3')

A built wheel file will now have the cp3-none-any suffix (and the cp3-none-any tag in wheel metadata), and will be rejected by other implementations:

$ pypy3 -m pip install meowpkg-0.0.1-cp3-none-any.whl 
ERROR: meowpkg-0.0.1-cp3-none-any.whl is not a supported wheel on this platform.

This will also work with source dists since pip will always build a wheel from PEP 517-compliant sdists (and not resort to legacy setup.py install), so this is also safe to use with source dists. Example:

$ python -m build
$ pip uninstall -y wheel  # for testing only
WARNING: Skipping wheel as it is not installed.
$ pip install dist/meowpkg-0.0.1.tar.gz 
Processing ./dist/meowpkg-0.0.1.tar.gz
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
    Preparing wheel metadata ... done
Building wheels for collected packages: meowpkg
  Building wheel for meowpkg (PEP 517) ... done
  Created wheel for meowpkg: filename=meowpkg-0.0.1-cp3-none-any.whl size=1005 sha256=d87571afcdeda6be74a182b9e3e1ce6035a4aea4bb173c291900a85e53232983
  Stored in directory: /home/oleg.hoefling/.cache/pip/wheels/1a/8c/43/90d6b484adcf2515d25503b0c47f14565cadf0e891a597e23e
Successfully built meowpkg
Installing collected packages: meowpkg
  Attempting uninstall: meowpkg
    Found existing installation: meowpkg 0.0.1
    Uninstalling meowpkg-0.0.1:
      Successfully uninstalled meowpkg-0.0.1
Successfully installed meowpkg-0.0.1
hoefling
  • 59,418
  • 12
  • 147
  • 194