Core metadata specification documents the metadata field Requires-External which seems to be for specifying system (non-python) dependencies.
How do you actually specify this field though? This is what I've tried:
.
├── mypackage
│ └── __init__.py
└── setup.py
Contents of setup.py
from setuptools import setup
setup(
name="mypackage",
description="blah blah",
url='https://example.org',
version="0.1",
packages=["mypackage"],
requires_external=[
"C",
"libpng (>=1.5)",
'make; sys_platform != "win32"',
],
)
When I build this package, that metadata was not included
Metadata-Version: 2.1
Name: mypackage
Version: 0.1
Summary: blah blah
Home-page: https://example.org
License: UNKNOWN
Platform: UNKNOWN
UNKNOWN
So what is the syntax to pass Requires-External to setuptools/distutils? Note: this question is not asking about Requires-Dist metadata.
So what is the syntax to pass Requires-External to setuptools/distutils?
There is none by default, as neither distutils
nor setuptools
support the field. Also, requires_external
keyword arg is not supported as well - it is silently ignored, just as any other unknown keyword arg.
To add local support for requires_external
kwarg, you need to provide your own distribution implementation. Minimal example (requires Python 3.9):
from setuptools.dist import Distribution as DistributionOrig
class Distribution(DistributionOrig):
_DISTUTILS_UNSUPPORTED_METADATA = DistributionOrig._DISTUTILS_UNSUPPORTED_METADATA | {'requires_external': dict}
You can now pass requires_external
to setup()
when paired with distclass
:
setup(
...,
requires_external=[
'C',
'libpng (>=1.5)',
'make; sys_platform != "win32"',
],
distclass=Distribution,
)
The next goal is to actually write the contents of requires_external
to PKG-INFO
. This is quite tricky to do via distribution metadata itself because setuptools
patches the relevant methods (DistributionMetadata.read_pkg_file()
and DistributionMetadata.write_pkg_file()
) with own monolithic impls. The easiest way for this IMO is to modify PKG-INFO
post factum via a custom egg_info
impl:
import email
from pathlib import Path
from setuptools.command.egg_info import egg_info as egg_info_orig
class egg_info(egg_info_orig):
def run(self):
super().run()
# PKG-INFO is now guaranteed to exist
pkg_info_file = Path(self.egg_info, 'PKG-INFO')
pkg_info = email.message_from_bytes(pkg_info_file.read_bytes())
for req in self.distribution.metadata.requires_external:
pkg_info.add_header('Requires-External', req)
pkg_info_file.write_bytes(pkg_info.as_bytes())
Pass your own egg_info
impl via cmdclass
argument in setup()
:
setup(
...,
requires_external=[
'C',
'libpng (>=1.5)',
'make; sys_platform != "win32"',
],
distclass=Distribution,
cmdclass={'egg_info': egg_info},
)