auto
  #   ˆl–Ðz¾” TÂXÔÝÆ_¸Å£Î„uÏÀË *    .. _Creating ``distutils`` Extensions:

Creating ``distutils`` Extensions
=================================

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.

With ``setuptools``, your distutils extension projects can hook in new
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",
            ],
        },
    )

(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
how setuptools' own commands are installed: the setuptools project's setup
script defines entry points for them!

Adding ``setup()`` Arguments
----------------------------

.. warning:: Adding arguments to setup is discouraged as such arguments
   are only supported through imperative execution and not supported through
   declarative config.

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",
            ],
        },
    )

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``
object will have the initial value of the attribute set to ``None``, and the
validation function will only be called if the ``setup()`` call sets it to
a non-None value.  Here's an example validation function::

    def assert_bool(dist, attr, value):
        """Verify that value is True, False, 0, or 1"""
        if bool(value) != value:
            raise DistutilsSetupError(
                "%r must be a boolean value (got %r)" % (attr,value)
            )

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
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
be ``None`` when they access it later.

If more than one active distribution defines an entry point for the same
``setup()`` argument,