Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
setuptools
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jérome Perrin
setuptools
Commits
a5b144e3
Commit
a5b144e3
authored
Jul 03, 2020
by
Jason R. Coombs
Committed by
GitHub
Jul 03, 2020
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2154 from alvyjudy/entrypoint
Step 6 on 2093: userguide on entry points now available
parents
01a87625
dfe2ef5d
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
154 additions
and
115 deletions
+154
-115
docs/userguide/entry_point.txt
docs/userguide/entry_point.txt
+154
-115
No files found.
docs/userguide/entry_point.txt
View file @
a5b144e3
==========================================
.. _`entry_points`:
Entry Points and Automatic Script Creation
==========================================
============
Entry Points
Packaging and installing scripts can be a bit awkward with the distutils. For
============
one thing, there's no easy way to have a script's filename match local
conventions on both Windows and POSIX platforms. For another, you often have
Packages may provide commands to be run at the console (console scripts),
to create a separate file just for the "main" script, when your actual "main"
such as the ``pip`` command. These commands are defined for a package
is a function in a module somewhere. And even in Python 2.4, using the ``-m``
as a specific kind of entry point in the ``setup.cfg`` or
option only works for actual ``.py`` files that aren't installed in a package.
``setup.py``.
``setuptools`` fixes all of these problems by automatically generating scripts
for you with the correct extension, and on Windows it will even create an
Console Scripts
``.exe`` file so that users don't have to change their ``PATHEXT`` settings.
===============
The way to use this feature is to define "entry points" in your setup script
that indicate what function the generated script should import and run. For
First consider an example without entry points. Imagine a package
example, to create two console scripts called ``foo`` and ``bar``, and a GUI
defined thus::
script called ``baz``, you might do something like this::
.. code-block:: bash
setup(
# other arguments here...
timmins/
entry_points={
timmins/__init__.py
"console_scripts": [
timmins/__main__.py
"foo = my_package.some_module:main_func",
setup.cfg # or setup.py
"bar = other_module:some_func",
#other necessary files
],
"gui_scripts": [
with ``__init__.py`` as:
"baz = my_package_gui:start_func",
]
.. code-block:: python
}
)
def helloworld():
print("Hello world")
When this project is installed on non-Windows platforms (using "setup.py
install", "setup.py develop", or with pip), a set of ``foo``, ``bar``,
and ``__main__.py`` providing a hook:
and ``baz`` scripts will be installed that import ``main_func`` and
``some_func`` from the specified modules. The functions you specify are
from . import hello_world
called with no arguments, and their return value is passed to
if __name__ == '__main__':
``sys.exit()``, so you can return an errorlevel or message to print to
hello_world()
stderr.
After installing the package, the function may be invoked through the
On Windows, a set of ``foo.exe``, ``bar.exe``, and ``baz.exe`` launchers are
`runpy <https://docs.python.org/3/library/runpy.html>`_ module::
created, alongside a set of ``foo.py``, ``bar.py``, and ``baz.pyw`` files. The
``.exe`` wrappers find and execute the right version of Python to run the
.. code-block:: bash
``.py`` or ``.pyw`` file.
python -m timmins
You may define as many "console script" and "gui script" entry points as you
like, and each one can optionally specify "extras" that it depends on, that
Adding a console script entry point allows the package to define a
will be added to ``sys.path`` when the script is run. For more information on
user-friendly name for installers of the package to execute. Installers
"extras", see the section below on `Declaring Extras`_. For more information
like pip will create wrapper scripts to execute a function. In the
on "entry points" in general, see the section below on `Dynamic Discovery of
above example, to create a command ``hello-world`` that invokes
Services and Plugins`_.
``timmins.hello_world``, add a console script entry point to
``setup.cfg``::
Dynamic Discovery of Services and Plugins
.. code-block:: ini
-----------------------------------------
[options.entry_points]
``setuptools`` supports creating libraries that "plug in" to extensible
console_scripts =
applications and frameworks, by letting you register "entry points" in your
hello-world = timmins:hello_world
project that can be imported by the application or framework.
After installing the package, a user may invoke that function by simply calling
For example, suppose that a blogging tool wants to support plugins
``hello-world`` on the command line.
that provide translation for various file types to the blog's output format.
The framework might define an "entry point group" called ``blogtool.parsers``,
The syntax for entry points is specified as follows:
and then allow plugins to register entry points for the file extensions they
support.
.. code-block::
This would allow people to create distributions that contain one or more
<name> = [<package>.[<subpackage>.]]<module>[:<object>.<object>]
parsers for different file types, and then the blogging tool would be able to
find the parsers at runtime by looking up an entry point for the file
where ``name`` is the name for the script you want to create, the left hand
extension (or mime type, or however it wants to).
side of ``:`` is the module that contains your function and the right hand
side is the object you want to invoke (e.g. a function).
Note that if the blogging tool includes parsers for certain file formats, it
can register these as entry points in its own setup script, which means it
In addition to ``console_scripts``, Setuptools supports ``gui_scripts``, which
doesn't have to special-case its built-in formats. They can just be treated
will launch a GUI application without running in a terminal window.
the same as any other plugin's entry points would be.
If you're creating a project that plugs in to an existing application or
Advertising Behavior
framework, you'll need to know what entry points or entry point groups are
====================
defined by that application or framework. Then, you can register entry points
in your setup script. Here are a few examples of ways you might register an
Console scripts are one use of the more general concept of entry points. Entry
``.rst`` file parser entry point in the ``blogtool.parsers`` entry point group,
points more generally allow a packager to advertise behavior for discovery by
for our hypothetical blogging tool::
other libraries and applications. This feature enables "plug-in"-like
functionality, where one library solicits entry points and any number of other
setup(
libraries provide those entry points.
# ...
entry_points={"blogtool.parsers": ".rst = some_module:SomeClass"}
A good example of this plug-in behavior can be seen in
)
`pytest plugins <https://docs.pytest.org/en/latest/writing_plugins.html>`_,
where pytest is a test framework that allows other libraries to extend
setup(
or modify its functionality through the ``pytest11`` entry point.
# ...
entry_points={"blogtool.parsers": [".rst = some_module:a_func"]}
The console scripts work similarly, where libraries advertise their commands
)
and tools like ``pip`` create wrapper scripts that invoke those commands.
setup(
For a project wishing to solicit entry points, Setuptools recommends the
# ...
`importlib.metadata <https://docs.python.org/3/library/importlib.metadata.html>`_
entry_points="""
module (part of stdlib since Python 3.8) or its backport,
[blogtool.parsers]
`importlib_metadata <https://pypi.org/project/importlib_metadata>`_.
.rst = some.nested.module:SomeClass.some_classmethod [reST]
""",
For example, to find the console script entry points from the example above::
extras_require=dict(reST="Docutils>=0.3.5")
)
.. code-block:: python
The ``entry_points`` argument to ``setup()`` accepts either a string with
>>> from importlib import metadata
``.ini``-style sections, or a dictionary mapping entry point group names to
>>> eps = metadata.entry_points()['console_scripts']
either strings or lists of strings containing entry point specifiers. An
entry point specifier consists of a name and value, separated by an ``=``
``eps`` is now a list of ``EntryPoint`` objects, one of which corresponds
sign. The value consists of a dotted module name, optionally followed by a
to the ``hello-world = timmins:hello_world`` defined above. Each ``EntryPoint``
``:`` and a dotted identifier naming an object within the module. It can
contains the ``name``, ``group``, and ``value``. It also supplies a ``.load()``
also include a bracketed list of "extras" that are required for the entry
method to import and load that entry point (module or object).
point to be used. When the invoking application or framework requests loading
of an entry point, any requirements implied by the associated extras will be
.. code-block:: ini
passed to ``pkg_resources.require()``, so that an appropriate error message
can be displayed if the needed package(s) are missing. (Of course, the
[options.entry_points]
invoking app or framework can ignore such errors if it wants to make an entry
my.plugins =
point optional if a requirement isn't installed.)
hello-world = timmins:hello_world
\ No newline at end of file
Then, a different project wishing to load 'my.plugins' plugins could run
the following routine to load (and invoke) such plugins::
.. code-block:: python
>>> 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.
Dependency Management
=====================
Some entry points may require additional dependencies to properly function.
For such an entry point, declare in square brakets any number of dependency
``extras`` following the entry point definition. Such entry points will only
be viable if their extras were declared and installed. See the
:ref:`guide on dependencies management <dependency_management>` for
more information on defining extra requirements. Consider from the
above example::
.. code-block:: ini
[options.entry_points]
console_scripts =
hello-world = timmins:hello_world [pretty-printer]
In this case, the ``hello-world`` script is only viable if the ``pretty-printer``
extra is indicated, and so a plugin host might exclude that entry point
(i.e. not install a console script) if the relevant extra dependencies are not
installed.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment