diff options
Diffstat (limited to 'docs/userguide')
-rw-r--r-- | docs/userguide/dependency_management.rst | 260 | ||||
-rw-r--r-- | docs/userguide/development_mode.rst | 48 | ||||
-rw-r--r-- | docs/userguide/extension.rst | 221 | ||||
-rw-r--r-- | docs/userguide/functionalities_rewrite.rst | 9 | ||||
-rw-r--r-- | docs/userguide/index.rst | 39 | ||||
-rw-r--r-- | docs/userguide/miscellaneous.rst | 100 | ||||
-rw-r--r-- | docs/userguide/quickstart.rst | 14 |
7 files changed, 280 insertions, 411 deletions
diff --git a/docs/userguide/dependency_management.rst b/docs/userguide/dependency_management.rst index d507a587..c7f1e059 100644 --- a/docs/userguide/dependency_management.rst +++ b/docs/userguide/dependency_management.rst @@ -6,24 +6,23 @@ There are three types of dependency styles offered by setuptools: 1) build system requirement, 2) required dependency and 3) optional dependency. -.. Note:: - Packages that are added to dependency can be optionally specified with the - version by following `PEP 440 <https://www.python.org/dev/peps/pep-0440/>`_ +.. attention:: + Each dependency, regardless of type, needs to be specified according to :pep:`508`. + This allows adding version :pep:`range restrictions <440#version-specifiers>` + and :ref:`environment markers <environment-markers>`. + Please note however that public package indexes, such as `PyPI`_ + might not accept packages that declare dependencies using + :pep:`direct URLs <440#direct-references>`. 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 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 -``pyproject.toml`` file (if you have forgot what this is, go to -:doc:`quickstart` or (WIP)): +there needs to be a way to specify what programs and libraries are actually needed +do the packaging (in our case, ``setuptools`` of course). +This needs to be specified in your ``pyproject.toml`` file +(if you have forgot what this is, go to :doc:`/userguide/quickstart` or :doc:`/build_meta`): .. code-block:: ini @@ -31,11 +30,16 @@ other two types of dependency keyword, this one is specified in your requires = ["setuptools"] #... +Please note that you should also include here any other ``setuptools`` plugin +(e.g., :pypi:`setuptools-scm`, :pypi:`setuptools-golang`, :pypi:`setuptools-rust`) +or build-time dependency (e.g., :pypi:`Cython`, :pypi:`cppy`, :pypi:`pybind11`). + .. note:: - This used to be accomplished with the ``setup_requires`` keyword but is - now considered deprecated in favor of the PEP 517 style described above. + In previous versions of ``setuptools``, + this used to be accomplished with the ``setup_requires`` keyword but is + now considered deprecated in favor of the :pep:`517` style described above. To peek into how this legacy keyword is used, consult our :doc:`guide on - deprecated practice (WIP) <../deprecated/index>` + deprecated practice (WIP) </deprecated/index>`. .. _Declaring Dependencies: @@ -82,12 +86,14 @@ finesse to it, let's start with a simple example. # ... -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), +When your project is installed (e.g., using :pypi:`pip`), all of the dependencies not +already installed will be located (via `PyPI`_), downloaded, built (if necessary), and installed and 2) Any scripts in your project will be installed with wrappers that verify the availability of the specified dependencies at runtime. +.. _environment-markers: + Platform specific dependencies ------------------------------ Setuptools offers the capability to evaluate certain conditions before blindly @@ -165,101 +171,22 @@ and only install it if the user is using a Windows operating system: # ... The environmental markers that may be used for testing platform types are -detailed in `PEP 508 <https://www.python.org/dev/peps/pep-0508/>`_. - - -Dependencies that aren't in PyPI --------------------------------- -.. warning:: - Dependency links support has been dropped by pip starting with version - 19.0 (released 2019-01-22). - -If your project depends on packages that don't exist on PyPI, you may still be -able to depend on them, as long as they are available for download as: - -- an egg, in the standard distutils ``sdist`` format, -- a single ``.py`` file, or -- a VCS repository (Subversion, Mercurial, or Git). - -You just need to add some URLs to the ``dependency_links`` argument to -``setup()``. - -The URLs must be either: - -1. direct download URLs, -2. the URLs of web pages that contain direct download links, or -3. the repository's URL - -In general, it's better to link to web pages, because it is usually less -complex to update a web page than to release a new version of your project. -You can also use a SourceForge ``showfiles.php`` link in the case where a -package you depend on is distributed via SourceForge. - -If you depend on a package that's distributed as a single ``.py`` file, you -must include an ``"#egg=project-version"`` suffix to the URL, to give a project -name and version number. (Be sure to escape any dashes in the name or version -by replacing them with underscores.) EasyInstall will recognize this suffix -and automatically create a trivial ``setup.py`` to wrap the single ``.py`` file -as an egg. - -In the case of a VCS checkout, you should also append ``#egg=project-version`` -in order to identify for what package that checkout should be used. You can -append ``@REV`` to the URL's path (before the fragment) to specify a revision. -Additionally, you can also force the VCS being used by prepending the URL with -a certain prefix. Currently available are: - -- ``svn+URL`` for Subversion, -- ``git+URL`` for Git, and -- ``hg+URL`` for Mercurial - -A more complete example would be: - - ``vcs+proto://host/path@revision#egg=project-version`` - -Be careful with the version. It should match the one inside the project files. -If you want to disregard the version, you have to omit it both in the -``requires`` and in the URL's fragment. - -This will do a checkout (or a clone, in Git and Mercurial parlance) to a -temporary folder and run ``setup.py bdist_egg``. - -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: - -.. tab:: setup.cfg - - .. code-block:: ini - - [options] - #... - dependency_links = http://peak.telecommunity.com/snapshots/ - -.. tab:: setup.py +detailed in :pep:`508`. - .. code-block:: python - - setup( - ..., - dependency_links=[ - "http://peak.telecommunity.com/snapshots/", - ], - ) +.. seealso:: + If environment markers are not enough an specific use case, + you can also consider creating a :ref:`backend wrapper <backend-wrapper>` + to implement custom detection logic. Optional dependencies ===================== -Setuptools allows you to declare dependencies that only get installed under -specific circumstances. These dependencies are specified with the ``extras_require`` -keyword and are only installed if another package depends on it (either -directly or indirectly). This makes it convenient to declare dependencies for -ancillary functions such as "tests" and "docs". - -.. note:: - ``tests_require`` is now deprecated +Setuptools allows you to declare dependencies that are not installed by default. +This effectively means that you can create a "variant" of your package with a +set of extra functionalities. -For example, Package-A offers optional PDF support and requires two other -dependencies for it to work: +For example, let's consider a ``Package-A`` that offers +optional PDF support and requires two other dependencies for it to work: .. tab:: setup.cfg @@ -269,7 +196,9 @@ dependencies for it to work: name = Package-A [options.extras_require] - PDF = ReportLab>=1.2; RXP + PDF = + ReportLab>=1.2 + RXP .. tab:: setup.py @@ -277,7 +206,7 @@ dependencies for it to work: .. code-block:: python setup( - name="Project-A", + name="Package-A", ..., extras_require={ "PDF": ["ReportLab>=1.2", "RXP"], @@ -288,15 +217,23 @@ dependencies for it to work: .. code-block:: toml + [project] + name = "Package-A" # ... [project.optional-dependencies] PDF = ["ReportLab>=1.2", "RXP"] -The name ``PDF`` is an arbitrary identifier of such a list of dependencies, to +.. sidebar:: + + .. tip:: + It is also convenient to declare optional requirements for + ancillary tasks such as running tests and or building docs. + +The name ``PDF`` is an arbitrary :pep:`identifier <685>` of such a list of dependencies, to which other components can refer and have them installed. A use case for this approach is that other package can use this "extra" for their -own dependencies. For example, if "Project-B" needs "project A" with PDF support +own dependencies. For example, if ``Package-B`` needs ``Package-B`` with PDF support installed, it might declare the dependency like this: .. tab:: setup.cfg @@ -304,21 +241,21 @@ installed, it might declare the dependency like this: .. code-block:: ini [metadata] - name = Project-B + name = Package-B #... [options] #... install_requires = - Project-A[PDF] + Package-A[PDF] .. tab:: setup.py .. code-block:: python setup( - name="Project-B", - install_requires=["Project-A[PDF]"], + name="Package-B", + install_requires=["Package-A[PDF]"], ..., ) @@ -327,71 +264,71 @@ installed, it might declare the dependency like this: .. code-block:: toml [project] - name = "Project-B" + name = "Package-B" # ... dependencies = [ - "Project-A[PDF]" + "Package-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 +This will cause ``ReportLab`` to be installed along with ``Package-A``, if ``Package-B`` is +installed -- even if ``Package-A`` was already installed. In this way, a project can encapsulate groups of optional "downstream dependencies" under a feature name, so that packages that depend on it don't have to know what the downstream -dependencies are. If a later version of Project A builds in PDF support and -no longer needs ReportLab, or if it ends up needing other dependencies besides -ReportLab in order to provide PDF support, Project B's setup information does +dependencies are. If a later version of ``Package-A`` builds in PDF support and +no longer needs ``ReportLab``, or if it ends up needing other dependencies besides +``ReportLab`` in order to provide PDF support, ``Package-B``'s setup information does not need to change, but the right packages will still be installed if needed. -.. note:: +.. tip:: Best practice: if a project ends up no longer needing any other packages to support a feature, it should keep an empty requirements list for that feature in its ``extras_require`` argument, so that packages depending on that feature don't break (due to an invalid feature name). -Historically ``setuptools`` also used to support extra dependencies in console -scripts, for example: +.. warning:: + Historically ``setuptools`` also used to support extra dependencies in console + scripts, for example: -.. tab:: setup.cfg + .. tab:: setup.cfg - .. code-block:: ini + .. code-block:: ini - [metadata] - name = Project A - #... + [metadata] + name = Package-A + #... - [options] - #... - entry_points= - [console_scripts] - rst2pdf = project_a.tools.pdfgen [PDF] - rst2html = project_a.tools.htmlgen + [options] + #... + entry_points= + [console_scripts] + rst2pdf = project_a.tools.pdfgen [PDF] + rst2html = project_a.tools.htmlgen -.. tab:: setup.py + .. tab:: setup.py - .. code-block:: python + .. code-block:: python - setup( - name="Project-A", - ..., - entry_points={ - "console_scripts": [ - "rst2pdf = project_a.tools.pdfgen [PDF]", - "rst2html = project_a.tools.htmlgen", - ], - }, - ) + setup( + name="Package-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). + 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). -.. warning:: - ``pip`` and other tools might not support this use case for extra - dependencies, therefore this practice is considered **deprecated**. - See :doc:`PyPUG:specifications/entry-points`. + **However**, ``pip`` and other tools might not support this use case for extra + dependencies, therefore this practice is considered **deprecated**. + See :doc:`PyPUG:specifications/entry-points`. Python requirement @@ -404,7 +341,7 @@ This can be configured as shown in the example below. .. code-block:: ini [metadata] - name = Project-B + name = Package-B #... [options] @@ -416,7 +353,7 @@ This can be configured as shown in the example below. .. code-block:: python setup( - name="Project-B", + name="Package-B", python_requires=">=3.6", ..., ) @@ -427,7 +364,7 @@ This can be configured as shown in the example below. .. code-block:: toml [project] - name = "Project-B" + name = "Package-B" requires-python = ">=3.6" # ... @@ -441,3 +378,6 @@ This can be configured as shown in the example below. options via the ``[project]`` and ``[tool.setuptools]`` tables is still experimental and might change in future releases. See :doc:`/userguide/pyproject_config`. + + +.. _PyPI: https://pypi.org diff --git a/docs/userguide/development_mode.rst b/docs/userguide/development_mode.rst index 90bc5676..fafcc527 100644 --- a/docs/userguide/development_mode.rst +++ b/docs/userguide/development_mode.rst @@ -1,13 +1,13 @@ "Development Mode" ================== -Under normal circumstances, the ``distutils`` assume that you are going to +Under normal circumstances, the ``setuptools`` assume that you are going to build a distribution of your project, not use it in its "raw" or "unbuilt" -form. However, if you were to use the ``distutils`` to build a distribution, +form. However, if you were to use the ``setuptools`` 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 +Another problem that sometimes comes is that you may need to do development on two related projects at the same time. You may need to put both projects' packages in the same directory to run them, but need to keep them separate for revision control purposes. How can you do this? @@ -15,38 +15,20 @@ keep them separate for revision control purposes. How can you do this? Setuptools allows you to deploy your projects for use in a common directory or staging area, but without copying any files. Thus, you can edit each project's code in its checkout directory, and only need to run build commands when you -change a project's C extensions or similarly compiled files. You can even -deploy a project into another project's checkout directory, if that's your -preferred way of working (as opposed to using a common independent staging area -or the site-packages directory). - -To do this, use the ``setup.py develop`` command. It works very similarly to -``setup.py install``, except that it doesn't actually install anything. -Instead, it creates a special ``.egg-link`` file in the deployment directory, -that links to your project's source code. And, if your deployment directory is -Python's ``site-packages`` directory, it will also update the -``easy-install.pth`` file to include your project's source code, thereby making +change files that need to be compiled or the provided metadata and setuptools configuration. + +You can perform a ``pip`` installation passing the ``-e/--editable`` +flag (e.g., ``pip install -e .``). It works very similarly to +``pip install .``, except that it doesn't actually install anything. +Instead, it creates a special ``.egg-link`` file in the target directory +(usually ``site-packages``) that links to your project's source code. +It may also update an existing ``easy-install.pth`` file +to include your project's source code, thereby making it available on ``sys.path`` for all programs using that Python installation. -In addition, the ``develop`` command creates wrapper scripts in the target -script directory that will run your in-development scripts after ensuring that -all your ``install_requires`` packages are available on ``sys.path``. - -You can deploy the same project to multiple staging areas, e.g. if you have +You can deploy the same project to multiple staging areas, e.g., if you have multiple projects on the same machine that are sharing the same project you're doing development work. -When you're done with a given development task, you can remove the project -source from a staging area using ``setup.py develop --uninstall``, specifying -the desired staging area if it's not the default. - -There are several options to control the precise behavior of the ``develop`` -command; see the section on the :ref:`develop <develop>` command below for more details. - -Note that you can also apply setuptools commands to non-setuptools projects, -using commands like this:: - - python -c "import setuptools; with open('setup.py') as f: exec(compile(f.read(), 'setup.py', 'exec'))" develop - -That is, you can simply list the normal setup commands and options following -the quoted part. +When you're done with a given development task, you can simply uninstall your +package (as you would normally do with ``pip uninstall <package name>``). diff --git a/docs/userguide/extension.rst b/docs/userguide/extension.rst index 21fb05b6..f1dce94b 100644 --- a/docs/userguide/extension.rst +++ b/docs/userguide/extension.rst @@ -1,60 +1,83 @@ .. _Creating ``distutils`` Extensions: -Creating ``distutils`` Extensions -================================= +Extending or Customizing Setuptools +=================================== -It can be hard to add new commands or setup arguments to the distutils. But -the ``setuptools`` package makes it a bit easier, by allowing you to distribute -a distutils extension as a separate project, and then have projects that need -the extension just refer to it in their ``setup_requires`` argument. +Setuptools design is based on the distutils_ package originally distributed +as part of Python's standard library, effectively serving as its successor +(as established in :pep:`632`). -With ``setuptools``, your distutils extension projects can hook in new +This means that ``setuptools`` strives to honor the extension mechanisms +provided by ``distutils``, and allows developers to create third party packages +that modify or augment the build process behavior. + +A simple way of doing that is to hook in new or existing commands and ``setup()`` arguments just by defining "entry points". These are mappings from command or argument names to a specification of where to import a handler from. (See the section on :ref:`Dynamic Discovery of -Services and Plugins` above for some more background on entry points.) - - -Adding Commands ---------------- - -You can add new ``setup`` commands by defining entry points in the -``distutils.commands`` group. For example, if you wanted to add a ``foo`` -command, you might add something like this to your distutils extension -project's setup script:: - - setup( - # ... - entry_points={ - "distutils.commands": [ - "foo = mypackage.some_module:foo", - ], - }, - ) +Services and Plugins` for some more background on entry points). + +The following sections describe the most common procedures for extending +the ``distutils`` functionality used by ``setuptools``. + +.. important:: + Any entry-point defined in your ``setup.cfg``, ``setup.py`` or + ``pyproject.toml`` files are not immediately available for use. Your + package needs to be installed first, then ``setuptools`` will be able to + access these entry points. For example consider a ``Project-A`` that + defines entry points. When building ``Project-A``, these will not be + available. If ``Project-B`` declares a :doc:`build system requirement + </userguide/dependency_management>` on ``Project-A``, then ``setuptools`` + will be able to use ``Project-A``' customizations. + +Customizing Commands +-------------------- + +Both ``setuptools`` and ``distutils`` are structured around the *command design +pattern*. This means that each main action executed when building a +distribution package (such as creating a :term:`sdist <Source Distribution (or "sdist")>` +or :term:`wheel`) correspond to the implementation of a Python class. + +Originally in ``distutils``, these commands would correspond to actual CLI +arguments that could be passed to the ``setup.py`` script to trigger a +different aspect of the build. In ``setuptools``, however, these command +objects are just a design abstraction that encapsulate logic and help to +organise the code. + +You can overwrite exiting commands (or add new ones) by defining entry +points in the ``distutils.commands`` group. For example, if you wanted to add +a ``foo`` command, you might add something like this to your project: + +.. code-block:: ini + + # setup.cfg + ... + [options.entry_points] + distutils.commands = + foo = mypackage.some_module:foo (Assuming, of course, that the ``foo`` class in ``mypackage.some_module`` is a ``setuptools.Command`` subclass.) Once a project containing such entry points has been activated on ``sys.path``, -(e.g. by running "install" or "develop" with a site-packages installation -directory) the command(s) will be available to any ``setuptools``-based setup -scripts. It is not necessary to use the ``--command-packages`` option or -to monkeypatch the ``distutils.command`` package to install your commands; -``setuptools`` automatically adds a wrapper to the distutils to search for -entry points in the active distributions on ``sys.path``. In fact, this is +(e.g. by running ``pip install``) the command(s) will be available to any +``setuptools``-based project. In fact, this is how setuptools' own commands are installed: the setuptools project's setup script defines entry points for them! -.. note:: - When creating commands, and specially when defining custom ways of building - compiled extensions (for example via ``build_ext``), consider - handling exceptions such as ``CompileError``, ``LinkError``, ``LibError``, - among others. These exceptions are available in the ``setuptools.errors`` - module. +The commands ``sdist``, ``build_py`` and ``build_ext`` are especially useful +to customize ``setuptools`` builds. Note however that when overwriting existing +commands, you should be very careful to maintain API compatibility. +Custom commands should try to replicate the same overall behavior as the +original classes, and when possible, even inherit from them. +You should also consider handling exceptions such as ``CompileError``, +``LinkError``, ``LibError``, among others. These exceptions are available in +the ``setuptools.errors`` module. -Adding ``setup()`` Arguments ----------------------------- + +Adding Arguments +---------------- .. warning:: Adding arguments to setup is discouraged as such arguments are only supported through imperative execution and not supported through @@ -64,19 +87,17 @@ Sometimes, your commands may need additional arguments to the ``setup()`` call. You can enable this by defining entry points in the ``distutils.setup_keywords`` group. For example, if you wanted a ``setup()`` argument called ``bar_baz``, you might add something like this to your -distutils extension project's setup script:: - - setup( - # ... - entry_points={ - "distutils.commands": [ - "foo = mypackage.some_module:foo", - ], - "distutils.setup_keywords": [ - "bar_baz = mypackage.some_module:validate_bar_baz", - ], - }, - ) +extension project: + +.. code-block:: ini + + # setup.cfg + ... + [options.entry_points] + distutils.commands = + foo = mypackage.some_module:foo + distutils.setup_keywords = + bar_baz = mypackage.some_module:validate_bar_baz The idea here is that the entry point defines a function that will be called to validate the ``setup()`` argument, if it's supplied. The ``Distribution`` @@ -93,7 +114,7 @@ a non-None value. Here's an example validation function:: Your function should accept three arguments: the ``Distribution`` object, the attribute name, and the attribute value. It should raise a -``DistutilsSetupError`` (from the ``distutils.errors`` module) if the argument +``SetupError`` (from the ``setuptools.errors`` module) if the argument is invalid. Remember, your function will only be called with non-None values, and the default value of arguments defined this way is always None. So, your commands should always be prepared for the possibility that the attribute will @@ -101,15 +122,9 @@ be ``None`` when they access it later. If more than one active distribution defines an entry point for the same ``setup()`` argument, *all* of them will be called. This allows multiple -distutils extensions to define a common argument, as long as they agree on +extensions to define a common argument, as long as they agree on what values of that argument are valid. -Also note that as with commands, it is not necessary to subclass or monkeypatch -the distutils ``Distribution`` class in order to add your arguments; it is -sufficient to define the entry points in your extension, as long as any setup -script using your extension lists your project in its ``setup_requires`` -argument. - Customizing Distribution Options -------------------------------- @@ -130,36 +145,48 @@ plugin is encouraged to load the configuration/settings for their behavior independently. +Defining Additional Metadata +---------------------------- + +Some extensible applications and frameworks may need to define their own kinds +of metadata, which they can then access using the :mod:`importlib.metadata` APIs. +Ordinarily, this is done by having plugin +developers include additional files in their ``ProjectName.egg-info`` +directory. However, since it can be tedious to create such files by hand, you +may want to create an extension that will create the necessary files +from arguments to ``setup()``, in much the same way that ``setuptools`` does +for many of the ``setup()`` arguments it adds. See the section below for more +details. + + .. _Adding new EGG-INFO Files: Adding new EGG-INFO Files -------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~ Some extensible applications or frameworks may want to allow third parties to develop plugins with application or framework-specific metadata included in the plugins' EGG-INFO directory, for easy access via the ``pkg_resources`` -metadata API. The easiest way to allow this is to create a distutils extension +metadata API. The easiest way to allow this is to create an extension to be used from the plugin projects' setup scripts (via ``setup_requires``) that defines a new setup keyword, and then uses that data to write an EGG-INFO file when the ``egg_info`` command is run. The ``egg_info`` command looks for extension points in an ``egg_info.writers`` -group, and calls them to write the files. Here's a simple example of a -distutils extension defining a setup argument ``foo_bar``, which is a list of +group, and calls them to write the files. Here's a simple example of an +extension defining a setup argument ``foo_bar``, which is a list of lines that will be written to ``foo_bar.txt`` in the EGG-INFO directory of any -project that uses the argument:: - - setup( - # ... - entry_points={ - "distutils.setup_keywords": [ - "foo_bar = setuptools.dist:assert_string_list", - ], - "egg_info.writers": [ - "foo_bar.txt = setuptools.command.egg_info:write_arg", - ], - }, - ) +project that uses the argument: + +.. code-block:: ini + + # setup.cfg + ... + [options.entry_points] + distutils.setup_keywords = + foo_bar = setuptools.dist:assert_string_list + egg_info.writers = + foo_bar.txt = setuptools.command.egg_info:write_arg This simple example makes use of two utility functions defined by setuptools for its own use: a routine to validate that a setup keyword is a sequence of @@ -179,11 +206,11 @@ write (e.g. ``foo_bar.txt``), and the actual full filename that should be written to. In general, writer functions should honor the command object's ``dry_run`` -setting when writing files, and use the ``distutils.log`` object to do any -console output. The easiest way to conform to this requirement is to use +setting when writing files, and use ``logging`` to do any console output. +The easiest way to conform to this requirement is to use the ``cmd`` object's ``write_file()``, ``delete_file()``, and -``write_or_delete_file()`` methods exclusively for your file operations. See -those methods' docstrings for more details. +``write_or_delete_file()`` methods exclusively for your file operations. +See those methods' docstrings for more details. .. _Adding Support for Revision Control Systems: @@ -212,13 +239,16 @@ called "foobar", you would write a function something like this: def find_files_for_foobar(dirname): ... # loop to yield paths that start with `dirname` -And you would register it in a setup script using something like this:: +And you would register it in a setup script using something like this: + +.. code-block:: ini + + # setup.cfg + ... - entry_points={ - "setuptools.file_finders": [ - "foobar = my_foobar_module:find_files_for_foobar", - ] - } + [options.entry_points] + setuptools.file_finders = + foobar = my_foobar_module:find_files_for_foobar Then, anyone who wants to use your plugin can simply install it, and their local setuptools installation will be able to find the necessary files. @@ -248,3 +278,18 @@ A few important points for writing revision control file finders: with the absence of needed programs (i.e., ones belonging to the revision control system itself. It *may*, however, use ``distutils.log.warn()`` to inform the user of the missing program(s). + + +.. _distutils: https://docs.python.org/3.9/library/distutils.html + + +Final Remarks +------------- + +* To use a ``setuptools`` plugin, your users will need to add your package as a + build requirement to their build-system configuration. Please check out our + guides on :doc:`/userguide/dependency_management` for more information. + +* Directly calling ``python setup.py ...`` is considered a **deprecated** practice. + You should not add new commands to ``setuptools`` expecting them to be run + via this interface. diff --git a/docs/userguide/functionalities_rewrite.rst b/docs/userguide/functionalities_rewrite.rst deleted file mode 100644 index d0997ca6..00000000 --- a/docs/userguide/functionalities_rewrite.rst +++ /dev/null @@ -1,9 +0,0 @@ -======================================================== -Using setuptools to package and distribute your project -======================================================== - -``setuptools`` offers a variety of functionalities that make it easy to -build and distribute your python package. Here we provide an overview on -the commonly used ones. - - diff --git a/docs/userguide/index.rst b/docs/userguide/index.rst index 74e9b1e4..d5d150af 100644 --- a/docs/userguide/index.rst +++ b/docs/userguide/index.rst @@ -2,22 +2,24 @@ Building and Distributing Packages with Setuptools ================================================== -``Setuptools`` is a collection of enhancements to the Python ``distutils`` -that allow developers to more easily build and -distribute Python packages, especially ones that have dependencies on other -packages. +The first step towards sharing a Python library or program is to build a +distribution package [#package-overload]_. This includes adding a set of +additional files containing metadata and configuration to not only instruct +``setuptools`` on how the distribution should be built but also +to help installer (such as :pypi:`pip`) during the installation process. -Packages built and distributed using ``setuptools`` look to the user like -ordinary Python packages based on the ``distutils``. +This document contains information to help Python developers through this +process. Please check the :doc:`/userguide/quickstart` for an overview of +the workflow. -Transition to PEP517 -==================== +Also note that ``setuptools`` is what is know in the community as :pep:`build +backend <517#terminology-and-goals>`, user facing interfaces are provided by tools +such as :pypi:`pip` and :pypi:`build`. To use ``setuptools``, one must +explicitly create a ``pyproject.toml`` file as described :doc:`/build_meta`. -Since setuptools no longer serves as the default build tool, one must explicitly -opt in (by providing a :file:`pyproject.toml` file) to use this library. The user -facing part is provided by tools such as pip and -backend interface is described :doc:`in this document <../build_meta>`. The -quickstart provides an overview of the new workflow. + +Contents +======== .. toctree:: :maxdepth: 1 @@ -33,5 +35,14 @@ quickstart provides an overview of the new workflow. declarative_config pyproject_config commands - functionalities_rewrite miscellaneous + +--- + +.. rubric:: Notes + +.. [#package-overload] + A :term:`Distribution Package` is also referred in the Python community simply as "package" + Unfortunately, this jargon might be a bit confusing for new users because the term package + can also to refer any :term:`directory <package>` (or sub directory) used to organize + :term:`modules <module>` and auxiliary files. diff --git a/docs/userguide/miscellaneous.rst b/docs/userguide/miscellaneous.rst index 5fd2f0a8..776f12f6 100644 --- a/docs/userguide/miscellaneous.rst +++ b/docs/userguide/miscellaneous.rst @@ -1,105 +1,7 @@ -.. _Automatic Resource Extraction: - -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. - -Defining Additional Metadata ----------------------------- - -Some extensible applications and frameworks may need to define their own kinds -of metadata to include in eggs, which they can then access using the -``pkg_resources`` metadata APIs. Ordinarily, this is done by having plugin -developers include additional files in their ``ProjectName.egg-info`` -directory. However, since it can be tedious to create such files by hand, you -may want to create a distutils extension that will create the necessary files -from arguments to ``setup()``, in much the same way that ``setuptools`` does -for many of the ``setup()`` arguments it adds. See the section below on -:ref:`Creating ``distutils\`\` Extensions` for more details, especially the -subsection on :ref:`Adding new EGG-INFO Files`. - -Setting the ``zip_safe`` flag ------------------------------ - -For some use cases (such as bundling as part of a larger application), Python -packages may be run directly from a zip file. -Not all packages, however, are capable of running in compressed form, because -they may expect to be able to access either source code or data files as -normal operating system files. So, ``setuptools`` can install your project -as a zipfile or a directory, and its default choice is determined by the -project's ``zip_safe`` flag. - -You can pass a True or False value for the ``zip_safe`` argument to the -``setup()`` function, or you can omit it. If you omit it, the ``bdist_egg`` -command will analyze your project's contents to see if it can detect any -conditions that would prevent it from working in a zipfile. It will output -notices to the console about any such conditions that it finds. - -Currently, this analysis is extremely conservative: it will consider the -project unsafe if it contains any C extensions or datafiles whatsoever. This -does *not* mean that the project can't or won't work as a zipfile! It just -means that the ``bdist_egg`` authors aren't yet comfortable asserting that -the project *will* work. If the project contains no C or data files, and does -no ``__file__`` or ``__path__`` introspection or source code manipulation, then -there is an extremely solid chance the project will work when installed as a -zipfile. (And if the project uses ``pkg_resources`` for all its data file -access, then C extensions and other data files shouldn't be a problem at all. -See the :ref:`Accessing Data Files at Runtime` section above for more information.) - -However, if ``bdist_egg`` can't be *sure* that your package will work, but -you've checked over all the warnings it issued, and you are either satisfied it -*will* work (or if you want to try it for yourself), then you should set -``zip_safe`` to ``True`` in your ``setup()`` call. If it turns out that it -doesn't work, you can always change it to ``False``, which will force -``setuptools`` to install your project as a directory rather than as a zipfile. - -In the future, as we gain more experience with different packages and become -more satisfied with the robustness of the ``pkg_resources`` runtime, the -"zip safety" analysis may become less conservative. However, we strongly -recommend that you determine for yourself whether your project functions -correctly when installed as a zipfile, correct any problems if you can, and -then make an explicit declaration of ``True`` or ``False`` for the ``zip_safe`` -flag, so that it will not be necessary for ``bdist_egg`` to try to guess -whether your project can work as a zipfile. - - .. _Controlling files in the distribution: Controlling files in the distribution -------------------------------------- +===================================== For the most common use cases, ``setuptools`` will automatically find out which files are necessary for distributing the package. diff --git a/docs/userguide/quickstart.rst b/docs/userguide/quickstart.rst index c4757b98..0b759473 100644 --- a/docs/userguide/quickstart.rst +++ b/docs/userguide/quickstart.rst @@ -1,6 +1,6 @@ -========================== -``setuptools`` Quickstart -========================== +========== +Quickstart +========== Installation ============ @@ -286,10 +286,8 @@ For more advanced use, see :doc:`dependency_management`. 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: +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 @@ -319,7 +317,7 @@ can simply use the ``include_package_data`` keyword: # 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 +The data files must be specified via the |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`. |