npe2 0.7.7rc0__tar.gz → 0.7.8rc0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/.github/workflows/ci.yml +7 -5
  2. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/.github/workflows/test_all_plugins.yml +11 -3
  3. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/.github/workflows/update_changelog.yml +2 -2
  4. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/.pre-commit-config.yaml +4 -4
  5. npe2-0.7.8rc0/PKG-INFO +196 -0
  6. npe2-0.7.8rc0/README.md +144 -0
  7. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/_docs/templates/_npe2_readers_guide.md.jinja +2 -1
  8. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/_docs/templates/_npe2_widgets_guide.md.jinja +1 -1
  9. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/pyproject.toml +5 -4
  10. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/_dynamic_plugin.py +2 -4
  11. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/_inspection/_fetch.py +4 -75
  12. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/_inspection/_from_npe1.py +4 -4
  13. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/_plugin_manager.py +21 -17
  14. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/_setuptools_plugin.py +1 -0
  15. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/cli.py +0 -25
  16. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/implements.pyi +1 -1
  17. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/io_utils.py +9 -11
  18. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/__init__.py +1 -1
  19. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/contributions/_configuration.py +1 -1
  20. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/contributions/_json_schema.py +6 -7
  21. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/contributions/_readers.py +13 -3
  22. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/contributions/_sample_data.py +1 -2
  23. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/schema.py +7 -3
  24. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/utils.py +7 -1
  25. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/plugin_manager.py +5 -1
  26. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/types.py +6 -10
  27. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/fixtures/my-compiled-plugin/my_module/_a.py +6 -8
  28. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/fixtures/my-compiled-plugin/my_module/_b.py +3 -6
  29. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/npe1-plugin/npe1_module/__init__.py +16 -16
  30. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/sample/_with_decorators.py +11 -18
  31. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/sample/my_plugin/__init__.py +4 -7
  32. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/test_cli.py +0 -17
  33. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/test_contributions.py +2 -4
  34. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/test_conversion.py +27 -2
  35. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/test_fetch.py +6 -12
  36. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/test_npe1_adapter.py +1 -2
  37. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/test_plugin_manager.py +23 -2
  38. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/test_tmp_plugin.py +7 -8
  39. npe2-0.7.7rc0/PKG-INFO +0 -93
  40. npe2-0.7.7rc0/README.md +0 -41
  41. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/.github/ISSUE_TEMPLATE.md +0 -0
  42. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/.github/dependabot.yml +0 -0
  43. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/.github/workflows/test_conversion.yml +0 -0
  44. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/.github_changelog_generator +0 -0
  45. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/.gitignore +0 -0
  46. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/CHANGELOG.md +0 -0
  47. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/LICENSE +0 -0
  48. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/Makefile +0 -0
  49. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/_docs/example_manifest.yaml +0 -0
  50. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/_docs/example_plugin/__init__.py +0 -0
  51. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/_docs/example_plugin/some_module.py +0 -0
  52. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/_docs/render.py +0 -0
  53. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/_docs/templates/_npe2_contributions.md.jinja +0 -0
  54. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/_docs/templates/_npe2_manifest.md.jinja +0 -0
  55. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/_docs/templates/_npe2_sample_data_guide.md.jinja +0 -0
  56. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/_docs/templates/_npe2_writers_guide.md.jinja +0 -0
  57. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/codecov.yml +0 -0
  58. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/docs/_config.yml +0 -0
  59. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/docs/_toc.yml +0 -0
  60. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/docs/index.md +0 -0
  61. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/docs/requirements.txt +0 -0
  62. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/__init__.py +5 -5
  63. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/__main__.py +0 -0
  64. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/_command_registry.py +0 -0
  65. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/_inspection/__init__.py +2 -2
  66. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/_inspection/_compile.py +0 -0
  67. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/_inspection/_setuputils.py +0 -0
  68. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/_inspection/_visitors.py +0 -0
  69. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/_pydantic_compat.py +7 -7
  70. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/_pytest_plugin.py +0 -0
  71. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/implements.py +0 -0
  72. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/_bases.py +0 -0
  73. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/_npe1_adapter.py +0 -0
  74. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/_package_metadata.py +0 -0
  75. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/_validators.py +0 -0
  76. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/contributions/__init__.py +0 -0
  77. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/contributions/_commands.py +0 -0
  78. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/contributions/_contributions.py +3 -3
  79. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/contributions/_icon.py +0 -0
  80. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/contributions/_keybindings.py +0 -0
  81. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/contributions/_menus.py +0 -0
  82. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/contributions/_submenu.py +0 -0
  83. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/contributions/_themes.py +0 -0
  84. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/contributions/_widgets.py +0 -0
  85. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/contributions/_writers.py +0 -0
  86. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/menus.py +0 -0
  87. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/manifest/package_metadata.py +0 -0
  88. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/src/npe2/py.typed +0 -0
  89. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/conftest.py +0 -0
  90. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/fixtures/my-compiled-plugin/my_module/__init__.py +0 -0
  91. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/fixtures/my-compiled-plugin/setup.cfg +0 -0
  92. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/npe1-plugin/npe1-plugin-0.0.1.dist-info/METADATA +0 -0
  93. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/npe1-plugin/npe1-plugin-0.0.1.dist-info/RECORD +0 -0
  94. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/npe1-plugin/npe1-plugin-0.0.1.dist-info/entry_points.txt +0 -0
  95. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/npe1-plugin/npe1-plugin-0.0.1.dist-info/top_level.txt +0 -0
  96. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/npe1-plugin/setup.cfg +0 -0
  97. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/sample/my_plugin/napari.yaml +0 -0
  98. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/sample/my_plugin-1.2.3.dist-info/METADATA +0 -0
  99. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/sample/my_plugin-1.2.3.dist-info/entry_points.txt +0 -0
  100. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/sample/my_plugin-1.2.3.dist-info/top_level.txt +0 -0
  101. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/test__io_utils.py +0 -0
  102. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/test_all_plugins.py +0 -0
  103. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/test_compile.py +0 -0
  104. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/test_config_contribution.py +0 -0
  105. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/test_docs.py +0 -0
  106. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/test_implements.py +0 -0
  107. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/test_manifest.py +0 -0
  108. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/test_package_meta.py +0 -0
  109. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/test_pm_module.py +0 -0
  110. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/test_pytest_plugin.py +0 -0
  111. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/test_setuptools_plugin.py +0 -0
  112. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/test_utils.py +0 -0
  113. {npe2-0.7.7rc0 → npe2-0.7.8rc0}/tests/test_validations.py +0 -0
@@ -53,11 +53,12 @@ jobs:
53
53
  coverage run --source=npe2 -m pytest --color yes
54
54
 
55
55
  - name: Upload coverage as artifact
56
- uses: actions/upload-artifact@v3
56
+ uses: actions/upload-artifact@v4
57
57
  with:
58
- name: coverage reports
58
+ name: coverage reports ${{ matrix.platform }} py ${{ matrix.python-version }} ${{ (matrix.pydantic == 'pydantic<2' && 'pydantic_lt_2') || 'pydantic_gt_2' }}
59
59
  path: |
60
60
  ./.coverage.*
61
+ include-hidden-files: true
61
62
 
62
63
  test_napari:
63
64
  name: napari tests
@@ -124,10 +125,11 @@ jobs:
124
125
  pip install codecov
125
126
 
126
127
  - name: Download coverage data
127
- uses: actions/download-artifact@v3
128
+ uses: actions/download-artifact@v4
128
129
  with:
129
- name: coverage reports
130
+ pattern: coverage reports*
130
131
  path: coverage
132
+ merge-multiple: true
131
133
 
132
134
  - name: combine coverage data
133
135
  run: |
@@ -138,7 +140,7 @@ jobs:
138
140
  python -Im coverage report --format=markdown --skip-empty --skip-covered >> $GITHUB_STEP_SUMMARY
139
141
 
140
142
  - name: Upload coverage data
141
- uses: codecov/codecov-action@v4
143
+ uses: codecov/codecov-action@v5
142
144
  with:
143
145
  fail_ci_if_error: true
144
146
  token: ${{ secrets.CODECOV_TOKEN }}
@@ -1,6 +1,7 @@
1
1
  name: Test all plugins
2
2
 
3
3
  on:
4
+ # To run this workflow, trigger it manually, or add the label 'test-all-plugins' to a pull request
4
5
  pull_request:
5
6
  types: [ labeled ]
6
7
  workflow_dispatch:
@@ -15,7 +16,13 @@ jobs:
15
16
  runs-on: ubuntu-latest
16
17
  steps:
17
18
  - id: plugin_names
