'How to get `setup.cfg` metadata at the command line (Python)
When you have a setup.py
file, you can get the name of the package via the command:
C:\some\dir>python setup.py --name
And this would print the name of the package to the command line.
In an attempt to adhere to best practice, I'm trying to migrate away from setup.py
by putting everything in setup.cfg
since everything that was previously in setup.py
was static content.
But our build pipeline depends on being able to call python setup.py --name
. I'm looking to rewrite the pipeline in such a way that I don't need to create a setup.py
file.
Is there way to get the name of the package when you have a setup.cfg
but not a setup.py
file?
Solution 1:[1]
Maybe using the ConfigParser Python module ?
python -c "from configparser import ConfigParser; cf = ConfigParser(); cf.read('setup.cfg'); print(cf['metadata']['name'])"
Solution 2:[2]
For an "over-kill" solution that allows getting any meta-data field from any PEP 517-compatible project (i.e. pyproject.toml
), with the help of the build
project:
#!/usr/bin/env python3
import argparse
import pathlib
import build.util
def _main():
args_parser = argparse.ArgumentParser()
args_parser.add_argument('path')
args = args_parser.parse_args()
path_name = getattr(args, 'path')
path = pathlib.Path(path_name)
#
metadata = build.util.project_wheel_metadata(path)
print(metadata)
if __name__ == '__main__':
_main()
This will actually call the build back-end (setuptools, poetry, flit, pdm, or watever), so this might take some seconds.
The build.util
API is documented here (on "latest") and it was added in "0.7.0 (16-09-2021)", in this change.
But yes, realistically, as you have already said it I would recommend just keeping a minimal setup.py
:
#!/usr/bin/env python3
import setuptools
setuptools.setup()
so that python setup.py --name
keeps working
And of course, as others have already said it, parsing is a viable and simple solution. setuptools uses ConfigParser
from the standard library to read the setup.cfg
file, so you can do it as well.
Solution 3:[3]
TL;DR, use the setuptools configuration API https://setuptools.pypa.io/en/latest/setuptools.html#configuration-api.
In your case, this line will give the name of the package:
python -c 'from setuptools.config import read_configuration as c; print(c("setup.cfg")["metadata"]["name"])'
Edit:
In setuptools v61.0.0 (24 Mar 2022) setuptools.config.read_configuration
was deprecated . Using the new API, the command becomes:
python -c 'from setuptools.config.setupcfg import read_configuration as c; print(c("setup.cfg")["metadata"]["name"])'
Explanation:
Setuptools exposes a read_configuration()
function for parsing metadata and options sections of the configuration. Internally, setuptools uses the configparser
module to parse the configuration file setup.cfg
. For simple str
-type data such as the "name" key, configparser can be used to read the data. However, setuptools also allows dynamic configuration using directives that cannot be directly parsed with configparser.
Here is an example that shows the difference between the two approaches for replacing python setup.py --version
:
$ tree .
.
??? my_package
? ??? __init__.py
??? pyproject.toml
??? setup.cfg
1 directory, 3 files
$ cat setup.cfg
[metadata]
name = my_package
version = attr:my_package.__version__
[options]
packages = find:
$ cat my_package/__init__.py
__version__ = "1.0.0"
$ cat pyproject.toml
$ python -c 'from setuptools.config import read_configuration as c; print(c("setup.cfg")["metadata"]["version"])'
1.0.0
$ python -c 'from configparser import ConfigParser; c = ConfigParser(); c.read("setup.cfg"); print(c["metadata"]["version"])'
attr:my_package.__version__
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Cubix48 |
Solution 2 | |
Solution 3 |