diff options
author | Jason R. Coombs <jaraco@jaraco.com> | 2021-07-18 15:13:50 -0400 |
---|---|---|
committer | Jason R. Coombs <jaraco@jaraco.com> | 2021-07-18 15:13:50 -0400 |
commit | 01f2abe71dc72fdf5b345f4ac3086a94b23efd15 (patch) | |
tree | 83bee7a6d933efe516f549423bff38f0d303a760 /docs/userguide | |
parent | 5c24e780b83e4557ca6e9e48b468e6f4a82695c9 (diff) | |
parent | aa5ef507f3bf78092abfff7c6a2cf55a9b2fb2dc (diff) | |
download | python-setuptools-git-01f2abe71dc72fdf5b345f4ac3086a94b23efd15.tar.gz |
Merge branch 'main' into change-docs-theme
Diffstat (limited to 'docs/userguide')
-rw-r--r-- | docs/userguide/declarative_config.rst | 136 | ||||
-rw-r--r-- | docs/userguide/dependency_management.rst | 246 | ||||
-rw-r--r-- | docs/userguide/development_mode.rst | 6 | ||||
-rw-r--r-- | docs/userguide/entry_point.rst | 4 | ||||
-rw-r--r-- | docs/userguide/package_discovery.rst | 114 | ||||
-rw-r--r-- | docs/userguide/quickstart.rst | 64 |
6 files changed, 341 insertions, 229 deletions
diff --git a/docs/userguide/declarative_config.rst b/docs/userguide/declarative_config.rst index bc66869b..128d9f97 100644 --- a/docs/userguide/declarative_config.rst +++ b/docs/userguide/declarative_config.rst @@ -18,15 +18,7 @@ to the ``setup()`` function (declarative config). This approach not only allows automation scenarios but also reduces boilerplate code in some cases. -.. note:: - - This implementation has limited compatibility with the distutils2-like - ``setup.cfg`` sections used by the ``pbr`` and ``d2to1`` packages. - - Namely: only metadata-related keys from ``metadata`` section are supported - (except for ``description-file``); keys from ``files``, ``entry_points`` - and ``backwards_compat`` are not supported. - +.. _example-setup-config: .. code-block:: ini @@ -58,6 +50,10 @@ boilerplate code in some cases. * = *.txt, *.rst hello = *.msg + [options.entry_points] + console_scripts = + executable-name = package.module:function + [options.extras_require] pdf = ReportLab>=1.2; RXP rest = docutils>=0.3; pack ==1.1, ==1.3 @@ -156,10 +152,9 @@ Special directives: * ``file:`` - Value is read from a list of files and then concatenated - -.. note:: - The ``file:`` directive is sandboxed and won't reach anything outside - the directory containing ``setup.py``. + .. note:: + The ``file:`` directive is sandboxed and won't reach anything outside + the directory containing ``setup.py``. Metadata @@ -169,11 +164,11 @@ Metadata 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) +version attr:, file:, str 39.2.0 [#meta-1]_ url home-page str download_url download-url str project_urls dict 38.3.0 @@ -183,8 +178,7 @@ maintainer str maintainer_email maintainer-email str classifiers classifier file:, list-comma license str -license_file str -license_files list-comma +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 @@ -193,28 +187,29 @@ platforms platform list-comma provides list-comma requires list-comma obsoletes list-comma -============================== ================= ================= =============== ===== +============================== ================= ================= =============== ========== -.. note:: - A version loaded using the ``file:`` directive must comply with PEP 440. - It is easy to accidentally put something other than a valid version - string in such a file, so validation is stricter in this case. +**Notes**: + +.. [#meta-1] The ``version`` file attribute has only been supported since 39.2.0. + + A version loaded using the ``file:`` directive must comply with PEP 440. + It is easy to accidentally put something other than a valid version + string in such a file, so validation is stricter in this case. -Notes: -1. The ``version`` file attribute has only been supported since 39.2.0. Options ------- -======================= =================================== =============== ===== +======================= =================================== =============== ========= Key Type Minimum Version Notes -======================= =================================== =============== ===== +======================= =================================== =============== ========= zip_safe bool setup_requires list-semi install_requires list-semi -extras_require section +extras_require section [#opt-2]_ python_requires str -entry_points file:, section +entry_points file:, section 51.0.0 use_2to3 bool use_2to3_fixers list-comma use_2to3_exclude_fixers list-comma @@ -224,25 +219,74 @@ eager_resources list-comma dependency_links list-comma tests_require list-semi include_package_data bool -packages find:, find_namespace:, list-comma +packages find:, find_namespace:, list-comma [#opt-3]_ package_dir dict -package_data section (1) +package_data section [#opt-1]_ exclude_package_data section namespace_packages list-comma py_modules list-comma data_files dict 40.6.0 -======================= =================================== =============== ===== - -.. note:: - - **packages** - The ``find:`` and ``find_namespace:`` directive can be further configured - in a dedicated subsection ``options.packages.find``. This subsection - accepts the same keys as the ``setuptools.find_packages`` and the - ``setuptools.find_namespace_packages`` function: - ``where``, ``include``, and ``exclude``. - - **find_namespace directive** - The ``find_namespace:`` directive is supported since Python >=3.3. - -Notes: -1. In the ``package_data`` section, a key named with a single asterisk (``*``) -refers to all packages, in lieu of the empty string used in ``setup.py``. +======================= =================================== =============== ========= + +**Notes**: + +.. [#opt-1] In the ``package_data`` section, a key named with a single asterisk + (``*``) refers to all packages, in lieu of the empty string used in ``setup.py``. + +.. [#opt-2] In the ``extras_require`` section, values are parsed as ``list-semi``. + This implies that in order to include markers, they **must** be *dangling*: + + .. code-block:: ini + + [options.extras_require] + rest = docutils>=0.3; pack ==1.1, ==1.3 + pdf = + ReportLab>=1.2 + RXP + importlib-metadata; python_version < "3.8" + +.. [#opt-3] The ``find:`` and ``find_namespace:`` directive can be further configured + in a dedicated subsection ``options.packages.find``. This subsection accepts the + same keys as the ``setuptools.find_packages`` and the + ``setuptools.find_namespace_packages`` function: + ``where``, ``include``, and ``exclude``. + + The ``find_namespace:`` directive is supported since Python >=3.3. + + +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 :file:`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 +:ref:`above example<example-setup-config>`). + +Also note that some features were only recently added to ``setuptools``. +Please refer to the previous sections to find out when. diff --git a/docs/userguide/dependency_management.rst b/docs/userguide/dependency_management.rst index 81ee226b..1c610790 100644 --- a/docs/userguide/dependency_management.rst +++ b/docs/userguide/dependency_management.rst @@ -3,7 +3,7 @@ Dependencies Management in Setuptools ===================================== There are three types of dependency styles offered by setuptools: -1) build system requirement, required dependency and 3) optional +1) build system requirement, 2) required dependency and 3) optional dependency. .. Note:: @@ -17,8 +17,8 @@ Build system requirement Package requirement ------------------- After organizing all the scripts and files and getting ready for packaging, -there needs to be a way to tell Python what programs it need to actually -do the packgaging (in our case, ``setuptools`` of course). Usually, +there needs to be a way to tell Python what programs it needs to actually +do the packaging (in our case, ``setuptools`` of course). Usually, you also need the ``wheel`` package as well since it is recommended that you upload a ``.whl`` file to PyPI alongside your ``.tar.gz`` file. Unlike the other two types of dependency keyword, this one is specified in your @@ -45,25 +45,29 @@ Declaring required dependency 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 -finess to it, let's start with a simple example. +finesse to it, let's start with a simple example. -.. code-block:: ini +.. tab:: setup.cfg - [options] - #... - install_requires = - docutils - BazSpam ==1.1 + .. code-block:: ini + + [options] + #... + install_requires = + docutils + BazSpam ==1.1 + +.. tab:: setup.py -.. code-block:: python + .. code-block:: python - setup( - #..., - 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 @@ -80,41 +84,49 @@ specific dependencies. For example, the ``enum`` package was added in Python 3.4, therefore, package that depends on it can elect to install it only when the Python version is older than 3.4. To accomplish this -.. code-block:: ini - - [options] - #... - install_requires = - enum34;python_version<'3.4' +.. tab:: setup.cfg -.. code-block:: python + .. code-block:: ini - setup( + [options] #... - install_requires=[ - "enum34;python_version<'3.4'",] - ) + install_requires = + enum34;python_version<'3.4' + +.. tab:: setup.py + + .. code-block:: python + + setup( + #... + install_requires=[ + "enum34;python_version<'3.4'",] + ) Similarly, if you also wish to declare ``pywin32`` with a minimal version of 1.0 and only install it if the user is using a Windows operating system: -.. code-block:: ini - - [options] - #... - install_requires = - enum34;python_version<'3.4' - pywin32 >= 1.0;platform_system=='Windows' +.. tab:: setup.cfg -.. code-block:: python + .. code-block:: ini - setup( + [options] #... - install_requires=[ - "enum34;python_version<'3.4'", - "pywin32 >= 1.0;platform_system=='Windows'" - ] - ) + install_requires = + enum34;python_version<'3.4' + pywin32 >= 1.0;platform_system=='Windows' + +.. tab:: setup.py + + .. code-block:: python + + setup( + #... + install_requires=[ + "enum34;python_version<'3.4'", + "pywin32 >= 1.0;platform_system=='Windows'" + ] + ) The environmental markers that may be used for testing platform types are detailed in `PEP 508 <https://www.python.org/dev/peps/pep-0508/>`_. @@ -179,20 +191,24 @@ The ``dependency_links`` option takes the form of a list of URL strings. For example, this will cause a search of the specified page for eggs or source distributions, if the package's dependencies aren't already installed: -.. code-block:: ini - - [options] - #... - dependency_links = http://peak.telecommunity.com/snapshots/ +.. tab:: setup.cfg -.. code-block:: python + .. code-block:: ini - setup( + [options] #... - dependency_links=[ - "http://peak.telecommunity.com/snapshots/" - ], - ) + dependency_links = http://peak.telecommunity.com/snapshots/ + +.. tab:: setup.py + + .. code-block:: python + + setup( + #... + dependency_links=[ + "http://peak.telecommunity.com/snapshots/" + ], + ) Optional dependencies @@ -209,82 +225,98 @@ ancillary functions such as "tests" and "docs". For example, Package-A offers optional PDF support and requires two other dependencies for it to work: -.. code-block:: ini +.. tab:: setup.cfg - [metadata] - name = Package-A + .. code-block:: ini - [options.extras_require] - PDF = ReportLab>=1.2; RXP + [metadata] + name = Package-A + [options.extras_require] + PDF = ReportLab>=1.2; RXP -.. code-block:: python - setup( - name="Project-A", - #... - extras_require={ - "PDF": ["ReportLab>=1.2", "RXP"], - } - ) +.. tab:: setup.py -The name ``PDF`` is an arbitary identifier of such a list of dependencies, to + .. code-block:: python + + setup( + name="Project-A", + #... + extras_require={ + "PDF": ["ReportLab>=1.2", "RXP"], + } + ) + +The name ``PDF`` is an arbitrary identifier of such a list of dependencies, to which other components can refer and have them installed. There are two common use cases. First is the console_scripts entry point: -.. code-block:: ini +.. tab:: setup.cfg - [metadata] - name = Project A - #... + .. code-block:: ini - [options] - #... - entry_points= - [console_scripts] - rst2pdf = project_a.tools.pdfgen [PDF] - rst2html = project_a.tools.htmlgen - -.. code-block:: python - - setup( - name = "Project-A" - #..., - entry_points={ - "console_scripts": [ - "rst2pdf = project_a.tools.pdfgen [PDF]", - "rst2html = project_a.tools.htmlgen", - ], - } - ) + [metadata] + name = Project A + #... -When the script ``rst2pdf`` is run, it will trigger the installation of -the two dependencies ``PDF`` maps to. + [options] + #... + entry_points= + [console_scripts] + rst2pdf = project_a.tools.pdfgen [PDF] + rst2html = project_a.tools.htmlgen + +.. tab:: setup.py + + .. code-block:: python + + setup( + name = "Project-A" + #..., + entry_points={ + "console_scripts": [ + "rst2pdf = project_a.tools.pdfgen [PDF]", + "rst2html = project_a.tools.htmlgen", + ], + } + ) + +This syntax indicates that the entry point (in this case a console script) +is only valid when the PDF extra is installed. It is up to the installer +to determine how to handle the situation where PDF was not indicated +(e.g. omit the console script, provide a warning when attempting to load +the entry point, assume the extras are present and let the implementation +fail later). The second use case is that other package can use this "extra" for their own dependencies. For example, if "Project-B" needs "project A" with PDF support installed, it might declare the dependency like this: -.. code-block:: ini +.. tab:: setup.cfg - [metadata] - name = Project-B - #... + .. code-block:: ini - [options] - #... - install_requires = - Project-A[PDF] + [metadata] + name = Project-B + #... + + [options] + #... + install_requires = + Project-A[PDF] + +.. tab:: setup.py -.. code-block:: python + .. code-block:: python - setup( - name="Project-B", - install_requires=["Project-A[PDF]"], - ... - ) + setup( + name="Project-B", + install_requires=["Project-A[PDF]"], + ... + ) This will cause ReportLab to be installed along with project A, if project B is installed -- even if project A was already installed. In this way, a project diff --git a/docs/userguide/development_mode.rst b/docs/userguide/development_mode.rst index bce724a7..3c477ec1 100644 --- a/docs/userguide/development_mode.rst +++ b/docs/userguide/development_mode.rst @@ -3,9 +3,9 @@ Under normal circumstances, the ``distutils`` assume that you are going to build a distribution of your project, not use it in its "raw" or "unbuilt" -form. If you were to use the ``distutils`` that way, you would have to rebuild -and reinstall your project every time you made a change to it during -development. +form. However, if you were to use the ``distutils`` to build a distribution, +you would have to rebuild and reinstall your project every time you made a +change to it during development. Another problem that sometimes comes up with the ``distutils`` is that you may need to do development on two related projects at the same time. You may need diff --git a/docs/userguide/entry_point.rst b/docs/userguide/entry_point.rst index edab4465..63d30a48 100644 --- a/docs/userguide/entry_point.rst +++ b/docs/userguide/entry_point.rst @@ -28,7 +28,7 @@ with ``__init__.py`` as: .. code-block:: python - def helloworld(): + def hello_world(): print("Hello world") and ``__main__.py`` providing a hook: @@ -64,7 +64,7 @@ After installing the package, a user may invoke that function by simply calling The syntax for entry points is specified as follows: -.. code-block:: +.. code-block:: ini <name> = [<package>.[<subpackage>.]]<module>[:<object>.<object>] diff --git a/docs/userguide/package_discovery.rst b/docs/userguide/package_discovery.rst index de4ef668..0a8070ae 100644 --- a/docs/userguide/package_discovery.rst +++ b/docs/userguide/package_discovery.rst @@ -19,36 +19,44 @@ Package Discovery and Namespace Package support for namespace package. Normally, you would specify the package to be included manually in the following manner: -.. code-block:: ini - - [options] - #... - packages = - mypkg1 - mypkg2 +.. tab:: setup.cfg -.. code-block:: python + .. code-block:: ini - setup( + [options] #... - packages = ['mypkg1', 'mypkg2'] - ) + packages = + mypkg1 + mypkg2 + +.. tab:: setup.py + + .. code-block:: python + + setup( + #... + packages = ['mypkg1', 'mypkg2'] + ) This can get tiresome reallly quickly. To speed things up, we introduce two functions provided by setuptools: -.. code-block:: ini +.. tab:: setup.cfg - [options] - packages = find: - #or - packages = find_namespace: + .. code-block:: ini -.. code-block:: python + [options] + packages = find: + #or + packages = find_namespace: + +.. tab:: setup.py - from setuptools import find_packages - #or - from setuptools import find_namespace_packages + .. code-block:: python + + from setuptools import find_packages + #or + from setuptools import find_namespace_packages Using ``find:`` or ``find_packages`` @@ -71,30 +79,34 @@ it, consider the following directory To have your setup.cfg or setup.py to automatically include packages found in ``src`` that starts with the name ``pkg`` and not ``additional``: -.. code-block:: ini +.. tab:: setup.cfg - [options] - packages = find: - package_dir = - =src + .. code-block:: ini - [options.packages.find] - where = src - include = pkg* - exclude = additional + [options] + packages = find: + package_dir = + =src -.. code-block:: python + [options.packages.find] + where = src + include = pkg* + exclude = additional - setup( - #... - packages = find_packages( - where = 'src', - include = ['pkg*',], - exclude = ['additional',] - ), - package_dir = {"":"src"} - #... - ) +.. tab:: setup.py + + .. code-block:: python + + setup( + #... + packages = find_packages( + where = 'src', + include = ['pkg*',], + exclude = ['additional',] + ), + package_dir = {"":"src"} + #... + ) .. _Namespace Packages: @@ -144,7 +156,7 @@ to use ``find_namespace:``: =src packages = find_namespace: - [options.packages.find_namespace] + [options.packages.find] where = src When you install the zipped distribution, ``timmins.foo`` would become @@ -195,17 +207,21 @@ following: And the ``namespace_packages`` keyword in your ``setup.cfg`` or ``setup.py``: -.. code-block:: ini +.. tab:: setup.cfg - [options] - namespace_packages = timmins + .. code-block:: ini -.. code-block:: python + [options] + namespace_packages = timmins + +.. tab:: setup.py + + .. code-block:: python - setup( - # ... - namespace_packages = ['timmins'] - ) + setup( + # ... + namespace_packages = ['timmins'] + ) And your directory should look like this diff --git a/docs/userguide/quickstart.rst b/docs/userguide/quickstart.rst index aa09e54d..1bd04ded 100644 --- a/docs/userguide/quickstart.rst +++ b/docs/userguide/quickstart.rst @@ -20,7 +20,7 @@ be generated with whatever tools that provides a ``build sdist``-alike 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 `bottom <Resources on python packaging>`_ of this page. +navigate to the :ref:`bottom <packaging-resources>` of this page. Basic Use @@ -35,33 +35,52 @@ package your project: requires = ["setuptools", "wheel"] build-backend = "setuptools.build_meta" -Then, you will need a ``setup.cfg`` to specify your package information, -such as metadata, contents, dependencies, etc. Here we demonstrate the minimum +Then, you will need a ``setup.cfg`` or ``setup.py`` to specify your package +information, such as metadata, contents, dependencies, etc. Here we demonstrate +the minimum -.. code-block:: ini +.. tab:: setup.cfg - [metadata] - name = mypackage - version = 0.0.1 + .. code-block:: ini - [options] - packages = mypackage - install_requires = - requests - importlib; python_version == "2.6" + [metadata] + name = mypackage + version = 0.0.1 + + [options] + packages = mypackage + install_requires = + requests + importlib; python_version == "2.6" + +.. tab:: setup.py + + .. code-block:: python + + from setuptools import setup + + setup( + name='mypackage', + version='0.0.1', + packages=['mypackage'], + install_requires=[ + 'requests', + 'importlib; python_version == "2.6"', + ], + ) This is what your project would look like:: ~/mypackage/ pyproject.toml - setup.cfg + setup.cfg # or setup.py mypackage/__init__.py -Then, you need an installer, such as `pep517 <https://pypi.org/project/pep517/>`_ -which you can obtain via ``pip install pep517``. After downloading it, invoke -the installer:: +Then, you need an 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 pep517.build . + 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! @@ -152,7 +171,7 @@ 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 +specify data files to be included in your packages. For the simplest use, you can simply use the ``include_package_data`` keyword: .. code-block:: ini @@ -168,7 +187,7 @@ For more details, see :doc:`datafiles` Development mode ================ ``setuptools`` allows you to install a package without copying any files -to your interpretor directory (e.g. the ``site-packages`` directory). This +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. This is currently incompatible with PEP 517 and therefore it requires a ``setup.py`` script with the following @@ -181,7 +200,7 @@ Then:: pip install --editable . -This creates a link file in your interpretor site package directory which +This creates a link file in your interpreter site package directory which associate with your source code. For more information, see: (WIP) @@ -194,13 +213,14 @@ basic use here. Transitioning from ``setup.py`` to ``setup.cfg`` -================================================== -To avoid executing arbitary scripts and boilerplate code, we are transitioning +================================================ +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. Here we provide a quick guide to understanding how ``setup.cfg`` is parsed by ``setuptool`` to ease the pain of transition. +.. _packaging-resources: Resources on Python packaging ============================= |