| ========================== |
| ``setuptools`` Quickstart |
| ========================== |
| |
| Installation |
| ============ |
| |
| To install the latest version of setuptools, use:: |
| |
| pip install --upgrade setuptools |
| |
| |
| Python packaging at a glance |
| ============================ |
| The landscape of Python packaging is shifting and ``Setuptools`` has evolved to |
| only provide backend support, no longer being the de-facto packaging tool in |
| the market. Every python package must provide a ``pyproject.toml`` and specify |
| the backend (build system) it wants to use. The distribution can then |
| be generated with whatever tool that provides a ``build sdist``-like |
| functionality. While this may appear cumbersome, given the added pieces, |
| it in fact tremendously enhances the portability of your package. The |
| change is driven under :pep:`PEP 517 <517#build-requirements>`. To learn more about Python packaging in general, |
| navigate to the :ref:`bottom <packaging-resources>` of this page. |
| |
| |
| Basic Use |
| ========= |
| For basic use of setuptools, you will need a ``pyproject.toml`` with the |
| exact following info, which declares you want to use ``setuptools`` to |
| package your project: |
| |
| .. code-block:: toml |
| |
| [build-system] |
| requires = ["setuptools"] |
| build-backend = "setuptools.build_meta" |
| |
| Then, you will need to specify your package information such as metadata, |
| contents, dependencies, etc. |
| |
| Setuptools currently supports configurations from either ``setup.cfg``, |
| ``setup.py`` or ``pyproject.toml`` [#experimental]_ files, however, configuring new |
| projects via ``setup.py`` is discouraged [#setup.py]_. |
| |
| The following example demonstrates a minimum configuration: |
| |
| .. tab:: setup.cfg |
| |
| .. code-block:: ini |
| |
| [metadata] |
| name = mypackage |
| version = 0.0.1 |
| |
| [options] |
| packages = mypackage |
| install_requires = |
| requests |
| importlib-metadata; python_version < "3.8" |
| |
| See :doc:`/userguide/declarative_config` for more information. |
| |
| .. tab:: setup.py [#setup.py]_ |
| |
| .. code-block:: python |
| |
| from setuptools import setup |
| |
| setup( |
| name='mypackage', |
| version='0.0.1', |
| packages=['mypackage'], |
| install_requires=[ |
| 'requests', |
| 'importlib-metadata; python_version == "3.8"', |
| ], |
| ) |
| |
| See :doc:`/references/keywords` for more information. |
| |
| .. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_ |
| |
| .. code-block:: toml |
| |
| [project] |
| name = "mypackage" |
| version = "0.0.1" |
| dependencies = [ |
| "requests", |
| 'importlib-metadata; python_version<"3.8"', |
| ] |
| |
| See :doc:`/userguide/pyproject_config` for more information. |
| |
| This is what your project would look like:: |
| |
| ~/mypackage/ |
| pyproject.toml |
| setup.cfg # or setup.py |
| mypackage/__init__.py |
| |
| Then, you need a builder, such as :std:doc:`PyPA build <pypa-build:index>` |
| which you can obtain via ``pip install build``. After downloading it, invoke |
| the builder:: |
| |
| python -m build |
| |
| You now have your distribution ready (e.g. a ``tar.gz`` file and a ``.whl`` |
| file in the ``dist`` directory), which you can upload to PyPI! |
| |
| Of course, before you release your project to PyPI, you'll want to add a bit |
| more information to your setup script to help people find or learn about your |
| project. And maybe your project will have grown by then to include a few |
| dependencies, and perhaps some data files and scripts. In the next few sections, |
| we will walk through the additional but essential information you need |
| to specify to properly package your project. |
| |
| |
| Automatic package discovery |
| =========================== |
| For simple projects, it's usually easy enough to manually add packages to |
| the ``packages`` keyword in ``setup.cfg``. However, for very large projects, |
| it can be a big burden to keep the package list updated. |
| Therefore, ``setuptoops`` provides a convenient way to automatically list all |
| the packages in your project directory: |
| |
| .. tab:: setup.cfg |
| |
| .. code-block:: ini |
| |
| [options] |
| packages = find: # OR `find_namespaces:` if you want to use namespaces |
| |
| [options.packages.find] (always `find` even if `find_namespaces:` was used before) |
| # This section is optional |
| # Each entry in this section is optional, and if not specified, the default values are: |
| # `where=.`, `include=*` and `exclude=` (empty). |
| include=mypackage* |
| exclude=mypackage.tests* |
| |
| .. tab:: setup.py [#setup.py]_ |
| |
| .. code-block:: python |
| |
| from setuptools import find_packages # or find_namespace_packages |
| |
| setup( |
| # ... |
| packages=find_packages( |
| where='.', |
| include=['mypackage*'], # ["*"] by default |
| exclude=['mypackage.tests'], # empty by default |
| ), |
| # ... |
| ) |
| |
| .. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_ |
| |
| .. code-block:: toml |
| |
| # ... |
| [tool.setuptools.packages] |
| find = {} # Scan the project directory with the default parameters |
| |
| # OR |
| [tool.setuptools.packages.find] |
| where = ["src"] # ["."] by default |
| include = ["mypackage*"] # ["*"] by default |
| exclude = ["mypackage.tests*"] # empty by default |
| namespaces = false # true by default |
| |
| When you pass the above information, alongside other necessary information, |
| ``setuptools`` walks through the directory specified in ``where`` (omitted |
| here as the package resides in the current directory) and filters the packages |
| it can find following the ``include`` (defaults to none), then removes |
| those that match the ``exclude`` and returns a list of Python packages. The above |
| setup also allows you to adopt a ``src/`` layout. For more details and advanced |
| use, go to :ref:`package_discovery`. |
| |
| .. tip:: |
| Starting with version 61.0.0, setuptools' automatic discovery capabilities |
| have been improved to detect popular project layouts (such as the |
| :ref:`flat-layout` and :ref:`src-layout`) without requiring any |
| special configuration. Check out our :ref:`reference docs <package_discovery>` |
| for more information, but please keep in mind that this functionality is |
| still considered **experimental** and might change (or even be removed) in |
| future releases. |
| |
| |
| Entry points and automatic script creation |
| =========================================== |
| Setuptools supports automatic creation of scripts upon installation, that runs |
| code within your package if you specify them as :doc:`entry points |
| <PyPUG:specifications/entry-points>`. |
| This is what allows you to run commands like ``pip install`` instead of having |
| to type ``python -m pip install``. |
| The following configuration examples show how to accomplish this: |
| |
| .. tab:: setup.cfg |
| |
| .. code-block:: ini |
| |
| [options.entry_points] |
| console_scripts = |
| cli-name = mypkg.mymodule:some_func |
| |
| .. tab:: setup.py [#setup.py]_ |
| |
| .. code-block:: python |
| |
| setup( |
| # ... |
| entry_points={ |
| 'console_scripts': [ |
| 'cli-name = mypkg.mymodule:some_func', |
| ] |
| } |
| ) |
| |
| .. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_ |
| |
| .. code-block:: toml |
| |
| [project.scripts] |
| cli-name = mypkg.mymodule:some_func |
| |
| When this project is installed, a ``cli-name`` executable will be created. |
| ``cli-name`` will invoke the function ``some_func`` in the |
| ``mypkg/mymodule.py`` file when called by the user. |
| Note that you can also use the ``entry-points`` mechanism to advertise |
| components between installed packages and implement plugin systems. |
| For detailed usage, go to :doc:`entry_point`. |
| |
| |
| Dependency management |
| ===================== |
| Packages built with ``setuptools`` can specify dependencies to be automatically |
| installed when the package itself is installed. |
| The example below show how to configure this kind of dependencies: |
| |
| .. tab:: setup.cfg |
| |
| .. code-block:: ini |
| |
| [options] |
| install_requires = |
| docutils |
| requests <= 0.4 |
| |
| .. tab:: setup.py [#setup.py]_ |
| |
| .. code-block:: python |
| |
| setup( |
| # ... |
| install_requires=["docutils", "requests <= 0.4"], |
| # ... |
| ) |
| |
| .. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_ |
| |
| .. code-block:: toml |
| |
| [project] |
| # ... |
| dependencies = [ |
| "docutils", |
| "requires <= 0.4", |
| ] |
| # ... |
| |
| Each dependency is represented by a string that can optionally contain version requirements |
| (e.g. one of the operators <, >, <=, >=, == or !=, followed by a version identifier), |
| and/or conditional environment markers, e.g. ``sys_platform == "win32"`` |
| (see :doc:`PyPUG:specifications/version-specifiers` for more information). |
| |
| When your project is installed, all of the dependencies not already installed |
| will be located (via PyPI), downloaded, built (if necessary), and installed. |
| This, of course, is a simplified scenario. You can also specify groups of |
| extra dependencies that are not strictly required by your package to work, but |
| that will provide additional functionalities. |
| For more advanced use, see :doc:`dependency_management`. |
| |
| |
| .. _Including Data Files: |
| |
| 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 simplest use, you |
| can simply use the ``include_package_data`` keyword: |
| |
| .. tab:: setup.cfg |
| |
| .. code-block:: ini |
| |
| [options] |
| include_package_data = True |
| |
| .. tab:: setup.py [#setup.py]_ |
| |
| .. code-block:: python |
| |
| setup( |
| # ... |
| include_package_data=True, |
| # ... |
| ) |
| |
| .. tab:: pyproject.toml (**EXPERIMENTAL**) [#experimental]_ |
| |
| .. code-block:: toml |
| |
| [tool.setuptools] |
| include-package-data = true |
| # This is already the default behaviour if your are using |
| # pyproject.toml to configure your build. |
| # You can deactivate that with `include-package-data = false` |
| |
| 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 |
| or automatically added by a :ref:`Revision Control System plugin |
| <Adding Support for Revision Control Systems>`. |
| For more details, see :doc:`datafiles`. |
| |
| |
| Development mode |
| ================ |
| |
| ``setuptools`` allows you to install a package without copying any files |
| to your interpreter directory (e.g. the ``site-packages`` directory). |
| This allows you to modify your source code and have the changes take |
| effect without you having to rebuild and reinstall. |
| Here's how to do it:: |
| |
| pip install --editable . |
| |
| This creates a link file in your interpreter site package directory which |
| associate with your source code. For more information, see :doc:`development_mode`. |
| |
| .. tip:: |
| |
| Prior to :ref:`pip v21.1 <pip:v21-1>`, a ``setup.py`` script was |
| required to be compatible with development mode. With late |
| versions of pip, ``setup.cfg``-only projects may be installed in this mode. |
| |
| If you are experimenting with :doc:`configuration using <pyproject_config>`, |
| or have version of ``pip`` older than v21.1, you might need to keep a |
| ``setup.py`` file in file in your repository if you want to use editable |
| installs (for the time being). |
| |
| A simple script will suffice, for example: |
| |
| .. code-block:: python |
| |
| from setuptools import setup |
| |
| setup() |
| |
| You can still keep all the configuration in :doc:`setup.cfg </userguide/declarative_config>` |
| (or :doc:`pyproject.toml </userguide/pyproject_config>`). |
| |
| |
| Uploading your package to PyPI |
| ============================== |
| After generating the distribution files, the next step would be to upload your |
| distribution so others can use it. This functionality is provided by |
| :pypi:`twine` and is documented in the :doc:`Python packaging tutorial |
| <PyPUG:tutorials/packaging-projects>`. |
| |
| |
| Transitioning from ``setup.py`` to ``setup.cfg`` |
| ================================================ |
| To avoid executing arbitrary scripts and boilerplate code, we are transitioning |
| into a full-fledged ``setup.cfg`` to declare your package information instead |
| of running ``setup()``. This inevitably brings challenges due to a different |
| syntax. :doc:`Here </userguide/declarative_config>` we provide a quick guide to |
| understanding how ``setup.cfg`` is parsed by ``setuptools`` to ease the pain of |
| transition. |
| |
| .. _packaging-resources: |
| |
| Resources on Python packaging |
| ============================= |
| Packaging in Python can be hard and is constantly evolving. |
| `Python Packaging User Guide <https://packaging.python.org>`_ has tutorials and |
| up-to-date references that can help you when it is time to distribute your work. |
| |
| |
| .. |MANIFEST.in| replace:: ``MANIFEST.in`` |
| .. _MANIFEST.in: https://packaging.python.org/en/latest/guides/using-manifest-in/ |
| |
| |
| ---- |
| |
| .. rubric:: Notes |
| |
| .. [#setup.py] |
| The ``setup.py`` file should be used only when custom scripting during the |
| build is necessary. |
| Examples are kept in this document to help people interested in maintaining or |
| contributing to existing packages that use ``setup.py``. |
| Note that you can still keep most of configuration declarative in |
| :doc:`setup.cfg <declarative_config>` or :doc:`pyproject.toml |
| <pyproject_config>` and use ``setup.py`` only for the parts not |
| supported in those files (e.g. C extensions). |
| |
| .. [#experimental] |
| While the ``[build-system]`` table should always be specified in the |
| ``pyproject.toml`` file, support for adding package metadata and build configuration |
| options via the ``[project]`` and ``[tool.setuptools]`` tables is still |
| experimental and might change (or be completely removed) in future releases. |
| See :doc:`/userguide/pyproject_config`. |