Configuring setuptools using setup.cfg files#

Note

New in 30.3.0 (8 Dec 2016).

Important

If compatibility with legacy builds (i.e. those not using the PEP 517 build API) is desired, a setup.py file containing a setup() function call is still required even if your configuration resides in setup.cfg.

Setuptools allows using configuration files (for example, setup.cfg) to define a package’s metadata and other options that are normally supplied to the setup() function (declarative config).

This approach not only allows automation scenarios but also reduces boilerplate code in some cases.

[metadata]
name = my_package
version = attr: my_package.VERSION
author = Josiah Carberry
author_email = josiah_carberry@brown.edu
description = My package description
long_description = file: README.rst, CHANGELOG.rst, LICENSE.rst
keywords = one, two
license = BSD-3-Clause
classifiers =
    Framework :: Django
    Programming Language :: Python :: 3

[options]
zip_safe = False
include_package_data = True
packages = find:
python_requires = >=3.8
install_requires =
    requests
    importlib-metadata; python_version<"3.10"

[options.package_data]
* = *.txt, *.rst
hello = *.msg

[options.entry_points]
console_scripts =
    executable-name = my_package.module:function

[options.extras_require]
pdf = ReportLab>=1.2; RXP
rest = docutils>=0.3; pack ==1.1, ==1.3

[options.packages.find]
exclude =
    examples*
    tools*
    docs*
    my_package.tests*

Metadata and options are set in the config sections of the same name.

  • Keys are the same as the keyword arguments one provides to the setup() function.

  • Complex values can be written comma-separated or placed one per line in dangling config values. The following are equivalent:

    [metadata]
    keywords = one, two
    
    [metadata]
    keywords =
        one
        two
    
  • In some cases, complex values can be provided in dedicated subsections for clarity.

  • Some keys allow file:, attr:, find:, and find_namespace: directives in order to cover common usecases.

  • Unknown keys are ignored.

Using a src/ layout#

One commonly used configuration has all the Python source code in a subdirectory (often called the src/ layout), like this:

├── src
│   └── mypackage
│       ├── __init__.py
│       └── mod1.py
├── setup.py
└── setup.cfg

You can set up your setup.cfg to automatically find all your packages in the subdirectory, using package_dir, like this:

# This example contains just the necessary options for a src-layout, set up
# the rest of the file as described above.

[options]
package_dir=
    =src
packages=find:

[options.packages.find]
where=src

In this example, the value for the package_dir configuration (i.e. =src) is parsed as {"": "src"}. The "" key has a special meaning in this context, and indicates that all the packages are contained inside the given directory. Also note that the value for [options.packages.find] where matches the value associated with "" in the package_dir dictionary.

Specifying values#

Some values are treated as simple strings, some allow more logic.

Type names used below:

  • str - simple string

  • list-comma - dangling list or string of comma-separated values

  • list-semi - dangling list or string of semicolon-separated values

  • bool - True is 1, yes, true

  • dict - list-comma where each entry corresponds to a key/value pair, with keys separated from values by =. If an entry starts with =, the key is assumed to be an empty string (e.g. =src is parsed as {"": "src"}).

  • section - values are read from a dedicated (sub)section

Special directives:

  • attr: - Value is read from a module attribute.

    It is advisable to use literal values together with attr: (e.g. str, tuple[str], see ast.literal_eval()). This is recommend in order to support the common case of a literal value assigned to a variable in a module containing (directly or indirectly) third-party imports.

    attr: first tries to read the value from the module by examining the module’s AST. If that fails, attr: falls back to importing the module, using importlib.util.spec_from_file_location() recommended recipe (see example on Python docs about “Importing a source file directly”). Note however that importing the module is error prone since your package is not installed yet. You may also need to manually add the project directory to sys.path (via setup.py) in order to be able to do that.

    When the module is imported, attr: supports callables and iterables; unsupported types are cast using str().

  • file: - Value is read from a list of files and then concatenated

    Important

    The file: directive is sandboxed and won’t reach anything outside the project directory (i.e. the directory containing setup.cfg/pyproject.toml).

    Note

    If you are using an old version of setuptools, you might need to ensure that all files referenced by the file: directive are included in the sdist (you can do that via MANIFEST.in or using plugins such as setuptools-scm, please have a look on Controlling files in the distribution for more information).

    Changed in version 66.1.0: Newer versions of setuptools will automatically add these files to the sdist.

Metadata#

Attention

The aliases given below are supported for compatibility reasons, but their use is not advised.

Key

Aliases

Type

Minimum Version

Notes

name

str

version

attr:, file:, str

39.2.0

[1]

url

home-page

str

download_url

download-url

str

project_urls

dict

38.3.0

author

str

author_email

author-email

str

maintainer

str

maintainer_email

maintainer-email

str

classifiers

classifier

file:, list-comma

license

str

license_files

license_file

list-comma

42.0.0

description

summary

file:, str

long_description

long-description

file:, str

long_description_content_type

str

38.6.0

keywords

list-comma

platforms

platform

list-comma

provides

list-comma

requires

list-comma

obsoletes

list-comma

Notes:

Options#

Key

Type

Minimum Version

Notes

zip_safe

bool

setup_requires

list-semi

36.7.0

install_requires

file:, list-semi

BETA [3], [7]

extras_require

file:, section

BETA [3], [7]

python_requires

str

34.4.0

entry_points

file:, section

51.0.0

scripts

list-comma

eager_resources

list-comma

dependency_links

list-comma

tests_require

list-semi

include_package_data

bool

packages

find:, find_namespace:, list-comma

[4]

package_dir

dict

package_data

section

[2]

exclude_package_data

section

namespace_packages

list-comma

[6]

py_modules

list-comma

34.4.0

data_files

section

40.6.0

[5]

Notes:

Compatibility with other tools#

Historically, several tools explored declarative package configuration in parallel. And several of them chose to place the packaging configuration within the project’s setup.cfg file. One of the first was distutils2, which development has stopped in 2013. Other include pbr which is still under active development or d2to1, which was a plug-in that backports declarative configuration to distutils, but has had no release since Oct. 2015. As a way to harmonize packaging tools, setuptools, having held the position of de facto standard, has gradually integrated those features as part of its core features.

Still this has lead to some confusion and feature incompatibilities:

  • some tools support features others don’t;

  • some have similar features but the declarative syntax differs;

The table below tries to summarize the differences. But, please, refer to each tool documentation for up-to-date information.

feature

setuptools

distutils2

d2to1

pbr

[metadata] description-file

S

Y

Y

Y

[files]

S

Y

Y

Y

entry_points

Y

Y

Y

S

[backwards_compat]

N

Y

Y

Y

Y: supported, N: unsupported, S: syntax differs (see above example).

Also note that some features were only recently added to setuptools. Please refer to the previous sections to find out when.