18
- run: echo "::set-output name=plugins::$(curl -s https://api.napari-hub.org/plugins | jq -c 'keys')"
19
+ # Query npe2api for index of all plugins, select the keys, turn them into an array, select 10 random
20
+ # names from that array, convert the "one per line" output back into a string array
21
+ # save the string array of 10 plugins into the output from this step
22
+ run: |
23
+ set -eux
24
+ DATA=$(echo $(curl -s https://npe2api.vercel.app/api/plugins | jq -c 'keys' | jq -r '.[]' | shuf -n 10 | jq -R -s 'split("\n") | map(select(. != ""))'))
25
+ echo "plugins=$DATA" >> "$GITHUB_OUTPUT"
19
26
  outputs:
20
27
  plugins: ${{ steps.plugin_names.outputs.plugins }}
21
28
 
@@ -38,8 +45,9 @@ jobs:
38
45
 
39
46
  - uses: conda-incubator/setup-miniconda@v3
40
47
  with:
41
- python-version: 3.9
42
- miniforge-variant: Mambaforge
48
+ python-version: '3.10'
49
+ miniforge-variant: Miniforge3
50
+ conda-remove-defaults: "true"
43
51
  miniforge-version: latest
44
52
  use-mamba: true
45
53
 
@@ -13,13 +13,13 @@ jobs:
13
13
  - name: Checkout
14
14
  uses: actions/checkout@v4
15
15
  - name: "✏️ Generate release changelog"
16
- uses: heinrichreimer/github-changelog-generator-action@v2.3
16
+ uses: heinrichreimer/github-changelog-generator-action@v2.4
17
17
  with:
18
18
  futureRelease: ${{ github.event.inputs.next_tag }}
19
19
  token: ${{ secrets.GITHUB_TOKEN }}
20
20
  repo: napari/npe2
21
21
  - name: Create Pull Request
22
- uses: peter-evans/create-pull-request@v6
22
+ uses: peter-evans/create-pull-request@v7
23
23
  with:
24
24
  token: ${{ secrets.GITHUB_TOKEN }}
25
25
  commit-message: Automatic changelog update
@@ -7,24 +7,24 @@ exclude: _docs/example_plugin/some_module.py
7
7
 
8
8
  repos:
9
9
  - repo: https://github.com/pre-commit/pre-commit-hooks
10
- rev: v4.4.0
10
+ rev: v5.0.0
11
11
  hooks:
12
12
  - id: check-docstring-first
13
13
  - id: end-of-file-fixer
14
14
  - id: trailing-whitespace
15
15
 
16
16
  - repo: https://github.com/psf/black
17
- rev: 23.7.0
17
+ rev: 25.1.0
18
18
  hooks:
19
19
  - id: black
20
20
 
21
21
  - repo: https://github.com/astral-sh/ruff-pre-commit
22
- rev: v0.0.282
22
+ rev: v0.9.4
23
23
  hooks:
24
24
  - id: ruff
25
25
 
26
26
  - repo: https://github.com/pre-commit/mirrors-mypy
27
- rev: v1.4.1
27
+ rev: v1.14.1
28
28
  hooks:
29
29
  - id: mypy
30
30
  additional_dependencies:
npe2-0.7.8rc0/PKG-INFO ADDED
@@ -0,0 +1,196 @@
1
+ Metadata-Version: 2.4
2
+ Name: npe2
3
+ Version: 0.7.8rc0
4
+ Summary: napari plugin engine v2
5
+ Project-URL: homepage, https://github.com/napari/npe2
6
+ Project-URL: repository, https://github.com/napari/npe2
7
+ Author: Nathan Clack
8
+ Author-email: Talley Lambert <talley.lambert@gmail.com>
9
+ License: BSD-3-Clause
10
+ License-File: LICENSE
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: License :: OSI Approved :: BSD License
13
+ Classifier: Natural Language :: English
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.8
22
+ Requires-Dist: appdirs
23
+ Requires-Dist: build>=1
24
+ Requires-Dist: psygnal>=0.3.0
25
+ Requires-Dist: pydantic
26
+ Requires-Dist: pyyaml
27
+ Requires-Dist: rich
28
+ Requires-Dist: tomli-w
29
+ Requires-Dist: tomli; python_version < '3.11'
30
+ Requires-Dist: typer
31
+ Provides-Extra: dev
32
+ Requires-Dist: black; extra == 'dev'
33
+ Requires-Dist: ipython; extra == 'dev'
34
+ Requires-Dist: isort; extra == 'dev'
35
+ Requires-Dist: mypy; extra == 'dev'
36
+ Requires-Dist: pre-commit; extra == 'dev'
37
+ Provides-Extra: docs
38
+ Requires-Dist: jinja2; extra == 'docs'
39
+ Requires-Dist: magicgui>=0.3.3; extra == 'docs'
40
+ Provides-Extra: json
41
+ Requires-Dist: jsonschema; extra == 'json'
42
+ Provides-Extra: testing
43
+ Requires-Dist: jsonschema; extra == 'testing'
44
+ Requires-Dist: magicgui; extra == 'testing'
45
+ Requires-Dist: napari-plugin-engine; extra == 'testing'
46
+ Requires-Dist: napari-svg==0.1.5; extra == 'testing'
47
+ Requires-Dist: numpy; extra == 'testing'
48
+ Requires-Dist: pytest; extra == 'testing'
49
+ Requires-Dist: pytest-cov; extra == 'testing'
50
+ Requires-Dist: pytest-pretty; extra == 'testing'
51
+ Description-Content-Type: text/markdown
52
+
53
+ # npe2 - napari plugin engine version 2
54
+
55
+ [![CI](https://github.com/napari/npe2/actions/workflows/ci.yml/badge.svg)](https://github.com/napari/npe2/actions/workflows/ci.yml)
56
+ [![codecov](https://codecov.io/gh/napari/npe2/branch/main/graph/badge.svg?token=FTH635x542)](https://codecov.io/gh/napari/npe2)
57
+
58
+ ## Project description
59
+
60
+ The **napari plugin engine version 2**, **npe2** extends the functionality of
61
+ [napari's core](https://github.com/napari/napari).
62
+ The plugin ecosystem offers user additional functionality for napari as well
63
+ as specific support for different scientific domains.
64
+
65
+ This repo contains all source code and documentation required for defining, validating and managing plugins for napari.
66
+
67
+ ## Getting started
68
+
69
+ The [napari plugin docs landing page](https://napari.org/stable/plugins/index.html)
70
+ offers comprehensive information for **plugin users** and for **plugin developers**.
71
+
72
+ ### Plugin users
73
+
74
+ For plugin users, the docs include information about:
75
+ - [Starting to use plugins](https://napari.org/stable/plugins/start_using_plugins/index.html#plugins-getting-started)
76
+ - [Finding and installing plugins](https://napari.org/stable/plugins/start_using_plugins/finding_and_installing_plugins.html#find-and-install-plugins)
77
+
78
+ ### Plugin developers
79
+
80
+ For plugin developers, the docs cover topics like:
81
+ - [Building a plugin](https://napari.org/stable/plugins/building_a_plugin/index.html)
82
+ - [Guides to different plugin contributions](https://napari.org/stable/plugins/building_a_plugin/guides.html)
83
+ - [Technical references such as the plugin manifest](https://napari.org/stable/plugins/technical_references/manifest.html)
84
+
85
+ Try the [**napari plugin template**](https://github.com/napari/napari-plugin-template)
86
+ to streamline development of a new plugin.
87
+
88
+ ## Installation
89
+
90
+ The `npe2` command line tool can be installed with `pip` or `conda`, but will already be installed as a dependency if you have napari installed.
91
+
92
+ ### Using pip
93
+
94
+ 1. Create and activate a virtual environment.
95
+
96
+ *If you are new to using virtual environments, visit our [virtual environments guide](https://napari.org/stable/plugins/virtual_environment_docs/1-virtual-environments.html)*.
97
+
98
+ ```bash
99
+ python3 -m venv .venv
100
+ source .venv/bin/activate
101
+ ```
102
+
103
+ 2. Install npe2.
104
+
105
+ ```bash
106
+ pip install npe2
107
+ ```
108
+
109
+ 3. Test your installation.
110
+
111
+ ```bash
112
+ npe2 --help
113
+ ```
114
+
115
+ ### Using conda
116
+
117
+ 1. Create and activate a virtual environment.
118
+
119
+ ```bash
120
+ conda create -n npe-test -c conda-forge python=3.12
121
+ conda activate npe-test
122
+ ```
123
+
124
+ 2. Install npe2.
125
+
126
+ ```bash
127
+ conda install npe2
128
+ ```
129
+
130
+ 3. Test your installation.
131
+
132
+ ```bash
133
+ npe2 --help
134
+ ```
135
+
136
+ ## Usage
137
+
138
+ The command line tool `npe2` offers the following commands:
139
+
140
+ ```bash
141
+ cache Cache utils
142
+ compile Compile @npe2.implements contributions to generate a manifest.
143
+ convert Convert first generation napari plugin to new (manifest) format.
144
+ fetch Fetch manifest from remote package.
145
+ list List currently installed plugins.
146
+ parse Show parsed manifest as yaml.
147
+ validate Validate manifest for a distribution name or manifest filepath.
148
+ ```
149
+
150
+ ### Examples
151
+
152
+ List currently installed plugins:
153
+
154
+ ```bash
155
+ npe2 list
156
+ ```
157
+
158
+ Compile a source directory to create a plugin manifest:
159
+
160
+ ```bash
161
+ npe2 compile PATH_TO_SOURCE_DIRECTORY
162
+ ```
163
+
164
+ Convert current directory to an npe2-ready plugin
165
+ (note: the repo must also be installed and importable in the current environment.):
166
+
167
+ ```bash
168
+ npe2 convert .
169
+ ```
170
+
171
+ Validate a plugin package. For example, a plugin named `your-plugin-package`:
172
+
173
+ ```bash
174
+ npe2 validate your-plugin-package
175
+ ```
176
+
177
+ Show a parsed manifest of your plugin:
178
+
179
+ ```bash
180
+ npe2 parse your-plugin-package
181
+ ```
182
+
183
+ ## License
184
+
185
+ npe2 uses the [BSD License](./LICENSE).
186
+
187
+ ## History
188
+
189
+ This repo replaces the initial napari plugin engine v1.
190
+ See also https://github.com/napari/napari/issues/3115 for
191
+ motivation and technical discussion about the creation of v2.
192
+
193
+ ## Contact us
194
+
195
+ Visit [our community documentation](https://napari.org/stable/community/index.html)
196
+ or [open a new issue on this repo](https://github.com/napari/npe2/issues/new).
@@ -0,0 +1,144 @@
1
+ # npe2 - napari plugin engine version 2
2
+
3
+ [![CI](https://github.com/napari/npe2/actions/workflows/ci.yml/badge.svg)](https://github.com/napari/npe2/actions/workflows/ci.yml)
4
+ [![codecov](https://codecov.io/gh/napari/npe2/branch/main/graph/badge.svg?token=FTH635x542)](https://codecov.io/gh/napari/npe2)
5
+
6
+ ## Project description
7
+
8
+ The **napari plugin engine version 2**, **npe2** extends the functionality of
9
+ [napari's core](https://github.com/napari/napari).
10
+ The plugin ecosystem offers user additional functionality for napari as well
11
+ as specific support for different scientific domains.
12
+
13
+ This repo contains all source code and documentation required for defining, validating and managing plugins for napari.
14
+
15
+ ## Getting started
16
+
17
+ The [napari plugin docs landing page](https://napari.org/stable/plugins/index.html)
18
+ offers comprehensive information for **plugin users** and for **plugin developers**.
19
+
20
+ ### Plugin users
21
+
22
+ For plugin users, the docs include information about:
23
+ - [Starting to use plugins](https://napari.org/stable/plugins/start_using_plugins/index.html#plugins-getting-started)
24
+ - [Finding and installing plugins](https://napari.org/stable/plugins/start_using_plugins/finding_and_installing_plugins.html#find-and-install-plugins)
25
+
26
+ ### Plugin developers
27
+
28
+ For plugin developers, the docs cover topics like:
29
+ - [Building a plugin](https://napari.org/stable/plugins/building_a_plugin/index.html)
30
+ - [Guides to different plugin contributions](https://napari.org/stable/plugins/building_a_plugin/guides.html)
31
+ - [Technical references such as the plugin manifest](https://napari.org/stable/plugins/technical_references/manifest.html)
32
+
33
+ Try the [**napari plugin template**](https://github.com/napari/napari-plugin-template)
34
+ to streamline development of a new plugin.
35
+
36
+ ## Installation
37
+
38
+ The `npe2` command line tool can be installed with `pip` or `conda`, but will already be installed as a dependency if you have napari installed.
39
+
40
+ ### Using pip
41
+
42
+ 1. Create and activate a virtual environment.
43
+
44
+ *If you are new to using virtual environments, visit our [virtual environments guide](https://napari.org/stable/plugins/virtual_environment_docs/1-virtual-environments.html)*.
45
+
46
+ ```bash
47
+ python3 -m venv .venv
48
+ source .venv/bin/activate
49
+ ```
50
+
51
+ 2. Install npe2.
52
+
53
+ ```bash
54
+ pip install npe2
55
+ ```
56
+
57
+ 3. Test your installation.
58
+
59
+ ```bash
60
+ npe2 --help
61
+ ```
62
+
63
+ ### Using conda
64
+
65
+ 1. Create and activate a virtual environment.
66
+
67
+ ```bash
68
+ conda create -n npe-test -c conda-forge python=3.12
69
+ conda activate npe-test
70
+ ```
71
+
72
+ 2. Install npe2.
73
+
74
+ ```bash
75
+ conda install npe2
76
+ ```
77
+
78
+ 3. Test your installation.
79
+
80
+ ```bash
81
+ npe2 --help
82
+ ```
83
+
84
+ ## Usage
85
+
86
+ The command line tool `npe2` offers the following commands:
87
+
88
+ ```bash
89
+ cache Cache utils
90
+ compile Compile @npe2.implements contributions to generate a manifest.
91
+ convert Convert first generation napari plugin to new (manifest) format.
92
+ fetch Fetch manifest from remote package.
93
+ list List currently installed plugins.
94
+ parse Show parsed manifest as yaml.
95
+ validate Validate manifest for a distribution name or manifest filepath.
96
+ ```
97
+
98
+ ### Examples
99
+
100
+ List currently installed plugins:
101
+
102
+ ```bash
103
+ npe2 list
104
+ ```
105
+
106
+ Compile a source directory to create a plugin manifest:
107
+
108
+ ```bash
109
+ npe2 compile PATH_TO_SOURCE_DIRECTORY
110
+ ```
111
+
112
+ Convert current directory to an npe2-ready plugin
113
+ (note: the repo must also be installed and importable in the current environment.):
114
+
115
+ ```bash
116
+ npe2 convert .
117
+ ```
118
+
119
+ Validate a plugin package. For example, a plugin named `your-plugin-package`:
120
+
121
+ ```bash
122
+ npe2 validate your-plugin-package
123
+ ```
124
+
125
+ Show a parsed manifest of your plugin:
126
+
127
+ ```bash
128
+ npe2 parse your-plugin-package
129
+ ```
130
+
131
+ ## License
132
+
133
+ npe2 uses the [BSD License](./LICENSE).
134
+
135
+ ## History
136
+
137
+ This repo replaces the initial napari plugin engine v1.
138
+ See also https://github.com/napari/napari/issues/3115 for
139
+ motivation and technical discussion about the creation of v2.
140
+
141
+ ## Contact us
142
+
143
+ Visit [our community documentation](https://napari.org/stable/community/index.html)
144
+ or [open a new issue on this repo](https://github.com/napari/npe2/issues/new).
@@ -12,7 +12,8 @@ that accepts a path (`str`) or a list of paths and:
12
12
  * returns a *new function* (a `ReaderFunction`) that is capable of doing the reading.
13
13
 
14
14
  The `ReaderFunction` will be passed the same path (or list of paths) and
15
- is expected to return a list of {ref}`LayerData tuples <layer-data-tuples>`.
15
+ is expected to return a list containing {ref}`LayerData tuples <layer-data-tuples>` or
16
+ a fully instantiated napari `Layer` objects like `Image` or `Labels`.
16
17
 
17
18
  In the rare case that a reader plugin would like to "claim" a file, but *not*
18
19
  actually add any data to the viewer, the `ReaderFunction` may return
@@ -64,7 +64,7 @@ specification:
64
64
  For more examples see [](creating-widgets) and
65
65
  [GUI gallery examples](https://napari.org/stable/_tags/gui.html) (only a subset
66
66
  involve widgets). Additionally,
67
- [cookiecutter-napari-plugin](https://github.com/napari/cookiecutter-napari-plugin)
67
+ [napari-plugin-template](https://github.com/napari/napari-plugin-template)
68
68
  has more robust widget examples that you can adapt to your needs.
69
69
 
70
70
  ```{note}
@@ -98,7 +98,7 @@ line-length = 88
98
98
  target-version = "py38"
99
99
  fix = true
100
100
  src = ["src/npe2", "tests"]
101
- select = [
101
+ lint.select = [
102
102
  "E",
103
103
  "F",
104
104
  "W", #flake8
@@ -110,14 +110,15 @@ select = [
110
110
  "RUF", # ruff-specific rules
111
111
  ]
112
112
 
113
- [tool.ruff.per-file-ignores]
113
+ [tool.ruff.lint.per-file-ignores]
114
114
  "src/npe2/cli.py" = ["B008", "A00"]
115
+ "**/test_*.py" = ["RUF018"]
115
116
 
116
- [tool.ruff.pyupgrade]
117
+ [tool.ruff.lint.pyupgrade]
117
118
  # Preserve types, even if a file imports `from __future__ import annotations`.
118
119
  keep-runtime-typing = true
119
120
 
120
- [tool.ruff.isort]
121
+ [tool.ruff.lint.isort]
121
122
  known-first-party = ['npe2']
122
123
 
123
124
  # https://mypy.readthedocs.io/en/stable/config_file.html
@@ -203,14 +203,12 @@ class ContributionDecorator(Generic[C]):
203
203
  self._contrib_name = CONTRIB_NAMES[self.contrib_type]
204
204
 
205
205
  @overload
206
- def __call__(self, func: T, **kwargs) -> T:
207
- ...
206
+ def __call__(self, func: T, **kwargs) -> T: ...
208
207
 
209
208
  @overload
210
209
  def __call__(
211
210
  self, func: Optional[Literal[None]] = None, **kwargs
212
- ) -> Callable[[T], T]:
213
- ...
211
+ ) -> Callable[[T], T]: ...
214
212
 
215
213
  def __call__(
216
214
  self, func: Optional[T] = None, **kwargs
@@ -3,10 +3,8 @@ from __future__ import annotations
3
3
  import io
4
4
  import json
5
5
  import os
6
- import re
7
6
  import subprocess
8
7
  import tempfile
9
- from concurrent.futures import ProcessPoolExecutor
10
8
  from contextlib import contextmanager
11
9
  from functools import lru_cache
12
10
  from importlib import metadata
@@ -20,11 +18,10 @@ from typing import (
20
18
  Iterator,
21
19
  List,
22
20
  Optional,
23
- Tuple,
24
21
  Union,
25
22
  )
26
23
  from unittest.mock import patch
27
- from urllib import error, parse, request
24
+ from urllib import error, request
28
25
  from zipfile import ZipFile
29
26
 
30
27
  from npe2.manifest import PackageMetadata
@@ -39,9 +36,8 @@ NPE1_ENTRY_POINT = "napari.plugin"
39
36
  NPE2_ENTRY_POINT = "napari.manifest"
40
37
  __all__ = [
41
38
  "fetch_manifest",
42
- "get_pypi_url",
43
39
  "get_hub_plugin",
44
- "get_pypi_plugins",
40
+ "get_pypi_url",
45
41
  ]
46
42
 
47
43
 
@@ -59,7 +55,7 @@ def _manifest_from_npe2_dist(
59
55
  module: str = match.groupdict()["module"]
60
56
  attr: str = match.groupdict()["attr"]
61
57
 
62
- mf_file = Path(dist.locate_file(Path(module.replace(".", os.sep)) / attr))
58
+ mf_file = Path(dist.locate_file(Path(module.replace(".", os.sep)) / attr)) # type: ignore[arg-type]
63
59
  if not mf_file.exists():
64
60
  raise ValueError( # pragma: no cover
65
61
  f"manifest {mf_file.name!r} does not exist in distribution "
@@ -264,7 +260,7 @@ def fetch_manifest(
264
260
  return _manifest_from_extracted_wheel(td)
265
261
  except metadata.PackageNotFoundError:
266
262
  return _manifest_from_pypi_sdist(package_or_url, version)
267
- except error.HTTPError:
263
+ except error.HTTPError: # pragma: no cover
268
264
  pass # pragma: no cover
269
265
  raise ValueError( # pragma: no cover
270
266
  f"Could not interpret {package_or_url!r} as a PYPI package name or URL to a "
@@ -377,75 +373,8 @@ def _tmp_pypi_sdist_download(
377
373
  return _tmp_targz_download(url)
378
374
 
379
375
 
380
- @lru_cache
381
- def _get_packages_by_classifier(classifier: str) -> Dict[str, str]:
382
- """Search for packages declaring ``classifier`` on PyPI.
383
-
384
- Returns
385
- -------
386
- packages : List[str]
387
- name of all packages at pypi that declare ``classifier``
388
- """
389
- PACKAGE_NAME_PATTERN = re.compile('class="package-snippet__name">(.+)</span>')
390
- PACKAGE_VERSION_PATTERN = re.compile('class="package-snippet__version">(.+)</span>')
391
-
392
- packages = {}
393
- page = 1
394
- url = f"https://pypi.org/search/?c={parse.quote_plus(classifier)}&page="
395
- while True:
396
- try:
397
- with request.urlopen(f"{url}{page}") as response:
398
- html = response.read().decode()
399
- names = PACKAGE_NAME_PATTERN.findall(html)
400
- versions = PACKAGE_VERSION_PATTERN.findall(html)
401
- packages.update(dict(zip(names, versions)))
402
- page += 1
403
- except error.HTTPError:
404
- break
405
-
406
- return dict(sorted(packages.items()))
407
-
408
-
409
- def get_pypi_plugins() -> Dict[str, str]:
410
- """Return {name: latest_version} for all plugins found on pypi."""
411
- NAPARI_CLASSIFIER = "Framework :: napari"
412
- return _get_packages_by_classifier(NAPARI_CLASSIFIER)
413
-
414
-
415
376
  @lru_cache
416
377
  def get_hub_plugin(plugin_name: str) -> Dict[str, Any]:
417
378
  """Return hub information for a specific plugin."""
418
379
  with request.urlopen(f"https://api.napari-hub.org/plugins/{plugin_name}") as r:
419
380
  return json.load(r)
420
-
421
-
422
- def _try_fetch_and_write_manifest(args: Tuple[str, str, Path, int]):
423
- name, version, dest, indent = args
424
- FORMAT = "json"
425
-
426
- try: # pragma: no cover
427
- mf = fetch_manifest(name, version=version)
428
- manifest_string = getattr(mf, FORMAT)(exclude=set(), indent=indent)
429
-
430
- (dest / f"{name}.{FORMAT}").write_text(manifest_string)
431
- print(f"✅ {name}")
432
- except Exception as e:
433
- print(f"❌ {name}")
434
- return name, {"version": version, "error": str(e)}
435
-
436
-
437
- def fetch_all_manifests(dest: str = "manifests", indent: int = 2) -> None:
438
- """Fetch all manifests for plugins on PyPI and write to ``dest`` directory."""
439
- _dest = Path(dest)
440
- _dest.mkdir(exist_ok=True, parents=True)
441
-
442
- args = [
443
- (name, ver, _dest, indent) for name, ver in sorted(get_pypi_plugins().items())
444
- ]
445
-
446
- # use processes instead of threads, because many of the subroutines in build
447
- # and setuptools use `os.chdir()`, which is not thread-safe
448
- with ProcessPoolExecutor() as executor:
449
- errors = list(executor.map(_try_fetch_and_write_manifest, args))
450
- _errors = {tup[0]: tup[1] for tup in errors if tup}
451
- (_dest / "errors.json").write_text(json.dumps(_errors, indent=indent))
@@ -404,11 +404,11 @@ class HookImplParser:
404
404
  )
405
405
 
406
406
  def add_command(self, impl: HookImplementation, py_name: str = "") -> str:
407
- name = impl.specname.replace("napari_", "")
408
- id = f"{self.package}.{name}"
409
- title = " ".join(name.split("_")).title()
410
407
  if not py_name:
411
408
  py_name = _python_name(impl.function)
409
+ name = impl.function.__name__
410
+ id = f"{self.package}.{name}"
411
+ title = " ".join(name.split("_")).title()
412
412
  c = CommandContribution(id=id, python_name=py_name, title=title)
413
413
  self.contributions["commands"].append(c)
414
414
  return id
@@ -516,7 +516,7 @@ def get_top_module_path(package_name, top_module: Optional[str] = None) -> Path:
516
516
  )
517
517
  top_module = top_mods[0]
518
518
 
519
- path = Path(dist.locate_file(top_module))
519
+ path = Path(dist.locate_file(top_module)) # type: ignore[arg-type]
520
520
  if not path.is_dir() and dist.files:
521
521
  for f_path in dist.files:
522
522
  if "__editable__" in f_path.name: