1.. _`entry_points`: 2 3============ 4Entry Points 5============ 6 7Packages may provide commands to be run at the console (console scripts), 8such as the ``pip`` command. These commands are defined for a package 9as a specific kind of entry point in the ``setup.cfg`` or 10``setup.py``. 11 12 13Console Scripts 14=============== 15 16First consider an example without entry points. Imagine a package 17defined thus: 18 19.. code-block:: bash 20 21 timmins/ 22 timmins/__init__.py 23 timmins/__main__.py 24 setup.cfg # or setup.py 25 #other necessary files 26 27with ``__init__.py`` as: 28 29.. code-block:: python 30 31 def hello_world(): 32 print("Hello world") 33 34and ``__main__.py`` providing a hook: 35 36.. code-block:: python 37 38 from . import hello_world 39 40 if __name__ == '__main__': 41 hello_world() 42 43After installing the package, the function may be invoked through the 44`runpy <https://docs.python.org/3/library/runpy.html>`_ module: 45 46.. code-block:: bash 47 48 python -m timmins 49 50Adding a console script entry point allows the package to define a 51user-friendly name for installers of the package to execute. Installers 52like pip will create wrapper scripts to execute a function. In the 53above example, to create a command ``hello-world`` that invokes 54``timmins.hello_world``, add a console script entry point to 55``setup.cfg``: 56 57.. tab:: setup.cfg 58 59 .. code-block:: ini 60 61 [options.entry_points] 62 console_scripts = 63 hello-world = timmins:hello_world 64 65.. tab:: setup.py 66 67 .. code-block:: python 68 69 from setuptools import setup 70 71 setup( 72 name='timmins', 73 version='0.0.1', 74 packages=['timmins'], 75 # ... 76 entry_points={ 77 'console_scripts': [ 78 'hello-world=timmins:hello_world', 79 ] 80 } 81 ) 82 83 84After installing the package, a user may invoke that function by simply calling 85``hello-world`` on the command line. 86 87The syntax for entry points is specified as follows: 88 89.. code-block:: ini 90 91 <name> = [<package>.[<subpackage>.]]<module>[:<object>.<object>] 92 93where ``name`` is the name for the script you want to create, the left hand 94side of ``:`` is the module that contains your function and the right hand 95side is the object you want to invoke (e.g. a function). 96 97In addition to ``console_scripts``, Setuptools supports ``gui_scripts``, which 98will launch a GUI application without running in a terminal window. 99 100 101.. _dynamic discovery of services and plugins: 102 103Advertising Behavior 104==================== 105 106Console scripts are one use of the more general concept of entry points. Entry 107points more generally allow a packager to advertise behavior for discovery by 108other libraries and applications. This feature enables "plug-in"-like 109functionality, where one library solicits entry points and any number of other 110libraries provide those entry points. 111 112A good example of this plug-in behavior can be seen in 113`pytest plugins <https://docs.pytest.org/en/latest/writing_plugins.html>`_, 114where pytest is a test framework that allows other libraries to extend 115or modify its functionality through the ``pytest11`` entry point. 116 117The console scripts work similarly, where libraries advertise their commands 118and tools like ``pip`` create wrapper scripts that invoke those commands. 119 120For a project wishing to solicit entry points, Setuptools recommends the 121`importlib.metadata <https://docs.python.org/3/library/importlib.metadata.html>`_ 122module (part of stdlib since Python 3.8) or its backport, 123:pypi:`importlib_metadata`. 124 125For example, to find the console script entry points from the example above: 126 127.. code-block:: pycon 128 129 >>> from importlib import metadata 130 >>> eps = metadata.entry_points()['console_scripts'] 131 132``eps`` is now a list of ``EntryPoint`` objects, one of which corresponds 133to the ``hello-world = timmins:hello_world`` defined above. Each ``EntryPoint`` 134contains the ``name``, ``group``, and ``value``. It also supplies a ``.load()`` 135method to import and load that entry point (module or object). 136 137.. code-block:: ini 138 139 [options.entry_points] 140 my.plugins = 141 hello-world = timmins:hello_world 142 143Then, a different project wishing to load 'my.plugins' plugins could run 144the following routine to load (and invoke) such plugins: 145 146.. code-block:: pycon 147 148 >>> from importlib import metadata 149 >>> eps = metadata.entry_points()['my.plugins'] 150 >>> for ep in eps: 151 ... plugin = ep.load() 152 ... plugin() 153 ... 154 155The project soliciting the entry points needs not to have any dependency 156or prior knowledge about the libraries implementing the entry points, and 157downstream users are able to compose functionality by pulling together 158libraries implementing the entry points. 159 160 161Dependency Management 162===================== 163 164Some entry points may require additional dependencies to properly function. 165For such an entry point, declare in square brackets any number of dependency 166``extras`` following the entry point definition. Such entry points will only 167be viable if their extras were declared and installed. See the 168:doc:`guide on dependencies management <dependency_management>` for 169more information on defining extra requirements. Consider from the 170above example: 171 172.. code-block:: ini 173 174 [options.entry_points] 175 console_scripts = 176 hello-world = timmins:hello_world [pretty-printer] 177 178In this case, the ``hello-world`` script is only viable if the ``pretty-printer`` 179extra is indicated, and so a plugin host might exclude that entry point 180(i.e. not install a console script) if the relevant extra dependencies are not 181installed. 182