From 1639d010a7469ca6cabf49d038dfcfb4a4472a3d Mon Sep 17 00:00:00 2001 From: alvyjudy Date: Tue, 26 May 2020 17:49:10 -0400 Subject: docs: detail userguide for entry point WIP --- docs/userguide/entry_point.txt | 118 +++++++++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 47 deletions(-) (limited to 'docs') diff --git a/docs/userguide/entry_point.txt b/docs/userguide/entry_point.txt index 18211a72..a23d223b 100644 --- a/docs/userguide/entry_point.txt +++ b/docs/userguide/entry_point.txt @@ -2,61 +2,82 @@ Entry Points and Automatic Script Creation ========================================== -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 -to create a separate file just for the "main" script, when your actual "main" -is a function in a module somewhere. And even in Python 2.4, using the ``-m`` -option only works for actual ``.py`` files that aren't installed in a package. - -``setuptools`` fixes all of these problems by automatically generating scripts -for you with the correct extension, and on Windows it will even create an -``.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 -example, to create two console scripts called ``foo`` and ``bar``, and a GUI -script called ``baz``, you might do something like this:: +When installing a package, you may realize you can invoke some commands without +explicitly calling the python interpreter. For example, instead of calling +``python -m pip install`` you can just do ``pip install``. The magic behind +this is entry point, a keyword passed to your ``setup.cfg`` or ``setup.py`` +to create script wrapped around function in your libraries. + + +Using entry point in your package +================================= +Let's start with an example. Suppose you have written your package like this: + +.. code-block:: bash + + timmins/ + timmins/__init__.py + setup.cfg + #other necessary files + +and in your ``__init__.py`` it defines a function: + +.. code-block:: python + + def helloworld(): + print("Hello world") + +After installing the package, you can invoke this function in the following +manner, without applying any magic: + +.. code-block:: bash + + python -m mypkg.helloworld + +But entry point simplifies this process and would create a wrapper script around +your function, making it behave more natively. To do that, add the following +lines to your ``setup.cfg`` or ``setup.py``: + +.. code-block:: ini + + [options] + #... + entry_points = + [console_scripts] + helloworld = mypkg:helloworld + +.. code-block:: python setup( - # other arguments here... - entry_points={ - "console_scripts": [ - "foo = my_package.some_module:main_func", - "bar = other_module:some_func", - ], - "gui_scripts": [ - "baz = my_package_gui:start_func", - ] - } + #... + entry_points = """ + [console_scripts] + helloworld = mypkg:helloworld + """ ) -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 ``baz`` scripts will be installed that import ``main_func`` and -``some_func`` from the specified modules. The functions you specify are -called with no arguments, and their return value is passed to -``sys.exit()``, so you can return an errorlevel or message to print to -stderr. +The syntax for your entry points is specified as follows -On Windows, a set of ``foo.exe``, ``bar.exe``, and ``baz.exe`` launchers are -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 -``.py`` or ``.pyw`` file. +.. code-block:: -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 -will be added to ``sys.path`` when the script is run. For more information on -"extras", see the section below on `Declaring Extras`_. For more information -on "entry points" in general, see the section below on `Dynamic Discovery of -Services and Plugins`_. + [] + = [..]: +where ``name`` is the name for the script you want to create and the left hand +side of ``:`` is the module that contains your function and the right hand +side is the function you wish to wrap. ``type`` specifies the type of script +you want to create. ``setuptools`` currently supports either ``[console_script]`` +and ``[gui_script]`` (DOUBLE CHECK ON THIS). -Dynamic Discovery of Services and Plugins ------------------------------------------ +After installation, you will be able to invoke that function simply calling +``helloworld`` on your command line. It will also do command line options parsing +for you! -``setuptools`` supports creating libraries that "plug in" to extensible -applications and frameworks, by letting you register "entry points" in your -project that can be imported by the application or framework. +Dynamic discovery of services and plugins +========================================= +The ability of entry points isn't limited to "advertising" your functions. In +fact, its implementation allows us to achieve more powerful features, such as +supporting libraries that "plus in" to extensible applications and frameworks For example, suppose that a blogging tool wants to support plugins that provide translation for various file types to the blog's output format. @@ -112,4 +133,7 @@ of an entry point, any requirements implied by the associated extras will be passed to ``pkg_resources.require()``, so that an appropriate error message can be displayed if the needed package(s) are missing. (Of course, the invoking app or framework can ignore such errors if it wants to make an entry -point optional if a requirement isn't installed.) \ No newline at end of file +point optional if a requirement isn't installed.) + +Dependencies management for entry points +======================================== -- cgit v1.2.1 From 45e784678b46636b7152ad7557d0757c3dfefaec Mon Sep 17 00:00:00 2001 From: alvyjudy Date: Wed, 27 May 2020 11:08:45 -0400 Subject: docs: update entry point userguide --- docs/userguide/entry_point.txt | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) (limited to 'docs') diff --git a/docs/userguide/entry_point.txt b/docs/userguide/entry_point.txt index a23d223b..5772698e 100644 --- a/docs/userguide/entry_point.txt +++ b/docs/userguide/entry_point.txt @@ -34,9 +34,10 @@ manner, without applying any magic: python -m mypkg.helloworld -But entry point simplifies this process and would create a wrapper script around -your function, making it behave more natively. To do that, add the following -lines to your ``setup.cfg`` or ``setup.py``: +But entry point simplifies the call and would create a wrapper script around +your function, making it behave more natively (you type in ``helloworld`` and +the ``helloworld`` function residing inside ``__init__.py`` is executed!). To +accomplish that, add the following lines to your ``setup.cfg`` or ``setup.py``: .. code-block:: ini @@ -56,22 +57,27 @@ lines to your ``setup.cfg`` or ``setup.py``: """ ) -The syntax for your entry points is specified as follows +The syntax for entry points is specified as follows: .. code-block:: [] - = [..]: + = [..][:.] -where ``name`` is the name for the script you want to create and the left hand +where ``name`` is the name for the script you want to create, the left hand side of ``:`` is the module that contains your function and the right hand -side is the function you wish to wrap. ``type`` specifies the type of script -you want to create. ``setuptools`` currently supports either ``[console_script]`` -and ``[gui_script]`` (DOUBLE CHECK ON THIS). - -After installation, you will be able to invoke that function simply calling -``helloworld`` on your command line. It will also do command line options parsing -for you! +side is the object you want to invoke (e.g. a function). ``type`` specifies the +type of script you want to create. ``setuptools`` currently supports either +``[console_script]`` and ``[gui_script]``. + +.. note:: + the syntax is not limited to ``INI`` string as demonstrated above. You can + also pass in the values in the form of a dictionary or list. Check out + :ref:`keyword reference ` for more details + +After installation, you will be able to invoke that function by simply calling +``helloworld`` on your command line. It will even do command line argument +parsing for you! Dynamic discovery of services and plugins ========================================= -- cgit v1.2.1 From 3eb1cecdd24c53bd07911177c52b3de253159709 Mon Sep 17 00:00:00 2001 From: alvyjudy Date: Thu, 28 May 2020 13:28:02 -0400 Subject: docs: guide on entry point completed Coverage 1. console_script 2. plugin support 3. optional dependencies --- docs/userguide/entry_point.txt | 181 +++++++++++++++++++++++++++-------------- 1 file changed, 118 insertions(+), 63 deletions(-) (limited to 'docs') diff --git a/docs/userguide/entry_point.txt b/docs/userguide/entry_point.txt index 5772698e..fe31f446 100644 --- a/docs/userguide/entry_point.txt +++ b/docs/userguide/entry_point.txt @@ -1,12 +1,14 @@ +.. _`entry_points`: + ========================================== Entry Points and Automatic Script Creation ========================================== -When installing a package, you may realize you can invoke some commands without -explicitly calling the python interpreter. For example, instead of calling -``python -m pip install`` you can just do ``pip install``. The magic behind -this is entry point, a keyword passed to your ``setup.cfg`` or ``setup.py`` -to create script wrapped around function in your libraries. +After installing some packages, you may realize you can invoke some commands +without explicitly calling the python interpreter. For example, instead of +calling ``python -m pip install`` you can just do ``pip install``. The magic +behind this is entry point, a keyword passed to your ``setup.cfg`` or +``setup.py`` to create script wrapped around function in your libraries. Using entry point in your package @@ -17,7 +19,7 @@ Let's start with an example. Suppose you have written your package like this: timmins/ timmins/__init__.py - setup.cfg + setup.cfg # or setup.py #other necessary files and in your ``__init__.py`` it defines a function: @@ -79,67 +81,120 @@ After installation, you will be able to invoke that function by simply calling ``helloworld`` on your command line. It will even do command line argument parsing for you! -Dynamic discovery of services and plugins -========================================= -The ability of entry points isn't limited to "advertising" your functions. In -fact, its implementation allows us to achieve more powerful features, such as -supporting libraries that "plus in" to extensible applications and frameworks - -For example, suppose that a blogging tool wants to support plugins -that provide translation for various file types to the blog's output format. -The framework might define an "entry point group" called ``blogtool.parsers``, -and then allow plugins to register entry points for the file extensions they -support. - -This would allow people to create distributions that contain one or more -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 -extension (or mime type, or however it wants to). - -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 -doesn't have to special-case its built-in formats. They can just be treated -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 -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 -``.rst`` file parser entry point in the ``blogtool.parsers`` entry point group, -for our hypothetical blogging tool:: - setup( - # ... - entry_points={"blogtool.parsers": ".rst = some_module:SomeClass"} - ) +Dynamic discovery of services (aka plugin support) +================================================== +The ability of entry points isn't limited to "advertising" your functions. Its +implementation allows us to accomplish more powerful features, such as creating +plugins. In fact, the aforementioned script wrapping ability is a form of +plugin that was built into ``setuptools``. With that being said, you now have +more options than ``[console_script]`` or ``[gui_script]`` when creating your +package. - setup( - # ... - entry_points={"blogtool.parsers": [".rst = some_module:a_func"]} - ) +To understand how you can extend this functionality, let's go through how +``setuptool`` does its ``[console_script]`` magic. Again, we use the same +example as above: - setup( - # ... - entry_points=""" - [blogtool.parsers] - .rst = some.nested.module:SomeClass.some_classmethod [reST] - """, - extras_require=dict(reST="Docutils>=0.3.5") - ) +.. code-block:: ini + + [options] + # ... + entry_points = + [console_scripts] + helloworld = mypkg:helloworld + +Package installation contains multiple steps, so at some point, this package +becomes available to your interpreter, and if you run the following code: + +.. code-block:: ini + + >>> import pkg_resources #a module part of setuptools + >>> [item for item in + pkg_srouces.working_set.iter_entry_points('console_scripts')] + +It will return a list of special objects (called "EntryPoints"), and there +will be one of them that corresponds to the ``helloworld = mypkg:helloworld`` +which we defined above. In fact, this object doesn't just contain the string, +but also an encompassing representation of the package that created it. +In the case of ``console_scripts``, setuptools will automatically invoke +an internal function that utilizes this object and create the wrapper scripts +and place them in your ``bin`` directory for your interpreter. How +``pkg_resource`` look up all the entry points is further detailed in our +:ref:`developer_guide` (WIP). With that being said, if you specify a different +entry point: + +.. code-block:: ini + + [options] + # ... + entry_points = + [iam.just.playing.around] + helloworld = mypkg:helloworld + +Then, running the same python expression like above: + +.. code-block:: python + + >>> import pkg_resources + >>> [item for item in + pkg_srouces.working_set.iter_entry_points('iam.just.playing.around') + ] + +will create another ``EntryPoints`` object that contains the +``helloworld = mypkg:helloworld`` and you can create custom +functions to exploit its information however you want. For example, one of +the installed programs on your system may contain a startup script that +scans the system for all the packages that specify this +``iam.just.playing.around`` entry points, such that when you install this new +package, it becomes immediately available without having to reconfigure +the already installed program. This in fact is the very idea of a plugin! -The ``entry_points`` argument to ``setup()`` accepts either a string with -``.ini``-style sections, or a dictionary mapping entry point group names to -either strings or lists of strings containing entry point specifiers. An -entry point specifier consists of a name and value, separated by an ``=`` -sign. The value consists of a dotted module name, optionally followed by a -``:`` and a dotted identifier naming an object within the module. It can -also include a bracketed list of "extras" that are required for the entry -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 -passed to ``pkg_resources.require()``, so that an appropriate error message -can be displayed if the needed package(s) are missing. (Of course, the -invoking app or framework can ignore such errors if it wants to make an entry -point optional if a requirement isn't installed.) Dependencies management for entry points ======================================== +Some entry points may require additional dependencies for them to work and +others may trigger the installation of additional dependencies only when they +are run. While this is elaborated in more excrutiating details on +:ref:`guide on dependencies management `, we will +provide a brief overview on the entry point aspect. + +Dependencies of this manner are declared using the ``extra_requires`` keywords, +which takes a mapping of the arbitary name of the functionality and a list of +its depencencies, optionally suffixed with its :ref:`version specifier +`. For example, our package provides "pdf" output capability +which requires at least 0.3 version of "ReportLab" and whatever version of "RXP" + +.. code-block:: ini + + [options.extras_require] + PDF = ReportLab>=1.2; RXP + +.. code-block:: python + + setup( + extras_require = { + "PDF": ["ReportLab>=1.2", "RXP"], + } + ) + + +And we only want them to be installed if the console script entry point +``rst2pdf`` is run: + +.. code-block:: ini + + [options] + entry_points = + ['console_script'] + rst2pdf = project_a.tools.pdfgen [PDF] + rst2html = project_a.tools.htmlgen + +.. code-block:: python + + setup( + entry_points = """ + ['console_script'] + rst2pdf = project_a.tools.pdfgen [PDF] + rst2html = project_a.tools.htmlgen + """ + ) -- cgit v1.2.1 From 1459bb4dcdc0f08463c71906952b35275be531de Mon Sep 17 00:00:00 2001 From: alvyjudy Date: Thu, 28 May 2020 14:32:49 -0400 Subject: docs: fixed mistaken explanation --- docs/userguide/entry_point.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/userguide/entry_point.txt b/docs/userguide/entry_point.txt index fe31f446..8190d8e3 100644 --- a/docs/userguide/entry_point.txt +++ b/docs/userguide/entry_point.txt @@ -69,8 +69,8 @@ The syntax for entry points is specified as follows: where ``name`` is the name for the script you want to create, the left hand 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). ``type`` specifies the -type of script you want to create. ``setuptools`` currently supports either -``[console_script]`` and ``[gui_script]``. +type of entry point (pertinent to the program that exploits it). ``setuptools`` +natively supports ``[console_script]`` and ``[gui_script]``. .. note:: the syntax is not limited to ``INI`` string as demonstrated above. You can -- cgit v1.2.1 From dfe2ef5d780f476db778aacfb37a44a017022180 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Mon, 15 Jun 2020 18:53:58 -0400 Subject: Correct some of the behaviors indicated in new entry points docs. Switch to imperative voice. Limit to declarative config (setup.cfg) examples. --- docs/userguide/entry_point.txt | 234 +++++++++++++++++------------------------ 1 file changed, 94 insertions(+), 140 deletions(-) (limited to 'docs') diff --git a/docs/userguide/entry_point.txt b/docs/userguide/entry_point.txt index 8190d8e3..7f5165a8 100644 --- a/docs/userguide/entry_point.txt +++ b/docs/userguide/entry_point.txt @@ -1,200 +1,154 @@ .. _`entry_points`: -========================================== -Entry Points and Automatic Script Creation -========================================== +============ +Entry Points +============ -After installing some packages, you may realize you can invoke some commands -without explicitly calling the python interpreter. For example, instead of -calling ``python -m pip install`` you can just do ``pip install``. The magic -behind this is entry point, a keyword passed to your ``setup.cfg`` or -``setup.py`` to create script wrapped around function in your libraries. +Packages may provide commands to be run at the console (console scripts), +such as the ``pip`` command. These commands are defined for a package +as a specific kind of entry point in the ``setup.cfg`` or +``setup.py``. -Using entry point in your package -================================= -Let's start with an example. Suppose you have written your package like this: +Console Scripts +=============== + +First consider an example without entry points. Imagine a package +defined thus:: .. code-block:: bash timmins/ timmins/__init__.py + timmins/__main__.py setup.cfg # or setup.py #other necessary files -and in your ``__init__.py`` it defines a function: +with ``__init__.py`` as: .. code-block:: python def helloworld(): print("Hello world") -After installing the package, you can invoke this function in the following -manner, without applying any magic: +and ``__main__.py`` providing a hook: + + from . import hello_world + if __name__ == '__main__': + hello_world() + +After installing the package, the function may be invoked through the +`runpy `_ module:: .. code-block:: bash - python -m mypkg.helloworld + python -m timmins -But entry point simplifies the call and would create a wrapper script around -your function, making it behave more natively (you type in ``helloworld`` and -the ``helloworld`` function residing inside ``__init__.py`` is executed!). To -accomplish that, add the following lines to your ``setup.cfg`` or ``setup.py``: +Adding a console script entry point allows the package to define a +user-friendly name for installers of the package to execute. Installers +like pip will create wrapper scripts to execute a function. In the +above example, to create a command ``hello-world`` that invokes +``timmins.hello_world``, add a console script entry point to +``setup.cfg``:: .. code-block:: ini - [options] - #... - entry_points = - [console_scripts] - helloworld = mypkg:helloworld - -.. code-block:: python + [options.entry_points] + console_scripts = + hello-world = timmins:hello_world - setup( - #... - entry_points = """ - [console_scripts] - helloworld = mypkg:helloworld - """ - ) +After installing the package, a user may invoke that function by simply calling +``hello-world`` on the command line. The syntax for entry points is specified as follows: .. code-block:: - [] - = [..][:.] + = [.[.]][:.] where ``name`` is the name for the script you want to create, the left hand 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). ``type`` specifies the -type of entry point (pertinent to the program that exploits it). ``setuptools`` -natively supports ``[console_script]`` and ``[gui_script]``. +side is the object you want to invoke (e.g. a function). -.. note:: - the syntax is not limited to ``INI`` string as demonstrated above. You can - also pass in the values in the form of a dictionary or list. Check out - :ref:`keyword reference ` for more details +In addition to ``console_scripts``, Setuptools supports ``gui_scripts``, which +will launch a GUI application without running in a terminal window. -After installation, you will be able to invoke that function by simply calling -``helloworld`` on your command line. It will even do command line argument -parsing for you! +Advertising Behavior +==================== -Dynamic discovery of services (aka plugin support) -================================================== -The ability of entry points isn't limited to "advertising" your functions. Its -implementation allows us to accomplish more powerful features, such as creating -plugins. In fact, the aforementioned script wrapping ability is a form of -plugin that was built into ``setuptools``. With that being said, you now have -more options than ``[console_script]`` or ``[gui_script]`` when creating your -package. +Console scripts are one use of the more general concept of entry points. Entry +points more generally allow a packager to advertise behavior for discovery by +other libraries and applications. This feature enables "plug-in"-like +functionality, where one library solicits entry points and any number of other +libraries provide those entry points. -To understand how you can extend this functionality, let's go through how -``setuptool`` does its ``[console_script]`` magic. Again, we use the same -example as above: +A good example of this plug-in behavior can be seen in +`pytest plugins `_, +where pytest is a test framework that allows other libraries to extend +or modify its functionality through the ``pytest11`` entry point. -.. code-block:: ini +The console scripts work similarly, where libraries advertise their commands +and tools like ``pip`` create wrapper scripts that invoke those commands. - [options] - # ... - entry_points = - [console_scripts] - helloworld = mypkg:helloworld +For a project wishing to solicit entry points, Setuptools recommends the +`importlib.metadata `_ +module (part of stdlib since Python 3.8) or its backport, +`importlib_metadata `_. -Package installation contains multiple steps, so at some point, this package -becomes available to your interpreter, and if you run the following code: +For example, to find the console script entry points from the example above:: -.. code-block:: ini +.. code-block:: python - >>> import pkg_resources #a module part of setuptools - >>> [item for item in - pkg_srouces.working_set.iter_entry_points('console_scripts')] - -It will return a list of special objects (called "EntryPoints"), and there -will be one of them that corresponds to the ``helloworld = mypkg:helloworld`` -which we defined above. In fact, this object doesn't just contain the string, -but also an encompassing representation of the package that created it. -In the case of ``console_scripts``, setuptools will automatically invoke -an internal function that utilizes this object and create the wrapper scripts -and place them in your ``bin`` directory for your interpreter. How -``pkg_resource`` look up all the entry points is further detailed in our -:ref:`developer_guide` (WIP). With that being said, if you specify a different -entry point: + >>> from importlib import metadata + >>> eps = metadata.entry_points()['console_scripts'] + +``eps`` is now a list of ``EntryPoint`` objects, one of which corresponds +to the ``hello-world = timmins:hello_world`` defined above. Each ``EntryPoint`` +contains the ``name``, ``group``, and ``value``. It also supplies a ``.load()`` +method to import and load that entry point (module or object). .. code-block:: ini - [options] - # ... - entry_points = - [iam.just.playing.around] - helloworld = mypkg:helloworld + [options.entry_points] + my.plugins = + hello-world = timmins:hello_world -Then, running the same python expression like above: +Then, a different project wishing to load 'my.plugins' plugins could run +the following routine to load (and invoke) such plugins:: .. code-block:: python - >>> import pkg_resources - >>> [item for item in - pkg_srouces.working_set.iter_entry_points('iam.just.playing.around') - ] - -will create another ``EntryPoints`` object that contains the -``helloworld = mypkg:helloworld`` and you can create custom -functions to exploit its information however you want. For example, one of -the installed programs on your system may contain a startup script that -scans the system for all the packages that specify this -``iam.just.playing.around`` entry points, such that when you install this new -package, it becomes immediately available without having to reconfigure -the already installed program. This in fact is the very idea of a plugin! - - -Dependencies management for entry points -======================================== -Some entry points may require additional dependencies for them to work and -others may trigger the installation of additional dependencies only when they -are run. While this is elaborated in more excrutiating details on -:ref:`guide on dependencies management `, we will -provide a brief overview on the entry point aspect. - -Dependencies of this manner are declared using the ``extra_requires`` keywords, -which takes a mapping of the arbitary name of the functionality and a list of -its depencencies, optionally suffixed with its :ref:`version specifier -`. For example, our package provides "pdf" output capability -which requires at least 0.3 version of "ReportLab" and whatever version of "RXP" - -.. code-block:: ini + >>> from importlib import metadata + >>> eps = metadata.entry_points()['my.plugins'] + >>> for ep in eps: + ... plugin = ep.load() + ... plugin() - [options.extras_require] - PDF = ReportLab>=1.2; RXP +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. -.. code-block:: python - setup( - extras_require = { - "PDF": ["ReportLab>=1.2", "RXP"], - } - ) +Dependency Management +===================== - -And we only want them to be installed if the console script entry point -``rst2pdf`` is run: +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 ` for +more information on defining extra requirements. Consider from the +above example:: .. code-block:: ini - [options] - entry_points = - ['console_script'] - rst2pdf = project_a.tools.pdfgen [PDF] - rst2html = project_a.tools.htmlgen - -.. code-block:: python + [options.entry_points] + console_scripts = + hello-world = timmins:hello_world [pretty-printer] - setup( - entry_points = """ - ['console_script'] - rst2pdf = project_a.tools.pdfgen [PDF] - rst2html = project_a.tools.htmlgen - """ - ) +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. -- cgit v1.2.1