Skip to content

Instantly share code, notes, and snippets.

@WYVERN2742
Created April 15, 2021 20:12
Show Gist options
  • Save WYVERN2742/1b8ba3cbf7cca699de2a62be9e9d06ce to your computer and use it in GitHub Desktop.
Save WYVERN2742/1b8ba3cbf7cca699de2a62be9e9d06ce to your computer and use it in GitHub Desktop.

Setuptools configuration documentation

Why did I have to figure this out all by myself? Why is setuputil's docs so garbage???

Key Description
name A string specifying the name of the package.
version A string specifying the version number of the package.
url A string specifying the URL for the package homepage.
download_url A string specifying the URL to download the package.
project_urls An arbitrary map of URL names to hyperlinks, allowing more extensible documentation of where various resources can be found than the simple url and download_url options provide.
author A string specifying the author of the package.
author_email A string specifying the email address of the package author.
maintainer A string specifying the name of the current maintainer, if different from the author. Note that if the maintainer is provided, setuptools will use it as the author in PKG-INFO.
maintainer_email A string specifying the email address of the current maintainer, if different from the author.
classifiers A list of strings describing the categories for the package.
license A string specifying the license of the package.
license_file license_file is deprecated. Use license_files instead.
license_files A list of glob patterns for license related files that should be included. If neither license_file nor license_files is specified, this option defaults to LICEN[CS]E*, COPYING*, NOTICE*, and AUTHORS*.
description A string describing the package in a single line.
long_description A string providing a longer description of the package.
long_description_content_type A string specifying the content type is used for the long_description (e.g. text/markdown)
keywords A list of strings or a comma-separated string providing descriptive meta-data. See: PEP-314
platforms A list of strings or comma-separated string.
provides ⚠️ provides is currently ignored by pip.
requires ❌ Deprecated: Superseded by install_requires and should not be used anymore.
obsoletes ⚠️ obsoletes is currently ignored by pip
Key Description
zip_safe A boolean flag specifying whether the project can be safely installed and run from a zip file. If this argument is not supplied, the bdist_egg command will have to analyze all of your project's contents for possible problems each time it builds an egg.
setup_requires ❌ Deprecated: Using setup_requires is discouraged in favor of PEP-518
install_requires A string or list of strings specifying what other distributions need to be installed when this one is. See the section on Declaring Dependencies for details.
extras_require A dictionary mapping names of "extras" (optional features of your project) to strings or lists of strings specifying what other distributions must be installed to support those features. See the section on Declaring Dependencies for details.
python_requires A string corresponding to a version specifier (as defined in PEP 440) for the Python version, used to specify the Requires-Python defined in PEP 345.
entry_points A dictionary mapping entry point group names to strings or lists of strings defining the entry points. Entry points are used to support dynamic discovery of services or plugins provided by a project. See Advertising Behaviour for details and examples of the format of this argument.
use_2to3 ❌ Deprecated: Used in converting python 2 to python 3
use_2to3_fixers ❌ Deprecated: Used in converting python 2 to python 3
use_2to3_exclude_fixers ❌ Deprecated: Used in converting python 2 to python 3
convert_2to3_doctests ❌ Deprecated: Used in converting python 2 to python 3
scripts A list of strings specifying the standalone script files to be built and installed.
eager_resources A list of strings naming resources that should be extracted together, if any of them is needed, or if any C extensions included in the project are imported. This argument is only useful if the project will be installed as a zipfile, and there is a need to have all of the listed resources be extracted to the filesystem as a unit. Resources listed here should be '/'-separated paths, relative to the source root, so to list a resource foo.png in package bar.baz, you would include the string bar/baz/foo.png in this argument. If you only need to obtain resources one at a time, or you don't have any C extensions that access other files in the project (such as data files or shared libraries), you probably do not need this argument and shouldn't mess with it. For more details on how this argument works, see Automatic Resource Extraction.
dependency_links ❌ Deprecated: not supported anymore by pip.
tests_require ❌ Deprecated: the test command is deprecated.
include_package_data If set to True, this tells setuptools to automatically include any data files it finds inside your package directories that are specified by your MANIFEST.in file. For more information, see the section on Including Data Files
packages A list of strings specifying the packages that setuptools will manipulate.
package_dir A dictionary providing a mapping of package to directory names.
package_data A dictionary mapping package names to lists of glob patterns. For a complete description and examples, see the section on Including Data Files. You do not need to use this option if you are using include_package_data, unless you need to add e.g. files that are generated by your setup script and build process. (And are therefore not in source control or are files that you don't want to include in your source distribution.)
exclude_package_data A dictionary mapping package names to lists of glob patterns that should be excluded from your package directories. You can use this to trim back any excess files included by include_package_data. For a complete description and examples, see the section on Including Data Files
namespace_packages A list of strings naming the project's "namespace packages". A namespace package is a package that may be split across multiple project distributions. For example, Zope 3's zope package is a namespace package, because subpackages like zope.interface and zope.publisher may be distributed separately. The egg runtime system can automatically merge such subpackages into a single parent package at runtime, as long as you declare them in each project that contains any subpackages of the namespace package, and as long as the namespace package's __init__.py does not contain any code other than a namespace declaration. See the section on Namespace Package for more information.
py_modules A list of strings specifying the modules that setuptools will manipulate.
data_files ❌ Deprecated: It does not work with wheels, so it should be avoided.

Declaring Dependencies

This is where a package declares its core dependencies, without which it won't be able to run. setuptools support automatically download and install these dependencies when the package is installed. Although there is more finesse to it, let's start with a simple example.

[options]
; ...
install_requires =
    docutils
    BazSpam ==1.1
setup(
    # ...
    install_requires = [
        'docutils',
        'BazSpam ==1.1'
    ]
)

When your project is installed (e.g. using pip), all of the dependencies not already installed will be located (via PyPI), downloaded, built (if necessary), and installed. Any scripts in your project will be installed with wrappers that verify the availability of the specified dependencies at runtime.

Advertising Behavior

Console scripts are one use of the more general concept of entry points. Entry points more generally allow a packager to advertise behavior for discovery by other libraries and applications. This feature enables "plug-in"-like functionality, where one library solicits entry points and any number of other libraries provide those entry points.

A good example of this plug-in behavior can be seen in pytest plugins, where pytest is a test framework that allows other libraries to extend or modify its functionality through the pytest11 entry point.

The console scripts work similarly, where libraries advertise their commands and tools like pip create wrapper scripts that invoke those commands.

For a project wishing to solicit entry points, Setuptools recommends the importlib.metadata module (part of stdlib since Python 3.8) or its backport, importlib_metadata

For example, to find the console script entry points from the example above:

    from importlib import metadata
    eps = metadata.entry_points()['console_scripts']

eps is now a list of EntryPoint objects, one of which corresponds to the hello-world = timmins:hello_world defined above. Each EntryPoint contains the name, group, and value. It also supplies a .load() method to import and load that entry point (module or object).

[options.entry_points]
my.plugins =
    hello-world = timmins:hello_world

Then, a different project wishing to load my.plugins plugins could run the following routine to load (and invoke) such plugins:

from importlib import metadata
eps = metadata.entry_points()['my.plugins']
for ep in eps:
    plugin = ep.load()
    plugin()

The project soliciting the entry points needs not to have any dependency or prior knowledge about the libraries implementing the entry points, and downstream users are able to compose functionality by pulling together libraries implementing the entry points.

Automatic Resource Extraction

If you are using tools that expect your resources to be "real" files, or your project includes non-extension native libraries or other files that your C extensions expect to be able to access, you may need to list those files in the eager_resources argument to setup(), so that the files will be extracted together, whenever a C extension in the project is imported.

This is especially important if your project includes shared libraries other than distutils-built C extensions, and those shared libraries use file extensions other than .dll, .so, or .dylib, which are the extensions that setuptools 0.6a8 and higher automatically detects as shared libraries and adds to the native_libs.txt file for you. Any shared libraries whose names do not end with one of those extensions should be listed as eager_resources, because they need to be present in the filesystem when he C extensions that link to them are used.

The pkg_resources runtime for compressed packages will automatically extract all C extensions and eager_resources at the same time, whenever any C extension or eager resource is requested via the resource_filename() API (C extensions are imported using resource_filename() internally). This ensures that C extensions will see all of the "real" files that they expect to see.

Note also that you can list directory resource names in eager_resources as well, in which case the directory's contents (including subdirectories) will be extracted whenever any C extension or eager resource is requested.

Please note that if you're not sure whether you need to use this argument, you don't! It's really intended to support projects with lots of non-Python dependencies and as a last resort for crufty projects that can't otherwise handle being compressed. If your package is pure Python, Python plus data files, or Python plus C, you really don't need this. You've got to be using either C or an external program that needs "real" files in your project before there's any possibility of eager_resources being relevant to your project.

Including Data Files

The distutils have traditionally allowed installation of "data files", which are placed in a platform-specific location. Setuptools offers three ways to specify data files to be included in your packages. For the simpliest use, you can simply use the include_package_data keyword:

[options]
include_package_data = True

This tells setuptools to install any data files it finds in your packages. The data files must be specified via the distutils' MANIFEST.in file. For more details, see :doc:datafiles

Using find_namespace: or find_namespace_packages

setuptools provides the find_namespace: (find_namespace_packages) which behaves similarly to find: but works with namespace package. Before diving in, it is important to have a good understanding of what namespace packages are. Here is a quick recap:

Suppose you have two packages named as follows:

/Users/Desktop/timmins/foo/__init__.py
/Library/timmins/bar/__init__.py

If both Desktop and Library are on your PYTHONPATH, then a namespace package called timmins will be created automatically for you when you invoke the import mechanism, allowing you to accomplish the following

import timmins.foo
import timmins.bar

as if there is only one timmins on your system. The two packages can then be distributed separately and installed individually without affecting the other one. Suppose you are packaging the foo part:

foo/
    src/
        timmins/foo/__init__.py
    setup.cfg # or setup.py

and you want the foo to be automatically included, find: won't work because timmins doesn't contain __init__.py directly, instead, you have to use find_namespace::

[options]
package_dir =
    =src
packages = find_namespace:

[options.packages.find]
where = src

When you install the zipped distribution, timmins.foo would become available to your interpreter.

You can think of find_namespace: as identical to find: except it would count a directory as a package even if it doesn't contain __init__.py file directly. As a result, this creates an interesting side effect. If you organize your package like this:

foo/
    timmins/
        foo/__init__.py
    setup.cfg # or setup.py
    tests/
        test_foo/__init__.py

a naive find_namespace: would include tests as part of your package to be installed. A simple way to fix it is to adopt the aforementioned src layout.

@WYVERN2742
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment