[ENH]: Prepare Junifer for extension support #366
8 changed files with 75 additions and 2 deletions
1
docs/changes/newsfragments/366.doc
Normal file
1
docs/changes/newsfragments/366.doc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Add documentation on how to make a ``junifer`` plugin by `Synchon Mandal`_
|
||||||
1
docs/changes/newsfragments/366.feature
Normal file
1
docs/changes/newsfragments/366.feature
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Add support for plugins by `Synchon Mandal`_
|
||||||
|
|
@ -30,3 +30,4 @@ DataGrabbers, Preprocessors, Markers, etc., following the *junifer* way.
|
||||||
parcellations
|
parcellations
|
||||||
coordinates
|
coordinates
|
||||||
masks
|
masks
|
||||||
|
plugins
|
||||||
|
|
|
||||||
50
docs/extending/plugins.rst
Normal file
50
docs/extending/plugins.rst
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
.. include:: ../links.inc
|
||||||
|
|
||||||
|
.. _plugins:
|
||||||
|
|
||||||
|
Creating a ``junifer`` plugin
|
||||||
|
=============================
|
||||||
|
|
||||||
|
What is a plugin
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Plugins are additional components that extend the functionality of ``junifer``.
|
||||||
|
Technically, plugins can also be called as extensions, but we clearly differentiate
|
||||||
|
them in ``junifer`` as :ref:`extensions<extending_extension>` serve a different
|
||||||
|
purpose. ``junifer`` plugins are command line programs which can be used
|
||||||
|
independently but also integrates with the core ``junifer`` command line interface
|
||||||
|
(CLI) framework.
|
||||||
|
|
||||||
|
When a plugin is installed, we basically inject new behaviours into the ``junifer`` CLI
|
||||||
|
while promoting modularity and allowing for easier maintenance and updates to the core
|
||||||
|
application. A great plugin example is `junifer-data`_ which is well-integrated
|
||||||
|
in ``junifer`` to access assets like parcellations, coordinates and masks, but also
|
||||||
|
remains modular enough to update its CLI without disturbing that of ``junifer``.
|
||||||
|
|
||||||
|
How to make a plugin
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
A key distinction between a ``junifer`` extension and a ``junifer`` plugin is that a
|
||||||
|
plugin will have its own CLI and be a Python package in its own right, for example,
|
||||||
|
`junifer-data`_.
|
||||||
|
|
||||||
|
The following steps should lead you to make a successful plugin:
|
||||||
|
|
||||||
|
#. Create CLI for your plugin. As ``junifer`` uses `click`_ for its CLI, a plugin
|
||||||
|
should be creating its own ``click.Group`` as shown here:
|
||||||
|
`<https://click.palletsprojects.com/en/stable/commands/#commands-and-groups>`_.
|
||||||
|
|
||||||
|
#. Integrate the `click`_-based plugin CLI with `setuptools`_ as shown here:
|
||||||
|
`<https://click.palletsprojects.com/en/stable/setuptools/#setuptools-integration>`_.
|
||||||
|
|
||||||
|
#. Make sure the plugin CLI independently works as intended.
|
||||||
|
|
||||||
|
#. Follow the steps here:
|
||||||
|
`<https://setuptools.pypa.io/en/latest/userguide/entry_point.html#entry-points-for-plugins>`_
|
||||||
|
and make a new entry point with the *name* as the sub-command you want under ``junifer`` command
|
||||||
|
and the *group* as ``"junifer.ext"``. The *name* should refer to the ``click.Group`` of your
|
||||||
|
plugin CLI.
|
||||||
|
|
||||||
|
#. After you install your plugin in the same environment as your ``junifer`` installation, you can
|
||||||
|
observe your plugin being added as a new sub-command under ``junifer`` and working exactly as it
|
||||||
|
did independently.
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
.. _`AML`: https://www.fz-juelich.de/inm/inm-7/EN/Forschung/Applied%20Machine%20Learning/_node.html
|
.. _`AML`: https://www.fz-juelich.de/inm/inm-7/EN/Forschung/Applied%20Machine%20Learning/_node.html
|
||||||
.. _`INM-7`: https://www.fz-juelich.de/inm/inm-7/EN/Home/home_node.html
|
.. _`INM-7`: https://www.fz-juelich.de/inm/inm-7/EN/Home/home_node.html
|
||||||
.. _`julearn`: https://juaml.github.io/julearn
|
.. _`julearn`: https://juaml.github.io/julearn
|
||||||
|
.. _`junifer-data`: https://github.com/juaml/junifer-data-client
|
||||||
|
|
||||||
.. _`pandas`: https://pandas.pydata.org
|
.. _`pandas`: https://pandas.pydata.org
|
||||||
.. _`pandas.DataFrame` : https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html
|
.. _`pandas.DataFrame` : https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html
|
||||||
|
|
@ -24,6 +25,7 @@
|
||||||
.. _`nipype`: https://nipype.readthedocs.io
|
.. _`nipype`: https://nipype.readthedocs.io
|
||||||
.. _`datalad`: https://datalad.org
|
.. _`datalad`: https://datalad.org
|
||||||
.. _`templateflow`: https://www.templateflow.org
|
.. _`templateflow`: https://www.templateflow.org
|
||||||
|
.. _`click`: https://click.palletsprojects.com/en/stable/
|
||||||
|
|
||||||
.. _`venv`: https://docs.python.org/3/tutorial/venv.html
|
.. _`venv`: https://docs.python.org/3/tutorial/venv.html
|
||||||
.. _`conda env`: https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html
|
.. _`conda env`: https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html
|
||||||
|
|
@ -36,6 +38,7 @@
|
||||||
.. _`Wikipedia`: https://wikipedia.org
|
.. _`Wikipedia`: https://wikipedia.org
|
||||||
.. _`YAML`: https://yaml.org
|
.. _`YAML`: https://yaml.org
|
||||||
|
|
||||||
|
.. _`setuptools`: https://setuptools.pypa.io/en/latest/
|
||||||
.. _`setuptools_scm`: https://github.com/pypa/setuptools_scm/
|
.. _`setuptools_scm`: https://github.com/pypa/setuptools_scm/
|
||||||
|
|
||||||
.. _`sphinx gallery`: https://sphinx-gallery.github.io/stable/index.html
|
.. _`sphinx gallery`: https://sphinx-gallery.github.io/stable/index.html
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,22 @@
|
||||||
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
||||||
# License: AGPL
|
# License: AGPL
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
import lazy_loader as lazy
|
import lazy_loader as lazy
|
||||||
|
|
||||||
|
|
||||||
|
if sys.version_info < (3, 11): # pragma: no cover
|
||||||
|
from importlib_metadata import entry_points
|
||||||
|
else:
|
||||||
|
from importlib.metadata import entry_points
|
||||||
|
|
||||||
|
|
||||||
__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__)
|
__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__)
|
||||||
|
|
||||||
|
|
||||||
|
# Register extensions
|
||||||
|
from .cli import cli
|
||||||
|
|
||||||
|
for ep in entry_points(group="junifer.ext"):
|
||||||
|
cli.add_command(ep.load(), name=ep.name)
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,9 @@ def _validate_verbose(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@click.group()
|
@click.group
|
||||||
|
@click.version_option()
|
||||||
|
@click.help_option()
|
||||||
def cli() -> None: # pragma: no cover
|
def cli() -> None: # pragma: no cover
|
||||||
"""JUelich NeuroImaging FEature extractoR."""
|
"""JUelich NeuroImaging FEature extractoR."""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ dependencies = [
|
||||||
"lazy_loader==0.4",
|
"lazy_loader==0.4",
|
||||||
"importlib_metadata; python_version<'3.9'",
|
"importlib_metadata; python_version<'3.9'",
|
||||||
"looseversion==1.3.0; python_version>='3.12'",
|
"looseversion==1.3.0; python_version>='3.12'",
|
||||||
"junifer_data==1.2.0",
|
"junifer_data==1.3.0",
|
||||||
]
|
]
|
||||||
dynamic = ["version"]
|
dynamic = ["version"]
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue