pluginify 0.1.0.post11.dev0__tar.gz → 1.0.0__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 (53) hide show
  1. pluginify-1.0.0/.github/workflows/code-quality.yaml +87 -0
  2. pluginify-1.0.0/.github/workflows/deploy-docs.yaml +32 -0
  3. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/.github/workflows/generate-badges.yaml +28 -52
  4. pluginify-1.0.0/.github/workflows/package-and-publish.yaml +34 -0
  5. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/.github/workflows/status-check.yaml +1 -1
  6. pluginify-1.0.0/.github/workflows/tag-and-release.yaml +27 -0
  7. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/PKG-INFO +13 -9
  8. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/README.md +12 -8
  9. pluginify-1.0.0/docs/source/releases/1.0.0/1.0.0-no-bug-fixes-required-on-this-release.yaml +17 -0
  10. pluginify-1.0.0/docs/source/releases/1.0.0/1.19.0-internal-release.yaml +12 -0
  11. pluginify-1.0.0/docs/source/releases/1.0.0/1.19.0-open-source-upload.yaml +7 -0
  12. pluginify-1.0.0/docs/source/releases/1.0.0/1.19.0-patch-internal-use-vars-runner.yaml +17 -0
  13. pluginify-1.0.0/docs/source/releases/1.0.0/module-to-class-updates.yaml +12 -0
  14. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/pluginify/_version.py +2 -2
  15. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/pluginify/commandline_typer.py +4 -2
  16. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/pluginify/config.py +3 -1
  17. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/pluginify/create_plugin_registries.py +12 -0
  18. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/pluginify/interfaces/__init__.py +5 -2
  19. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/pluginify/interfaces/base.py +2 -2
  20. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/pluginify/interfaces/class_based/data_modifiers.py +1 -1
  21. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/pluginify/interfaces/class_based_plugin.py +10 -6
  22. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/pluginify/plugin_registry.py +4 -5
  23. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/pluginify/plugins/classes/data_modifiers/cuboid.py +3 -0
  24. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/pluginify/pydantic_models/v1/configs.py +3 -0
  25. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/pluginify/utils/validators.py +3 -0
  26. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/pyproject.toml +19 -1
  27. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/tests/conftest.py +13 -6
  28. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/tests/unit_tests/config/test_config.py +3 -0
  29. pluginify-0.1.0.post11.dev0/.github/workflows/lint-and-test.yaml +0 -119
  30. pluginify-0.1.0.post11.dev0/.github/workflows/package-and-publish.yaml +0 -106
  31. pluginify-0.1.0.post11.dev0/docs/source/releases/latest/initial-commit.yaml +0 -92
  32. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/LICENSE +0 -0
  33. {pluginify-0.1.0.post11.dev0/docs/source/releases/latest → pluginify-1.0.0/docs/source/releases/1.0.0}/ci-fix-perms.yaml +0 -0
  34. {pluginify-0.1.0.post11.dev0/docs/source/releases/latest → pluginify-1.0.0/docs/source/releases/1.0.0}/copy-geoips-functionality.yaml +0 -0
  35. {pluginify-0.1.0.post11.dev0/docs/source/releases/latest → pluginify-1.0.0/docs/source/releases/1.0.0}/ignore-dot-files-and-dirs.yaml +0 -0
  36. {pluginify-0.1.0.post11.dev0/docs/source/releases/latest → pluginify-1.0.0/docs/source/releases/1.0.0}/obp-plugin-registry-updates.yaml +0 -0
  37. {pluginify-0.1.0.post11.dev0/docs/source/releases/latest → pluginify-1.0.0/docs/source/releases/1.0.0}/pluginify-updates-jeremy-comments.yaml +0 -0
  38. {pluginify-0.1.0.post11.dev0/docs/source/releases/latest → pluginify-1.0.0/docs/source/releases/1.0.0}/pypi-publish-bug-fix.yaml +0 -0
  39. {pluginify-0.1.0.post11.dev0/docs/source/releases/latest → pluginify-1.0.0/docs/source/releases/1.0.0}/remove-all-geoips-references.yaml +0 -0
  40. {pluginify-0.1.0.post11.dev0/docs/source/releases/latest → pluginify-1.0.0/docs/source/releases/1.0.0}/replace-geoips-functionality.yaml +0 -0
  41. {pluginify-0.1.0.post11.dev0/docs/source/releases/latest → pluginify-1.0.0/docs/source/releases/1.0.0}/update-black-formatting.yaml +0 -0
  42. {pluginify-0.1.0.post11.dev0/docs/source/releases/latest → pluginify-1.0.0/docs/source/releases/1.0.0}/version-update.yaml +0 -0
  43. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/pluginify/__init__.py +0 -0
  44. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/pluginify/errors.py +0 -0
  45. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/pluginify/interfaces/yaml_based/configs.py +0 -0
  46. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/pluginify/plugins/yaml/configs/stucco.yaml +0 -0
  47. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/pluginify/utils/__init__.py +0 -0
  48. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/pluginify/utils/context_managers.py +0 -0
  49. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/tests/unit_tests/plugin_registries/files/bad/invalid_interfaces.yaml +0 -0
  50. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/tests/unit_tests/plugin_registries/files/bad/missing_lowest_keys.yaml +0 -0
  51. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/tests/unit_tests/plugin_registries/files/bad/missing_plugin_types.yaml +0 -0
  52. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/tests/unit_tests/plugin_registries/files/good/pluginify.yaml +0 -0
  53. {pluginify-0.1.0.post11.dev0 → pluginify-1.0.0}/tests/unit_tests/plugin_registries/test_plugin_registries.py +0 -0
