From 2b0bd268dd1bf6e23aed98a98906ab821de946f5 Mon Sep 17 00:00:00 2001 From: Barnaby Sherratt Date: Wed, 1 Feb 2023 11:18:16 +0000 Subject: [PATCH 01/11] Set up `iris.plugins` namespace package --- lib/iris/plugins/README.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 lib/iris/plugins/README.md diff --git a/lib/iris/plugins/README.md b/lib/iris/plugins/README.md new file mode 100644 index 0000000000..6d848b572c --- /dev/null +++ b/lib/iris/plugins/README.md @@ -0,0 +1,4 @@ +# Iris plugins + +`iris.plugins` is a [namespace package](https://packaging.python.org/en/latest/guides/packaging-namespace-packages/) +allowing arbitrary plugins to be installed alongside Iris. From 301ae91e91eb92df3b87c0d226b66c117a714d05 Mon Sep 17 00:00:00 2001 From: Barnaby Sherratt Date: Wed, 1 Feb 2023 11:22:38 +0000 Subject: [PATCH 02/11] Provide convenience function to use a plugin --- lib/iris/__init__.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/iris/__init__.py b/lib/iris/__init__.py index a81d25add3..c199467dc5 100644 --- a/lib/iris/__init__.py +++ b/lib/iris/__init__.py @@ -91,6 +91,7 @@ def callback(cube, field, filename): import contextlib import glob +import importlib import itertools import os.path import pathlib @@ -470,3 +471,14 @@ def sample_data_path(*path_to_join): "appropriate for general file access.".format(target) ) return target + + +def use_plugin(plugin_name): + """ + Convenience function to import a plugin + + This is useful for plugins that are not used directly, but instead do all + their setup on import. In this case, style checkers would not know the + significance of the import statement and warn that it is an unused import. + """ + importlib.import_module(f"iris.plugins.{plugin_name}") From e15e4e3a009752c58f99f88b37d180b44918260e Mon Sep 17 00:00:00 2001 From: Barnaby Sherratt Date: Wed, 1 Feb 2023 12:07:54 +0000 Subject: [PATCH 03/11] Basic documentation for plugins --- docs/src/community/index.rst | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/src/community/index.rst b/docs/src/community/index.rst index a9e2a4d040..2e0d33e868 100644 --- a/docs/src/community/index.rst +++ b/docs/src/community/index.rst @@ -1,4 +1,5 @@ .. include:: ../common_links.inc +.. _namespace package: https://packaging.python.org/en/latest/guides/packaging-namespace-packages/ .. todo: consider scientific-python.org @@ -46,3 +47,23 @@ smoother interoperability: :hidden: iris_xarray + +Plugins +------- + +Iris supports *plugins* under the `iris.plugins` `namespace package`_. This +allows packages that extend Iris' functionality to be developed and maintained +independently, while still being installed into `iris.plugins` instead of a +separate package. For example, a plugin may provide loaders or savers for +additional file formats, or alternative visualisation methods. + +Once a plugin is installed, it can be used either via the :func:`iris.use_plugin` +function, or by importing it directly: + +.. code-block:: python + + import iris + + iris.use_plugin("my_plugin") + # OR + import iris.plugins.my_plugin From 67b44a034b173c705b8f84c15bf14b773d0167d6 Mon Sep 17 00:00:00 2001 From: Barnaby Sherratt Date: Wed, 1 Feb 2023 14:15:27 +0000 Subject: [PATCH 04/11] Add a hint about plugins when load fails --- lib/iris/io/format_picker.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/iris/io/format_picker.py b/lib/iris/io/format_picker.py index edf448e95b..a8e333c566 100644 --- a/lib/iris/io/format_picker.py +++ b/lib/iris/io/format_picker.py @@ -134,8 +134,9 @@ def get_spec(self, basename, buffer_obj): value = value[:50] + "..." printable_values[key] = value msg = ( - "No format specification could be found for the given buffer." - " File element cache:\n {}".format(printable_values) + "No format specification could be found for the given buffer. " + "Perhaps a plugin is missing or has not been loaded. " + "File element cache:\n {}".format(printable_values) ) raise ValueError(msg) From 2d351b524dd361fab0c06f1f8c33cc2c648ec6fe Mon Sep 17 00:00:00 2001 From: Barnaby Sherratt Date: Wed, 8 Feb 2023 16:09:31 +0000 Subject: [PATCH 05/11] Expose `use_plugin` in `__all__` --- lib/iris/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/iris/__init__.py b/lib/iris/__init__.py index c199467dc5..c56589d938 100644 --- a/lib/iris/__init__.py +++ b/lib/iris/__init__.py @@ -130,6 +130,7 @@ def callback(cube, field, filename): "sample_data_path", "save", "site_configuration", + "use_plugin", ] From 565bde654d2782052178b4e350e295254d9a9fea Mon Sep 17 00:00:00 2001 From: Barnaby Sherratt Date: Wed, 8 Feb 2023 16:17:06 +0000 Subject: [PATCH 06/11] Add example usage --- lib/iris/__init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/iris/__init__.py b/lib/iris/__init__.py index c56589d938..38465472ee 100644 --- a/lib/iris/__init__.py +++ b/lib/iris/__init__.py @@ -478,6 +478,14 @@ def use_plugin(plugin_name): """ Convenience function to import a plugin + For example:: + + use_plugin("my_plugin") + + is equivalent to:: + + import iris.plugins.my_plugin + This is useful for plugins that are not used directly, but instead do all their setup on import. In this case, style checkers would not know the significance of the import statement and warn that it is an unused import. From f531023f9d0c2d04ea3572f5cc007298c06643e5 Mon Sep 17 00:00:00 2001 From: Barnaby Sherratt Date: Thu, 9 Feb 2023 13:02:48 +0000 Subject: [PATCH 07/11] Split plugin documentation to its own page --- docs/src/community/index.rst | 19 ++++--------------- docs/src/community/plugins.rst | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 15 deletions(-) create mode 100644 docs/src/community/plugins.rst diff --git a/docs/src/community/index.rst b/docs/src/community/index.rst index 2e0d33e868..114cb96fe9 100644 --- a/docs/src/community/index.rst +++ b/docs/src/community/index.rst @@ -1,5 +1,4 @@ .. include:: ../common_links.inc -.. _namespace package: https://packaging.python.org/en/latest/guides/packaging-namespace-packages/ .. todo: consider scientific-python.org @@ -51,19 +50,9 @@ smoother interoperability: Plugins ------- -Iris supports *plugins* under the `iris.plugins` `namespace package`_. This -allows packages that extend Iris' functionality to be developed and maintained -independently, while still being installed into `iris.plugins` instead of a -separate package. For example, a plugin may provide loaders or savers for -additional file formats, or alternative visualisation methods. +Iris can be extended with **plugins**! See below for further information: -Once a plugin is installed, it can be used either via the :func:`iris.use_plugin` -function, or by importing it directly: - -.. code-block:: python - - import iris +.. toctree:: + :maxdepth: 2 - iris.use_plugin("my_plugin") - # OR - import iris.plugins.my_plugin + plugins diff --git a/docs/src/community/plugins.rst b/docs/src/community/plugins.rst new file mode 100644 index 0000000000..7ecef49cac --- /dev/null +++ b/docs/src/community/plugins.rst @@ -0,0 +1,25 @@ +.. _namespace package: https://packaging.python.org/en/latest/guides/packaging-namespace-packages/ + +Plugins +======= + +Iris supports **plugins** under the ``iris.plugins`` `namespace package`_. +This allows packages that extend Iris' functionality to be developed and +maintained independently, while still being installed into ``iris.plugins`` +instead of a separate package. For example, a plugin may provide loaders or +savers for additional file formats, or alternative visualisation methods. + + +Using plugins +------------- + +Once a plugin is installed, it can be used either via the +:func:`iris.use_plugin` function, or by importing it directly: + +.. code-block:: python + + import iris + + iris.use_plugin("my_plugin") + # OR + import iris.plugins.my_plugin From f4736e0c34a678e5421e00c261ef1ddd5a28b070 Mon Sep 17 00:00:00 2001 From: Barnaby Sherratt Date: Thu, 9 Feb 2023 13:41:12 +0000 Subject: [PATCH 08/11] Document how to create a plugin --- docs/src/community/plugins.rst | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/docs/src/community/plugins.rst b/docs/src/community/plugins.rst index 7ecef49cac..90d2110f20 100644 --- a/docs/src/community/plugins.rst +++ b/docs/src/community/plugins.rst @@ -23,3 +23,44 @@ Once a plugin is installed, it can be used either via the iris.use_plugin("my_plugin") # OR import iris.plugins.my_plugin + + +Creating plugins +---------------- + +The choice of a `namespace package`_ makes writing a plugin relatively +straightforward: it simply needs to appear as a folder within ``iris/plugins``, +then can be distributed in the same way as any other package. An example +repository layout: + +.. code-block:: plain + + + lib + + iris + + plugins + + my_plugin + - __init__.py + - (more code...) + - README.md + - pyproject.toml + - setup.cfg + - (other project files...) + +In particular, note that there must **not** be any ``__init__.py`` files at +higher levels than the plugin itself. + +The package name - how it is referred to by PyPI/conda, specified by +``metadata.name`` in ``setup.cfg`` - is recommended to include both "iris" and +the plugin name. Continuing this example, its ``setup.cfg`` should include, at +minimum: + +.. code-block:: ini + + [metadata] + name = iris-my-plugin + + [options] + packages = find_namespace: + + [options.packages.find] + where = lib From f3aca3927a6daafdc8b1a98f9bea3df0d1a74f38 Mon Sep 17 00:00:00 2001 From: Barnaby Sherratt Date: Thu, 9 Feb 2023 13:50:42 +0000 Subject: [PATCH 09/11] Link to documentation --- lib/iris/plugins/README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/iris/plugins/README.md b/lib/iris/plugins/README.md index 6d848b572c..e8dee1de2c 100644 --- a/lib/iris/plugins/README.md +++ b/lib/iris/plugins/README.md @@ -1,4 +1,10 @@ # Iris plugins -`iris.plugins` is a [namespace package](https://packaging.python.org/en/latest/guides/packaging-namespace-packages/) -allowing arbitrary plugins to be installed alongside Iris. +`iris.plugins` is a [namespace package] allowing arbitrary plugins to be +installed alongside Iris. + +See [the Iris documentation][plugins] for more information. + + +[namespace package]: https://packaging.python.org/en/latest/guides/packaging-namespace-packages/ +[plugins]: https://scitools-iris.readthedocs.io/en/latest/community/plugins.html From 6f1cd1bb7fafa689c163a205b992e66133c7b656 Mon Sep 17 00:00:00 2001 From: Barnaby Sherratt Date: Thu, 9 Feb 2023 14:32:28 +0000 Subject: [PATCH 10/11] Correct "plain" code block -> "text" --- docs/src/community/plugins.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/community/plugins.rst b/docs/src/community/plugins.rst index 90d2110f20..72ee114a77 100644 --- a/docs/src/community/plugins.rst +++ b/docs/src/community/plugins.rst @@ -33,7 +33,7 @@ straightforward: it simply needs to appear as a folder within ``iris/plugins``, then can be distributed in the same way as any other package. An example repository layout: -.. code-block:: plain +.. code-block:: text + lib + iris From 502730d101c40c6ef04d979c2c1e8cbc10cb6c4d Mon Sep 17 00:00:00 2001 From: Barnaby Sherratt Date: Wed, 15 Feb 2023 13:42:34 +0000 Subject: [PATCH 11/11] Whatsnew --- docs/src/common_links.inc | 1 + docs/src/community/plugins.rst | 2 ++ docs/src/whatsnew/latest.rst | 4 +++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/src/common_links.inc b/docs/src/common_links.inc index c8a7fef74b..7d4e7f464b 100644 --- a/docs/src/common_links.inc +++ b/docs/src/common_links.inc @@ -51,6 +51,7 @@ .. _@ajdawson: https://github.com/ajdawson .. _@bjlittle: https://github.com/bjlittle .. _@bouweandela: https://github.com/bouweandela +.. _@bsherratt: https://github.com/bsherratt .. _@corinnebosley: https://github.com/corinnebosley .. _@cpelley: https://github.com/cpelley .. _@djkirkham: https://github.com/djkirkham diff --git a/docs/src/community/plugins.rst b/docs/src/community/plugins.rst index 72ee114a77..0d79d64623 100644 --- a/docs/src/community/plugins.rst +++ b/docs/src/community/plugins.rst @@ -1,5 +1,7 @@ .. _namespace package: https://packaging.python.org/en/latest/guides/packaging-namespace-packages/ +.. _community_plugins: + Plugins ======= diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst index 9d9fa8b342..a38e426e6a 100644 --- a/docs/src/whatsnew/latest.rst +++ b/docs/src/whatsnew/latest.rst @@ -32,7 +32,9 @@ This document explains the changes made to Iris for this release ✨ Features =========== -#. N/A +#. `@bsherratt`_ added support for plugins - see the corresponding + :ref:`documentation page` for further information. + (:pull:`5144`) 🐛 Bugs Fixed