@@ -0,0 +1,87 @@
1
+ name: CodeQuality
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: ${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ env:
17
+ UV_SYSTEM_PYTHON: true
18
+
19
+ jobs:
20
+ lint:
21
+ continue-on-error: true
22
+ runs-on: ${{ vars.RUNNER }}
23
+ steps:
24
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
25
+
26
+ - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
27
+ with:
28
+ python-version: "3.13"
29
+
30
+ - uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
31
+ with:
32
+ go-version: stable
33
+ cache: false
34
+
35
+ - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
36
+
37
+ - name: Install linters
38
+ run: |
39
+ uv pip install ruff blacken-docs mdformat validate-pyproject
40
+ go install github.com/rhysd/actionlint/cmd/actionlint@latest
41
+ go install github.com/google/yamlfmt/cmd/yamlfmt@latest
42
+ echo "$HOME/go/bin" >> "$GITHUB_PATH"
43
+
44
+ - name: Ruff (lint)
45
+ run: ruff check ./pluginify
46
+
47
+ - name: Ruff (format)
48
+ if: success() || failure()
49
+ run: ruff format --check ./pluginify
50
+
51
+ - name: Blacken-docs
52
+ if: success() || failure()
53
+ run: git ls-files '*.rst' '*.md' | xargs -r blacken-docs --check
54
+
55
+ - name: mdformat
56
+ if: success() || failure()
57
+ run: mdformat --check .
58
+
59
+ - name: actionlint
60
+ if: success() || failure()
61
+ run: actionlint
62
+
63
+ - name: validate-pyproject
64
+ if: success() || failure()
65
+ run: validate-pyproject pyproject.toml
66
+
67
+ - name: yamlfmt
68
+ if: success() || failure()
69
+ run: yamlfmt -lint
70
+
71
+ mypy:
72
+ continue-on-error: true
73
+ runs-on: ${{ vars.RUNNER }}
74
+ steps:
75
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
76
+
77
+ - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
78
+ with:
79
+ python-version: "3.13"
80
+
81
+ - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
82
+
83
+ - name: Install package with all extras
84
+ run: uv pip install -e ".[doc,lint,test]" mypy
85
+
86
+ - name: Run mypy
87
+ run: mypy ./pluginify
@@ -0,0 +1,32 @@
1
+ name: Deploy docs
2
+
3
+ # 1. Tag and Release - on merge of v*-version-release
4
+ # * Tag current version
5
+ # * Release just tagged version
6
+ # 2. Package and Publish - on published release (from #1)
7
+ # * Build wheel
8
+ # * Publish to pypi
9
+ # 3. Deploy docs - on published release (from #1)
10
+ # * pip install geoips
11
+ # * pip install plugin repo
12
+ # * build docs with geoips/docs/build_docs.sh
13
+ # * deploy docs with geoips/docs/deploy_pages.sh
14
+
15
+ on:
16
+ # Triggers the workflow on published release
17
+ release:
18
+ types:
19
+ - published
20
+ # Allows run of this workflow manually from the Actions tab
21
+ # Must be merged to default before it will be available to manually run.
22
+ workflow_dispatch:
23
+
24
+ jobs:
25
+ deploy-docs:
26
+ name: Deploy docs
27
+ # You do not appear to be able to use variables in the "uses" field.
28
+ uses: NRLMMD-GEOIPS/geoips_ci/.github/workflows/reusable-deploy-docs.yaml@main
29
+ permissions:
30
+ contents: write
31
+ secrets:
32
+ token: ${{ secrets.GITHUB_TOKEN }}
@@ -17,46 +17,46 @@ env:
17
17
 
18
18
  jobs:
19
19
  check-commits:
20
- runs-on: ubuntu-latest
20
+ runs-on: ${{ vars.RUNNER }}
21
21
  outputs:
22
22
  has_new_commits: ${{ steps.check.outputs.has_new_commits }}
23
23
  steps:
24
- - uses: actions/checkout@v4
24
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
25
25
  with:
26
26
  fetch-depth: 0
27
27
 
28
28
  - name: Check for new commits in last 24 hours
29
29
  id: check
30
30
  run: |
31
- COMMITS=$(git log --oneline --since="25 hours ago" --no-merges | grep -v "\[skip ci\]" | wc -l)
31
+ COMMITS=$(git log --oneline --since="25 hours ago" --no-merges | grep -c -v "\[skip ci\]")
32
32
  if [ "$COMMITS" -gt 0 ]; then
33
- echo "has_new_commits=true" >> $GITHUB_OUTPUT
33
+ echo "has_new_commits=true" >> "$GITHUB_OUTPUT"
34
34
  echo "Found $COMMITS new commits in the last 25 hours"
35
35
  else
36
- echo "has_new_commits=false" >> $GITHUB_OUTPUT
36
+ echo "has_new_commits=false" >> "$GITHUB_OUTPUT"
37
37
  echo "No new commits in the last 25 hours"
38
38
  fi
39
39
 
40
40
  generate-badges:
41
41
  needs: check-commits
42
42
  if: needs.check-commits.outputs.has_new_commits == 'true'
43
- runs-on: ubuntu-latest
43
+ runs-on: ${{ vars.RUNNER }}
44
44
 
45
45
  steps:
46
- - uses: actions/checkout@v4
46
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
47
47
  with:
48
48
  fetch-depth: 0
49
49
 
50
- - uses: actions/setup-python@v5
50
+ - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
51
51
  with:
52
52
  python-version: "3.13"
53
53
 
54
- - uses: astral-sh/setup-uv@v6
54
+ - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
55
55
 
56
56
  - name: Install dependencies
57
57
  run: |
58
- uv pip install -e .[doc,lint,test]
59
- uv pip install pytest mypy ruff commitizen coverage genbadge[all]
58
+ uv pip install -e ".[doc,lint,test]"
59
+ uv pip install pytest mypy ruff commitizen coverage "genbadge[all]"
60
60
 
61
61
  - name: Create directories
62
62
  run: |
@@ -95,7 +95,7 @@ jobs:
95
95
  - name: Run mypy
96
96
  id: mypy
97
97
  continue-on-error: true
98
- run: mypy ./src --junit-xml reports/mypy.xml || true
98
+ run: mypy ./pluginify --junit-xml reports/mypy.xml || true
99
99
 
100
100
  - name: Generate mypy badge
101
101
  run: |
@@ -112,7 +112,7 @@ jobs:
112
112
  - name: Run ruff
113
113
  id: ruff
114
114
  continue-on-error: true
115
- run: ruff check ./src --output-format=junit -o reports/ruff.xml || true
115
+ run: ruff check ./pluginify --output-format=junit -o reports/ruff.xml || true
116
116
 
117
117
  - name: Generate ruff badge
118
118
  run: |
@@ -155,31 +155,6 @@ jobs:
155
155
  "
156
156
  fi
157
157
 
158
- - uses: actions/setup-node@v4
159
- with:
160
- node-version: "22"
161
-
162
- - name: Run cspell
163
- id: cspell
164
- continue-on-error: true
165
- run: npx cspell "./src/**/*" --no-progress
166
-
167
- - name: Generate cspell badge
168
- run: |
169
- if [ "${{ steps.cspell.outcome }}" == "success" ]; then
170
- python -c "
171
- from genbadge import Badge
172
- b = Badge(left_txt='cspell', right_txt='passing', color='brightgreen')
173
- b.write_to('.github/badges/cspell-badge.svg', use_shields=False)
174
- "
175
- else
176
- python -c "
177
- from genbadge import Badge
178
- b = Badge(left_txt='cspell', right_txt='failing', color='red')
179
- b.write_to('.github/badges/cspell-badge.svg', use_shields=False)
180
- "
181
- fi
182
-
183
158
  - name: Check commitizen
184
159
  id: commitizen
185
160
  continue-on-error: true
@@ -208,10 +183,10 @@ jobs:
208
183
  run: |
209
184
  git add .github/badges/*.svg
210
185
  if git diff --cached --quiet; then
211
- echo "has_changes=false" >> $GITHUB_OUTPUT
186
+ echo "has_changes=false" >> "$GITHUB_OUTPUT"
212
187
  echo "No badge changes detected"
213
188
  else
214
- echo "has_changes=true" >> $GITHUB_OUTPUT
189
+ echo "has_changes=true" >> "$GITHUB_OUTPUT"
215
190
  echo "Badge changes detected:"
216
191
  git diff --cached --name-status .github/badges/
217
192
  fi
@@ -226,15 +201,16 @@ jobs:
226
201
 
227
202
  - name: Generate summary
228
203
  run: |
229
- echo "## Badge Generation Summary" >> $GITHUB_STEP_SUMMARY
230
- echo "" >> $GITHUB_STEP_SUMMARY
231
- echo "| Check | Status |" >> $GITHUB_STEP_SUMMARY
232
- echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
233
- echo "| Pytest & Coverage | ${{ steps.pytest.outcome }} |" >> $GITHUB_STEP_SUMMARY
234
- echo "| Mypy | ${{ steps.mypy.outcome }} |" >> $GITHUB_STEP_SUMMARY
235
- echo "| Ruff | ${{ steps.ruff.outcome }} |" >> $GITHUB_STEP_SUMMARY
236
- echo "| Install | ${{ steps.install.outcome }} |" >> $GITHUB_STEP_SUMMARY
237
- echo "| CSpell | ${{ steps.cspell.outcome }} |" >> $GITHUB_STEP_SUMMARY
238
- echo "| Commitizen | ${{ steps.commitizen.outcome }} |" >> $GITHUB_STEP_SUMMARY
239
- echo "" >> $GITHUB_STEP_SUMMARY
240
- echo "Badges committed: ${{ steps.badge_changes.outputs.has_changes }}" >> $GITHUB_STEP_SUMMARY
204
+ {
205
+ echo "## Badge Generation Summary"
206
+ echo ""
207
+ echo "| Check | Status |"
208
+ echo "|-------|--------|"
209
+ echo "| Pytest & Coverage | ${{ steps.pytest.outcome }} |"
210
+ echo "| Mypy | ${{ steps.mypy.outcome }} |"
211
+ echo "| Ruff | ${{ steps.ruff.outcome }} |"
212
+ echo "| Install | ${{ steps.install.outcome }} |"
213
+ echo "| Commitizen | ${{ steps.commitizen.outcome }} |"
214
+ echo ""
215
+ echo "Badges committed: ${{ steps.badge_changes.outputs.has_changes }}"
216
+ } >> "$GITHUB_STEP_SUMMARY"
@@ -0,0 +1,34 @@
1
+ name: Package/publish
2
+
3
+ # 1. Tag and Release - on merge of v*-version-release
4
+ # * Tag current version
5
+ # * Release just tagged version
6
+ # 2. Package and Publish - on published release (from #1)
7
+ # * Build wheel
8
+ # * Publish to pypi
9
+ # 3. Deploy docs - on published release (from #1)
10
+ # * pip install geoips
11
+ # * pip install plugin repo
12
+ # * build docs with geoips/docs/build_docs.sh
13
+ # * deploy docs with geoips/docs/deploy_pages.sh
14
+
15
+ on:
16
+ # triggers the workflow on published release
17
+ release:
18
+ types:
19
+ - published
20
+ # allows run of this workflow manually from the actions tab
21
+ # must be merged to default before it will be available to manually run.
22
+ workflow_dispatch:
23
+
24
+ jobs:
25
+ package-publish:
26
+ name: Package/publish
27
+ # You do not appear to be able to use variables in the "uses" field.
28
+ uses: NRLMMD-GEOIPS/geoips_ci/.github/workflows/reusable-package-and-publish.yaml@main
29
+ permissions:
30
+ contents: read
31
+ secrets:
32
+ token: ${{ secrets.GITHUB_TOKEN }}
33
+ pypi_user: ${{ secrets.PYPI_USER }}
34
+ pypi_password: ${{ secrets.PYPI_PASSWORD }}
@@ -11,7 +11,7 @@ permissions:
11
11
 
12
12
  jobs:
13
13
  status-check:
14
- runs-on: ubuntu-latest
14
+ runs-on: ${{ vars.RUNNER }}
15
15
  steps:
16
16
  - name: No-op status check
17
17
  run: echo "No-op Actions workflow to allow enforcing up to date branches before merge"
@@ -0,0 +1,27 @@
1
+ name: Tag/release
2
+
3
+ on:
4
+ # Triggers the workflow when pull request closed (either closed
5
+ # as non-planned, or actually approved and merged.)
6
+ pull_request:
7
+ types:
8
+ - closed
9
+ # You do not appear to be able to use variables in triggers
10
+ branches:
11
+ - main
12
+ # Allows run of this workflow manually from the Actions tab
13
+ # Must be merged to default branch before it will be available
14
+ # to manually run.
15
+ workflow_dispatch:
16
+
17
+ jobs:
18
+ tag-release:
19
+ name: Tag/release
20
+ # You do not appear to be able to use variables in the "uses" field.
21
+ uses: NRLMMD-GEOIPS/geoips_ci/.github/workflows/reusable-tag-and-release.yaml@main
22
+ # Only run this if the pull request was merged, not just closed.
23
+ if: github.event.pull_request.merged == true
24
+ permissions:
25
+ contents: write
26
+ secrets:
27
+ token: ${{ secrets.GITHUB_TOKEN }}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pluginify
3
- Version: 0.1.0.post11.dev0
3
+ Version: 1.0.0
4
4
  Summary: Pluginify package
5
5
  License: LICENSE
6
6
  License-File: LICENSE
@@ -24,11 +24,12 @@ Requires-Dist: typer
24
24
  Project-URL: Repository, https://github.com/NRLMMD-GEOIPS/pluginify
25
25
  Description-Content-Type: text/markdown
26
26
 
27
- # # # This source code is subject to the license referenced at
28
- # # # https://github.com/NRLMMD-GEOIPS.
27
+ ```
28
+ # # # This source code is subject to the license referenced at
29
+ # # # https://github.com/NRLMMD-GEOIPS.
30
+ ```
29
31
 
30
- Pluginify
31
- =========
32
+ # Pluginify
32
33
 
33
34
  This repository contains everything necessary to fully register YAML and python classes
34
35
  and/or modules as valid python plugin objects. A YAML-based plugin object essentially
@@ -43,21 +44,24 @@ PluginRegistry class. This package can and is used alongside other packages such
43
44
  [GeoIPS](https://github.com/NRLMMD-GEOIPS/geoips) to handle their plugin-based
44
45
  infrastructure.
45
46
 
46
- Install pluginify package
47
- -------------------------
47
+ ## Install pluginify package
48
+
48
49
  Current status:
50
+
49
51
  ```bash
50
52
  git clone https://github.com/NRLMMD-GEOIPS/pluginify.git
51
53
  # cd to pluginify's top level dir
52
54
  pip install -e .
53
55
  ```
56
+
54
57
  OR
58
+
55
59
  ```bash
56
60
  pip install pluginify
57
61
  ```
58
62
 
59
- Use pluginify
60
- -------------
63
+ ## Use pluginify
64
+
61
65
  ```bash
62
66
  pluginify -h
63
67
  # Top level commands without additional args
@@ -1,8 +1,9 @@
1
- # # # This source code is subject to the license referenced at
2
- # # # https://github.com/NRLMMD-GEOIPS.
1
+ ```
2
+ # # # This source code is subject to the license referenced at
3
+ # # # https://github.com/NRLMMD-GEOIPS.
4
+ ```
3
5
 
4
- Pluginify
5
- =========
6
+ # Pluginify
6
7
 
7
8
  This repository contains everything necessary to fully register YAML and python classes
8
9
  and/or modules as valid python plugin objects. A YAML-based plugin object essentially
@@ -17,21 +18,24 @@ PluginRegistry class. This package can and is used alongside other packages such
17
18
  [GeoIPS](https://github.com/NRLMMD-GEOIPS/geoips) to handle their plugin-based
18
19
  infrastructure.
19
20
 
20
- Install pluginify package
21
- -------------------------
21
+ ## Install pluginify package
22
+
22
23
  Current status:
24
+
23
25
  ```bash
24
26
  git clone https://github.com/NRLMMD-GEOIPS/pluginify.git
25
27
  # cd to pluginify's top level dir
26
28
  pip install -e .
27
29
  ```
30
+
28
31
  OR
32
+
29
33
  ```bash
30
34
  pip install pluginify
31
35
  ```
32
36
 
33
- Use pluginify
34
- -------------
37
+ ## Use pluginify
38
+
35
39
  ```bash
36
40
  pluginify -h
37
41
  # Top level commands without additional args
@@ -0,0 +1,17 @@
1
+ documentation:
2
+ - title: Add release note for version 1.19.0
3
+ description: |
4
+ Release note on release branch to force tag/release, package/publish,
5
+ and deploy docs.
6
+
7
+ Additionally add any updated files from geoips_ci/sync
8
+ files:
9
+ added:
10
+ - docs/source/releases/latest/1.19.0-release-note.yaml
11
+ modified:
12
+ - geoips_ci/sync updated files
13
+ date:
14
+ start: 2026-06-05
15
+ finish: 2026-06-05
16
+ related-issue:
17
+ internal: geoips#1067 - 1.19.0 updates
@@ -0,0 +1,12 @@
1
+ Release Process:
2
+ - title: Add 1.19.0 release note
3
+ description: |
4
+ Currently tagged internal version 1.18.2.
5
+ files:
6
+ added:
7
+ - docs/source/releases/1.19.0/1.19.0-internal-release.yaml
8
+ related-issue:
9
+ internal: pluginify#1067 - 1.19.0 updates*
10
+ date:
11
+ start: 2026-05-26
12
+ finish: 2026-05-26
@@ -0,0 +1,7 @@
1
+ Release Updates - Open Source Upload:
2
+ - title: Open source upload
3
+ description: "This repo updated with current geoips version release"
4
+ files:
5
+ modified:
6
+ - standard sync files
7
+ - release notes
@@ -0,0 +1,17 @@
1
+ continuous integration:
2
+ - title: 'Use vars.RUNNER for runners'
3
+ description: |
4
+ Ensure we are using standard vars.RUNNER for the new pluginify-specific workflows.
5
+ Eventually we will want to consolidate this CI with the standard actions in
6
+ geoips_ci, but for now at least use vars.RUNNER.
7
+ files:
8
+ added: []
9
+ modified:
10
+ - '.github/workflows/generate-badges.yaml'
11
+ - '.github/workflows/lint-and-test.yaml'
12
+ deleted: []
13
+ moved: []
14
+ date:
15
+ start: 2026-05-26
16
+ finish: 2026-05-26
17
+
@@ -0,0 +1,12 @@
1
+ bug fix:
2
+ - title: 'Fix bug where non-plugin modules are treated like plugins during registry initialization'
3
+ description: |
4
+ In GeoIPS 1342 we converted nearly all of the module-based plugins to true
5
+ class-based plugins. In doing so I discovered a bug where non-plugin modules living
6
+ in the geoips/plugins/classes/.../ directory caused errors when trying to build
7
+ the plugin registry. To fix this, I've added a check to see if a module has an
8
+ 'interface' attribute set to None. If that condition is met, then just ignore the
9
+ module and continue to the next potential plugin.
10
+ files:
11
+ modified:
12
+ - pluginify/create_plugin_registries.py
@@ -3,5 +3,5 @@
3
3
 
4
4
  # DO NOT EDIT
5
5
  # managed by poetry-dynamic-versioning
6
- __version__ = "0.1.0.post11.dev0"
7
- __version_tuple__ = (0, 1, 0, "post11", "dev0")
6
+ __version__ = "1.0.0"
7
+ __version_tuple__ = (1, 0, 0)
@@ -1,3 +1,6 @@
1
+ # # # This source code is subject to the license referenced at
2
+ # # # https://github.com/NRLMMD-GEOIPS.
3
+
1
4
  """Commandline module for Pluginify.
2
5
 
3
6
  Supports two main commands, `pluginify create` and `pluginify delete` as well as
@@ -140,7 +143,6 @@ class DocstringTyper(typer.Typer):
140
143
  new_params = []
141
144
 
142
145
  for name, param in sig.parameters.items():
143
-
144
146
  default = param.default
145
147
  help_text = param_help.get(name)
146
148
 
@@ -155,7 +157,7 @@ class DocstringTyper(typer.Typer):
155
157
 
156
158
  # Optional arguments
157
159
  short = f"-{name[0]}"
158
- long = f"--{name.replace('_','-')}"
160
+ long = f"--{name.replace('_', '-')}"
159
161
 
160
162
  option = typer.Option(default, short, long, help=help_text)
161
163
 
@@ -1,3 +1,6 @@
1
+ # # # This source code is subject to the license referenced at
2
+ # # # https://github.com/NRLMMD-GEOIPS.
3
+
1
4
  """Module containing configuration variables needed for pluginify to run."""
2
5
 
3
6
 
@@ -58,7 +61,6 @@ def _env_to_variable(name, default):
58
61
  env_val = getenv(name)
59
62
 
60
63
  if env_val:
61
-
62
64
  if name == "PLUGINIFY_REGISTRY_DIRECTORY":
63
65
  return Path(env_val)
64
66
  elif name == "PLUGINIFY_REBUILD_REGISTRIES":
@@ -957,6 +957,18 @@ def add_class_plugin(package, relpath, plugins):
957
957
  at relpath '{relpath}'\n"""
958
958
  return error_message
959
959
 
960
+ # If interface is None, then legitimately skip the module.
961
+ # We want to skip this first, before we test anything else.
962
+ # If it is not a plugin, we don't care if there are other
963
+ # errors in it at this stage (ie, avoid unnecessary unrelated
964
+ # catastrophic failures)
965
+ if hasattr(module, "interface") and module.interface is None:
966
+ LOG.info(
967
+ f"Skipping module '{module_name}' from '{package}', "
968
+ "interface_name is 'None'"
969
+ )
970
+ return error_message
971
+
960
972
  # We've encountered a truly 'class-based' plugin. I.e. we don't need to generate
961
973
  # the plugin object from the module itself. Collect metadata from this plugin
962
974
  # in a different fashion to what we've done previously.
@@ -1,7 +1,10 @@
1
+ # # # This source code is subject to the license referenced at
2
+ # # # https://github.com/NRLMMD-GEOIPS.
3
+
1
4
  """Initialization module for pluginify interfaces."""
2
5
 
3
- from pluginify.interfaces.class_based.data_modifiers import data_modifiers
4
- from pluginify.interfaces.yaml_based.configs import configs
6
+ from pluginify.interfaces.class_based.data_modifiers import data_modifiers # noqa: F401
7
+ from pluginify.interfaces.yaml_based.configs import configs # noqa: F401
5
8
 
6
9
  class_based_interfaces = ["data_modifiers"]
7
10
  yaml_based_interfaces = ["configs"]
@@ -35,7 +35,7 @@ class BaseInterface(abc.ABC):
35
35
  import pluginify.plugin_registry as plugin_registry_module
36
36
 
37
37
  name = "BaseInterface"
38
- interface_type = None # This is set by child classes
38
+ interface_type: str = "" # This is set by child classes
39
39
  rebuild_registries = REBUILD_REGISTRIES
40
40
  # Setting this attribute at the top level so it can be used by all methods.
41
41
  # This can be overridden by setting them in child interface classes
@@ -375,7 +375,7 @@ class BaseClassInterface(BaseInterface):
375
375
 
376
376
  interface_type = "class_based"
377
377
  name = "BaseClassInterface"
378
- required_args = {}
378
+ required_args: dict[str, list[str]] = {}
379
379
 
380
380
  def __repr__(self):
381
381
  """Plugin interface repr method."""
@@ -32,7 +32,7 @@ class DataModifiersInterface(BaseClassInterface):
32
32
  "standard": ["data", "config"],
33
33
  }
34
34
 
35
- required_kwargs = {"standard": []}
35
+ required_kwargs: dict[str, list[str]] = {"standard": []}
36
36
 
37
37
 
38
38
  data_modifiers = DataModifiersInterface()
@@ -1,3 +1,6 @@
1
+ # # # This source code is subject to the license referenced at
2
+ # # # https://github.com/NRLMMD-GEOIPS.
3
+
1
4
  """Implements a base class for class-based plugins.
2
5
 
3
6
  The base class implemented here would expose the call signature of the child plugin
@@ -72,6 +75,7 @@ class BaseClassPlugin(ABC):
72
75
  # If no family is provided, just assume it works with DT
73
76
  data_tree = False
74
77
  required_attributes = ["interface", "family", "name"]
78
+ __plugin_abstract__: bool = False
75
79
 
76
80
  def _check_interface_attribute(cls):
77
81
  """Check the validity of the 'interface' attribute.
@@ -196,15 +200,15 @@ class BaseClassPlugin(ABC):
196
200
  if "__call__" in cls.__dict__:
197
201
  raise TypeError(f"{cls.__name__} cannot override __call__")
198
202
 
199
- try:
200
- call_method = cls.__dict__.get("call")
201
- except AttributeError:
203
+ if "call" not in cls.__dict__:
202
204
  raise TypeError(f"{cls.__name__} must implement call()")
205
+ call_method = cls.__dict__["call"]
203
206
 
204
- @functools.wraps(call_method)
207
+ @functools.wraps(call_method) # type: ignore[arg-type]
205
208
  def _call(self, data=None, *args, **kwargs):
206
209
  return cls._invoke(self, data, *args, **kwargs)
207
210
 
208
- _call.__signature__ = inspect.signature(call_method) # mirror only call()
211
+ call_sig = inspect.signature(call_method)
212
+ _call.__signature__ = call_sig # type: ignore[attr-defined]
209
213
  _call.__annotations__ = getattr(call_method, "__annotations__", {})
210
- cls.__call__ = _call
214
+ cls.__call__ = _call # type: ignore[method-assign]
@@ -128,7 +128,7 @@ class PluginRegistry:
128
128
 
129
129
  See the interface_mapping property for more information.
130
130
  """
131
- self._registered_plugins = new_value
131
+ self._interface_mapping = new_value
132
132
 
133
133
  @property
134
134
  def registered_yaml_based_plugins(self):
@@ -170,7 +170,6 @@ class PluginRegistry:
170
170
  """
171
171
  # Load the registries here and return them as a dictionary
172
172
  if not hasattr(self, "_registered_plugins") or force_reset:
173
-
174
173
  # Complete dictionary of all available plugins found in every plugin package
175
174
  self._registered_plugins = {}
176
175
  # A mapping of interfaces to plugin_types. Ie:
@@ -478,9 +477,9 @@ class PluginRegistry:
478
477
 
479
478
  if _expand:
480
479
  # Only applies to workflow plugins
481
- return model_class.model_validate(data, context={"expand": True})
480
+ return model_class.model_validate(data, context={"expand": True}) # type: ignore[no-any-return] # NOQA
482
481
 
483
- return model_class(**data)
482
+ return model_class(**data) # type: ignore[no-any-return]
484
483
 
485
484
  def get_yaml_plugin(
486
485
  self, interface_obj, name, rebuild_registries=None, _expand=False
@@ -886,7 +885,7 @@ class PluginRegistry:
886
885
  for pkg in plugin_packages:
887
886
  if pkg.value in packages:
888
887
  filtered_packages.append(pkg)
889
- plugin_packages = filtered_packages
888
+ plugin_packages = type(plugin_packages)(filtered_packages) # type: ignore[arg-type] # NOQA
890
889
 
891
890
  LOG.debug(plugin_packages)
892
891
  create_plugin_registries(plugin_packages, save_type, self.namespace)
@@ -1,3 +1,6 @@
1
+ # # # This source code is subject to the license referenced at
2
+ # # # https://github.com/NRLMMD-GEOIPS.
3
+
1
4
  """Cuboid data modifier plugin class.
2
5
 
3
6
  This is a 'dummy' plugin which is strictly used for testing pluginify.
@@ -1,3 +1,6 @@
1
+ # # # This source code is subject to the license referenced at
2
+ # # # https://github.com/NRLMMD-GEOIPS.
3
+
1
4
  """
2
5
  Pydantic model for pluginify configuration plugins.
3
6
 
@@ -1,3 +1,6 @@
1
+ # # # This source code is subject to the license referenced at
2
+ # # # https://github.com/NRLMMD-GEOIPS.
3
+
1
4
  """Pluginify validators module.
2
5
 
3
6
  Currently only implements a PluginRegistryValidator class.
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "pluginify" # package available at the root of the project
3
- version = "0.1.0.post11.dev0"
3
+ version = "1.0.0"
4
4
  description = "Pluginify package"
5
5
  authors = ["Evan Rose", "evrose54@colostate.edu"]
6
6
  readme = "README.md"
@@ -63,3 +63,21 @@ doc = [
63
63
 
64
64
  [tool.poetry.scripts]
65
65
  pluginify = "pluginify.commandline_typer:main"
66
+
67
+ [tool.mypy]
68
+ python_version = "3.11"
69
+ follow_imports = "normal"
70
+ warn_return_any = true
71
+ warn_unused_configs = true
72
+ exclude = ["_version.py"]
73
+
74
+ [[tool.mypy.overrides]]
75
+ module = [
76
+ "yaml",
77
+ "jsonschema.*",
78
+ "lexeme_type.*",
79
+ "pytest",
80
+ "geoips.*",
81
+ "geoips.interfaces",
82
+ ]
83
+ ignore_missing_imports = true
@@ -1,3 +1,6 @@
1
+ # # # This source code is subject to the license referenced at
2
+ # # # https://github.com/NRLMMD-GEOIPS.
3
+
1
4
  """Pytest configuration for test data validation.
2
5
 
3
6
  Provides command-line options and fixtures to control test behavior
@@ -20,12 +23,16 @@ def pytest_addoption(parser):
20
23
  Adds --no-fail-on-missing-data flag to skip tests instead of
21
24
  failing when test data is unavailable.
22
25
  """
23
- parser.addoption(
24
- "--no-fail-on-missing-data",
25
- action="store_true",
26
- default=False,
27
- help="Fail tests if test data is missing",
28
- )
26
+ try:
27
+ parser.addoption(
28
+ "--no-fail-on-missing-data",
29
+ action="store_true",
30
+ default=False,
31
+ help="Fail tests if test data is missing",
32
+ )
33
+ except ValueError as resp:
34
+ if "option names {'--no-fail-on-missing-data'} already added" in str(resp):
35
+ pass
29
36
 
30
37
 
31
38
  @pytest.fixture
@@ -1,3 +1,6 @@
1
+ # # # This source code is subject to the license referenced at
2
+ # # # https://github.com/NRLMMD-GEOIPS.
3
+
1
4
  """Unit test module for pluginify's config.py module."""
2
5
 
3
6
  from pathlib import Path
@@ -1,119 +0,0 @@
1
- name: CI
2
-
3
- on:
4
- push:
5
- branches: [main]
6
- pull_request:
7
- branches: [main]
8
-
9
- permissions:
10
- contents: read
11
-
12
- concurrency:
13
- group: ${{ github.workflow }}-${{ github.ref }}
14
- cancel-in-progress: true
15
-
16
- env:
17
- UV_SYSTEM_PYTHON: true
18
- COMMITIZEN_START_REV: "9d83e6984277ccbe6c5f6713f65b75a90e7c7e40"
19
-
20
- jobs:
21
- # ---------------------------------------------------------------------------
22
- # Single lint job — every hook runs as its own step so failures are visible
23
- # ---------------------------------------------------------------------------
24
- lint:
25
- runs-on: ubuntu-latest
26
- steps:
27
- - uses: actions/checkout@v4
28
- with:
29
- fetch-depth: 0 # needed for commitizen rev-range
30
-
31
- - uses: actions/setup-python@v5
32
- with:
33
- python-version: "3.13"
34
-
35
- - uses: actions/setup-go@v5
36
- with:
37
- go-version: stable
38
- cache: false
39
-
40
- - uses: actions/setup-node@v4
41
- with:
42
- node-version: "22"
43
-
44
- - uses: astral-sh/setup-uv@v6
45
-
46
- - name: Ruff (lint)
47
- uses: pre-commit/action@v3.0.1
48
- with:
49
- extra_args: ruff-check --all-files
50
-
51
- - name: Ruff (format)
52
- if: success() || failure()
53
- uses: pre-commit/action@v3.0.1
54
- with:
55
- extra_args: ruff-format --all-files
56
-
57
- - name: Blacken-docs
58
- if: success() || failure()
59
- uses: pre-commit/action@v3.0.1
60
- with:
61
- extra_args: blacken-docs --all-files
62
-
63
- - name: mdformat
64
- if: success() || failure()
65
- uses: pre-commit/action@v3.0.1
66
- with:
67
- extra_args: mdformat --all-files
68
-
69
- - name: actionlint
70
- if: success() || failure()
71
- uses: pre-commit/action@v3.0.1
72
- with:
73
- extra_args: actionlint --all-files
74
-
75
- - name: validate-pyproject
76
- if: success() || failure()
77
- uses: pre-commit/action@v3.0.1
78
- with:
79
- extra_args: validate-pyproject --all-files
80
-
81
- - name: yamlfmt
82
- if: success() || failure()
83
- uses: pre-commit/action@v3.0.1
84
- with:
85
- extra_args: yamlfmt --all-files
86
-
87
- - name: cspell
88
- if: success() || failure()
89
- uses: pre-commit/action@v3.0.1
90
- with:
91
- extra_args: cspell --all-files
92
-
93
- # ---------------------------------------------------------------------------
94
- # Single matrix job — install once, then run pytest + docs + mypy
95
- # ---------------------------------------------------------------------------
96
- test:
97
- runs-on: ubuntu-latest
98
- strategy:
99
- fail-fast: false
100
- matrix:
101
- python-version: ["3.11", "3.12", "3.13"]
102
- steps:
103
- - uses: actions/checkout@v4
104
-
105
- - uses: actions/setup-python@v5
106
- with:
107
- python-version: ${{ matrix.python-version }}
108
-
109
- - uses: astral-sh/setup-uv@v6
110
-
111
- - name: Install package with all extras
112
- run: uv pip install -e .[doc,lint,test] pytest mypy
113
-
114
- - name: Run pytest
115
- run: python -m pytest
116
-
117
- - name: Run mypy
118
- if: (success() || failure()) && matrix.python-version == '3.13'
119
- run: mypy ./src
@@ -1,106 +0,0 @@
1
- name: Publish to PyPI
2
-
3
- on:
4
- release:
5
- types: [published]
6
-
7
- # Allow manual trigger for testing the workflow
8
- workflow_dispatch:
9
-
10
- permissions:
11
- contents: read
12
- id-token: write
13
-
14
- concurrency:
15
- group: ${{ github.workflow }}-${{ github.ref }}
16
- cancel-in-progress: true
17
-
18
- env:
19
- UV_SYSTEM_PYTHON: true
20
-
21
- jobs:
22
- # ---------------------------------------------------------------------------
23
- # Build sdist and wheel
24
- # ---------------------------------------------------------------------------
25
- build:
26
- runs-on: ubuntu-latest
27
- steps:
28
- - uses: actions/checkout@v4
29
- with:
30
- fetch-depth: 0 # make poetry dynamic versioning actually see our git tags
31
-
32
- - uses: actions/setup-python@v5
33
- with:
34
- python-version: "3.13"
35
-
36
- - uses: astral-sh/setup-uv@v6
37
-
38
- - name: Install build tools
39
- run: uv pip install build
40
-
41
- - name: Build sdist and wheel
42
- run: python -m build
43
-
44
- - name: List built artifacts
45
- run: ls -lh dist/
46
-
47
- - name: Upload build artifacts
48
- uses: actions/upload-artifact@v4
49
- with:
50
- name: dist
51
- path: dist/
52
- if-no-files-found: error
53
-
54
- # ---------------------------------------------------------------------------
55
- # Run the test suite against the built wheel (not the source tree)
56
- # ---------------------------------------------------------------------------
57
- test-built-package:
58
- needs: build
59
- runs-on: ${{ matrix.os }}
60
- strategy:
61
- fail-fast: false
62
- matrix:
63
- os: [ubuntu-latest, macos-latest, windows-latest]
64
- python-version: ["3.11", "3.12", "3.13"]
65
- steps:
66
- - uses: actions/checkout@v4
67
-
68
- - uses: actions/setup-python@v5
69
- with:
70
- python-version: ${{ matrix.python-version }}
71
-
72
- - uses: astral-sh/setup-uv@v6
73
-
74
- - name: Download build artifacts
75
- uses: actions/download-artifact@v4
76
- with:
77
- name: dist
78
- path: dist/
79
-
80
- - name: Install wheel and test dependencies
81
- shell: bash
82
- run: |
83
- uv pip install dist/*.whl
84
- uv pip install pytest pytest-cov pytest-xdist pydantic
85
-
86
- - name: Run tests
87
- run: python -m pytest tests/ -v
88
-
89
- # ---------------------------------------------------------------------------
90
- # Publish to PyPI
91
- # ---------------------------------------------------------------------------
92
- publish-pypi:
93
- needs: [build, test-built-package]
94
- runs-on: ubuntu-latest
95
- #if: github.event_name == 'release'
96
- steps:
97
- - name: Download build artifacts
98
- uses: actions/download-artifact@v4
99
- with:
100
- name: dist
101
- path: dist/
102
-
103
- - name: Publish to PyPI
104
- uses: pypa/gh-action-pypi-publish@release/v1
105
- with:
106
- password: ${{ secrets.PYPI_TOKEN }}
@@ -1,92 +0,0 @@
1
- Major New Functionality:
2
- - title: "Add standard top level and installation files"
3
- description: |
4
- Standard README, release notes for initial release, and pyproject.toml
5
- installation specifications.
6
- files:
7
- added:
8
- - "README.md"
9
- - "docs/source/releases/latest/initial-commit.yaml"
10
- - "pyproject.toml"
11
- - "tests/scripts/test_config.yaml"
12
- deleted:
13
- - ""
14
- modified:
15
- - ""
16
- moved:
17
- - ""
18
- related-issue:
19
- number: 0
20
- repo_url: "https://github.com/NRLMMD-GEOIPS/geoips"
21
- - title: "Add initial functionality"
22
- description: |
23
- Create one or more release note sections here to enumerate initial functionality.
24
-
25
- * @functionality 1 description
26
- * @functionality 2 description
27
- files:
28
- added:
29
- - "@package@/plugins/modules/readers/@my_reader@"
30
- - "@package@/plugins/modules/@module_type@/@my_module@"
31
- deleted:
32
- - ""
33
- modified:
34
- - ""
35
- moved:
36
- - ""
37
- related-issue:
38
- number: 0
39
- repo_url: "https://github.com/NRLMMD-GEOIPS/geoips"
40
- Testing Updates:
41
- - title: "Add standard test scripts"
42
- description: |
43
- Include:
44
-
45
- * complete test script for full package integration tests.
46
- * Direct single source test calls.
47
- * Complete functionality integration test.
48
- * YAML procflow config to produce all available products.
49
-
50
- * @product1 test description@
51
- * @product2 test description@
52
- files:
53
- added:
54
- - "tests/test_all.sh"
55
- - "@tests/scripts/@mydatatype@.tc.@product@.imagery_clean.sh@"
56
- - "tests/scripts/test_config.sh"
57
- - "tests/scripts/test_config.yaml"
58
- deleted:
59
- - ""
60
- modified:
61
- - ""
62
- moved:
63
- - ""
64
- related-issue:
65
- number: 0
66
- repo_url: "https://github.com/NRLMMD-GEOIPS/geoips"
67
- Release Updates:
68
- - title: "Versions including updates to template_basic_plugin repo"
69
- description: |
70
- To ensure release note is updated with each release, and to track which versions
71
- actually resulted in updates on template_basic_plugin, always add the currently
72
- tagged version to this list.
73
-
74
- This "Release Updates" section can be removed for your actual release notes
75
- section, this is specifically for the template_basic_plugin repo itself.
76
- files:
77
- added:
78
- - 1.14.0
79
- - 1.14.1
80
- - 1.14.2
81
- - 1.14.3
82
- - 1.14.4
83
- - 1.14.5
84
- - 1.15.1
85
- - 1.15.2
86
- - 1.15.3
87
- - 1.16.0
88
- - 1.16.2
89
- - 1.16.3
90
- - 1.17.0
91
- - 1.17.1
92
- - 1.17.2
File without changes