pluginify 1.0.0__tar.gz → 1.0.0.post16.dev0__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.
- pluginify-1.0.0.post16.dev0/.github/workflows/integ_test.yaml +25 -0
- pluginify-1.0.0.post16.dev0/.github/workflows/mypy.yaml +39 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/.github/workflows/status-check.yaml +2 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/PKG-INFO +2 -1
- pluginify-1.0.0.post16.dev0/docs/source/releases/latest/atomic-registry-writes.yaml +22 -0
- pluginify-1.0.0.post16.dev0/docs/source/releases/latest/fix-concurrent-writes.yaml +16 -0
- pluginify-1.0.0.post16.dev0/docs/source/releases/latest/ignore-files-in-utils-directories.yaml +17 -0
- pluginify-1.0.0.post16.dev0/docs/source/releases/latest/use-geoips-ci.yaml +32 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pluginify/_version.py +2 -2
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pluginify/create_plugin_registries.py +36 -7
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pyproject.toml +1 -1
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/tests/unit_tests/plugin_registries/test_plugin_registries.py +29 -0
- pluginify-1.0.0/.github/workflows/code-quality.yaml +0 -87
- pluginify-1.0.0/.github/workflows/generate-badges.yaml +0 -216
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/.github/workflows/deploy-docs.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/.github/workflows/package-and-publish.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/.github/workflows/tag-and-release.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/LICENSE +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/README.md +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/docs/source/releases/1.0.0/1.0.0-no-bug-fixes-required-on-this-release.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/docs/source/releases/1.0.0/1.19.0-internal-release.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/docs/source/releases/1.0.0/1.19.0-open-source-upload.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/docs/source/releases/1.0.0/1.19.0-patch-internal-use-vars-runner.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/docs/source/releases/1.0.0/ci-fix-perms.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/docs/source/releases/1.0.0/copy-geoips-functionality.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/docs/source/releases/1.0.0/ignore-dot-files-and-dirs.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/docs/source/releases/1.0.0/module-to-class-updates.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/docs/source/releases/1.0.0/obp-plugin-registry-updates.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/docs/source/releases/1.0.0/pluginify-updates-jeremy-comments.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/docs/source/releases/1.0.0/pypi-publish-bug-fix.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/docs/source/releases/1.0.0/remove-all-geoips-references.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/docs/source/releases/1.0.0/replace-geoips-functionality.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/docs/source/releases/1.0.0/update-black-formatting.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/docs/source/releases/1.0.0/version-update.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pluginify/__init__.py +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pluginify/commandline_typer.py +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pluginify/config.py +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pluginify/errors.py +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pluginify/interfaces/__init__.py +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pluginify/interfaces/base.py +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pluginify/interfaces/class_based/data_modifiers.py +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pluginify/interfaces/class_based_plugin.py +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pluginify/interfaces/yaml_based/configs.py +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pluginify/plugin_registry.py +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pluginify/plugins/classes/data_modifiers/cuboid.py +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pluginify/plugins/yaml/configs/stucco.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pluginify/pydantic_models/v1/configs.py +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pluginify/utils/__init__.py +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pluginify/utils/context_managers.py +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pluginify/utils/validators.py +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/tests/conftest.py +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/tests/unit_tests/config/test_config.py +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/tests/unit_tests/plugin_registries/files/bad/invalid_interfaces.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/tests/unit_tests/plugin_registries/files/bad/missing_lowest_keys.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/tests/unit_tests/plugin_registries/files/bad/missing_plugin_types.yaml +0 -0
- {pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/tests/unit_tests/plugin_registries/files/good/pluginify.yaml +0 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: Integration tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened, synchronize, reopened, ready_for_review]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: integ-test-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
integ-test:
|
|
14
|
+
if: github.event_name == 'workflow_dispatch' || github.event.pull_request.draft == false
|
|
15
|
+
uses: NRLMMD-GEOIPS/geoips_ci/.github/workflows/reusable-ci.yaml
|
|
16
|
+
# reusable-ci's job requests these; a called workflow cannot exceed the caller.
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
packages: write
|
|
20
|
+
with:
|
|
21
|
+
geoips_image: "ghcr.io/nrlmmd-geoips/geoips:latest"
|
|
22
|
+
run_core_tests: true
|
|
23
|
+
secrets:
|
|
24
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
25
|
+
docker_token: ${{ secrets.DOCKER_TOKEN }}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: mypy
|
|
2
|
+
|
|
3
|
+
# Lint, unit tests and the geoips unit tests are in integ_test.yaml (geoips_ci's
|
|
4
|
+
# reusable-ci). It does not type check, so mypy stays here.
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches: [main]
|
|
9
|
+
pull_request:
|
|
10
|
+
branches: [main]
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
concurrency:
|
|
16
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
17
|
+
cancel-in-progress: true
|
|
18
|
+
|
|
19
|
+
env:
|
|
20
|
+
UV_SYSTEM_PYTHON: true
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
mypy:
|
|
24
|
+
continue-on-error: true
|
|
25
|
+
runs-on: ${{ vars.RUNNER }}
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
28
|
+
|
|
29
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
30
|
+
with:
|
|
31
|
+
python-version: "3.13"
|
|
32
|
+
|
|
33
|
+
- uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
|
|
34
|
+
|
|
35
|
+
- name: Install package
|
|
36
|
+
run: uv pip install -e ".[doc]" mypy
|
|
37
|
+
|
|
38
|
+
- name: Run mypy
|
|
39
|
+
run: mypy ./pluginify
|
|
@@ -2,6 +2,7 @@ name: Require up-to-date branch
|
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
pull_request:
|
|
5
|
+
types: [opened, synchronize, reopened, ready_for_review]
|
|
5
6
|
push:
|
|
6
7
|
branches:
|
|
7
8
|
- main
|
|
@@ -11,6 +12,7 @@ permissions:
|
|
|
11
12
|
|
|
12
13
|
jobs:
|
|
13
14
|
status-check:
|
|
15
|
+
if: github.event_name == 'push' || github.event.pull_request.draft == false
|
|
14
16
|
runs-on: ${{ vars.RUNNER }}
|
|
15
17
|
steps:
|
|
16
18
|
- name: No-op status check
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pluginify
|
|
3
|
-
Version: 1.0.0
|
|
3
|
+
Version: 1.0.0.post16.dev0
|
|
4
4
|
Summary: Pluginify package
|
|
5
5
|
License: LICENSE
|
|
6
6
|
License-File: LICENSE
|
|
@@ -12,6 +12,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.12
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.13
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
15
16
|
Provides-Extra: doc
|
|
16
17
|
Requires-Dist: docstring_parser
|
|
17
18
|
Requires-Dist: jsonschema (>4.18.0)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
bug fix:
|
|
2
|
+
- title: 'Write plugin registries atomically'
|
|
3
|
+
description: |
|
|
4
|
+
Plugin registries were rewritten in place, so another process reading a
|
|
5
|
+
registry at the same time (for example parallel pytest-xdist workers, one of
|
|
6
|
+
them rebuilding the registries) could read an empty or partial file and fail
|
|
7
|
+
with ``JSONDecodeError``. Registries are now written to a temporary file in
|
|
8
|
+
the same directory and moved into place with ``os.replace``.
|
|
9
|
+
files:
|
|
10
|
+
deleted:
|
|
11
|
+
- ''
|
|
12
|
+
modified:
|
|
13
|
+
- 'pluginify/create_plugin_registries.py'
|
|
14
|
+
- 'tests/unit_tests/plugin_registries/test_plugin_registries.py'
|
|
15
|
+
added:
|
|
16
|
+
- ''
|
|
17
|
+
related-issue:
|
|
18
|
+
number: null
|
|
19
|
+
repo_url: 'https://github.com/NRLMMD-GEOIPS/pluginify'
|
|
20
|
+
date:
|
|
21
|
+
start: 2026-10-01
|
|
22
|
+
finish: 2026-10-01
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
bug fix:
|
|
2
|
+
- title: "Use NamedTemporaryFile for safer writes"
|
|
3
|
+
description: |
|
|
4
|
+
Plugin registry temp files were still having conflicts when
|
|
5
|
+
written by threads in the same process. To fix this I switched
|
|
6
|
+
to using tempfile.NamedTemporaryFile which is guaranteed to
|
|
7
|
+
avoid conflicts.
|
|
8
|
+
files:
|
|
9
|
+
modified:
|
|
10
|
+
- pluginfiy/create_plugin_registries.py
|
|
11
|
+
related-issue:
|
|
12
|
+
number: null
|
|
13
|
+
repo_url: ''
|
|
14
|
+
date:
|
|
15
|
+
start: 2026-10-30
|
|
16
|
+
finish: 2026-10-30
|
pluginify-1.0.0.post16.dev0/docs/source/releases/latest/ignore-files-in-utils-directories.yaml
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
bug fix:
|
|
2
|
+
- title: 'Force ignore files in directories named */utils/'
|
|
3
|
+
description: 'Force ignore files in directories named */utils/'
|
|
4
|
+
files:
|
|
5
|
+
deleted:
|
|
6
|
+
- ''
|
|
7
|
+
modified:
|
|
8
|
+
- 'pluginify/create_plugin_registries.py'
|
|
9
|
+
- 'tests/unit_tests/plugin_registries/test_plugin_registries.py'
|
|
10
|
+
added:
|
|
11
|
+
- ''
|
|
12
|
+
related-issue:
|
|
13
|
+
number: null
|
|
14
|
+
repo_url: ''
|
|
15
|
+
date:
|
|
16
|
+
start: 2026-07-12
|
|
17
|
+
finish: 2026-07-12
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
continuous integration:
|
|
2
|
+
- title: 'Use the standard GeoIPS CI from geoips_ci'
|
|
3
|
+
description: |
|
|
4
|
+
Run geoips_ci's reusable-ci on pull requests, like geoips and the plugin
|
|
5
|
+
repositories: geoips' lint (flake8, black, bandit), pluginify's unit tests, and
|
|
6
|
+
geoips' unit tests against the pluginify branch, in the geoips:latest image.
|
|
7
|
+
Remove the code-quality and nightly badge workflows and the unused badges; mypy
|
|
8
|
+
keeps its own workflow, since reusable-ci does not type check. Skip draft pull
|
|
9
|
+
requests in the status check, like geoips.
|
|
10
|
+
files:
|
|
11
|
+
deleted:
|
|
12
|
+
- '.github/badges/coverage-badge.svg'
|
|
13
|
+
- '.github/badges/cspell-badge.svg'
|
|
14
|
+
- '.github/badges/install-badge.svg'
|
|
15
|
+
- '.github/badges/mypy-badge.svg'
|
|
16
|
+
- '.github/badges/ruff-badge.svg'
|
|
17
|
+
- '.github/badges/tests-badge.svg'
|
|
18
|
+
- '.github/workflows/code-quality.yaml'
|
|
19
|
+
- '.github/workflows/generate-badges.yaml'
|
|
20
|
+
modified:
|
|
21
|
+
- '.github/workflows/status-check.yaml'
|
|
22
|
+
- 'docs/source/releases/latest/ignore-files-in-utils-directories.yaml'
|
|
23
|
+
added:
|
|
24
|
+
- '.github/workflows/integ_test.yaml'
|
|
25
|
+
- '.github/workflows/mypy.yaml'
|
|
26
|
+
- 'docs/source/releases/latest/use-geoips-ci.yaml'
|
|
27
|
+
related-issue:
|
|
28
|
+
number: null
|
|
29
|
+
repo_url: ''
|
|
30
|
+
date:
|
|
31
|
+
start: 2026-10-20
|
|
32
|
+
finish: 2026-10-20
|
|
@@ -17,7 +17,7 @@ import logging
|
|
|
17
17
|
from importlib import metadata, resources, util, import_module
|
|
18
18
|
from inspect import signature
|
|
19
19
|
import json
|
|
20
|
-
from os import makedirs, remove
|
|
20
|
+
from os import makedirs, remove, replace
|
|
21
21
|
from os.path import (
|
|
22
22
|
basename,
|
|
23
23
|
dirname,
|
|
@@ -29,6 +29,7 @@ from os.path import (
|
|
|
29
29
|
)
|
|
30
30
|
from pathlib import Path
|
|
31
31
|
import re
|
|
32
|
+
import tempfile
|
|
32
33
|
import warnings
|
|
33
34
|
|
|
34
35
|
import yaml
|
|
@@ -317,14 +318,33 @@ def write_registered_plugins(pkg_dir, plugins, save_type):
|
|
|
317
318
|
"""
|
|
318
319
|
if save_type == "yaml":
|
|
319
320
|
reg_plug_abspath = os_join(pkg_dir, "registered_plugins.yaml")
|
|
320
|
-
with open(reg_plug_abspath, "w") as plugin_registry:
|
|
321
|
-
LOG.info("Writing %s", reg_plug_abspath)
|
|
322
|
-
yaml.safe_dump(plugins, plugin_registry, default_flow_style=False)
|
|
323
321
|
else:
|
|
324
322
|
reg_plug_abspath = os_join(pkg_dir, "registered_plugins.json")
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
323
|
+
LOG.info("Writing %s", reg_plug_abspath)
|
|
324
|
+
# Write to a temporary file and move it into place, so that other processes
|
|
325
|
+
# reading the registry (for example parallel test workers) never see a
|
|
326
|
+
# partially written file.
|
|
327
|
+
tmp_abspath = None
|
|
328
|
+
try:
|
|
329
|
+
with tempfile.NamedTemporaryFile(
|
|
330
|
+
mode="w",
|
|
331
|
+
dir=dirname(reg_plug_abspath),
|
|
332
|
+
suffix=".tmp",
|
|
333
|
+
delete=False,
|
|
334
|
+
) as plugin_registry:
|
|
335
|
+
tmp_abspath = plugin_registry.name
|
|
336
|
+
if save_type == "yaml":
|
|
337
|
+
yaml.safe_dump(plugins, plugin_registry, default_flow_style=False)
|
|
338
|
+
else:
|
|
339
|
+
json.dump(plugins, plugin_registry, indent=4)
|
|
340
|
+
|
|
341
|
+
replace(tmp_abspath, reg_plug_abspath)
|
|
342
|
+
finally:
|
|
343
|
+
if tmp_abspath is not None:
|
|
344
|
+
try:
|
|
345
|
+
remove(tmp_abspath)
|
|
346
|
+
except FileNotFoundError:
|
|
347
|
+
pass
|
|
328
348
|
|
|
329
349
|
|
|
330
350
|
def create_plugin_registries(plugin_packages, save_type, namespace):
|
|
@@ -934,6 +954,15 @@ def add_class_plugin(package, relpath, plugins):
|
|
|
934
954
|
# __version.py, etc.
|
|
935
955
|
return error_message
|
|
936
956
|
|
|
957
|
+
if "utils" in Path(relpath).parts:
|
|
958
|
+
# Ignore helper modules that live under plugin trees. These files are not
|
|
959
|
+
# plugins and should not be imported or validated for PLUGIN_CLASS.
|
|
960
|
+
LOG.info(
|
|
961
|
+
f"Skipping module at relpath {relpath} from {package}, "
|
|
962
|
+
"found under a utils directory"
|
|
963
|
+
)
|
|
964
|
+
return error_message
|
|
965
|
+
|
|
937
966
|
module_name = splitext(basename(relpath))[0]
|
|
938
967
|
# We need the full path to the module in order
|
|
939
968
|
# for relative imports to work within modules.
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
"""TestPluginRegistry Class used for Unit Testing the Plugin Registries."""
|
|
5
5
|
|
|
6
6
|
from glob import glob
|
|
7
|
+
import json
|
|
7
8
|
import logging
|
|
8
9
|
from os.path import basename, splitext
|
|
9
10
|
|
|
@@ -11,6 +12,10 @@ import pytest
|
|
|
11
12
|
import yaml
|
|
12
13
|
|
|
13
14
|
from pluginify.errors import PluginError, PluginRegistryError
|
|
15
|
+
from pluginify.create_plugin_registries import (
|
|
16
|
+
add_class_plugin,
|
|
17
|
+
write_registered_plugins,
|
|
18
|
+
)
|
|
14
19
|
from pluginify.interfaces import configs
|
|
15
20
|
from pluginify.interfaces import data_modifiers
|
|
16
21
|
from pluginify.utils.validators import PluginRegistryValidator
|
|
@@ -18,6 +23,21 @@ from pluginify.utils.validators import PluginRegistryValidator
|
|
|
18
23
|
LOG = logging.getLogger(__name__)
|
|
19
24
|
|
|
20
25
|
|
|
26
|
+
@pytest.mark.parametrize("save_type", ["json", "yaml"])
|
|
27
|
+
def test_write_registered_plugins_replaces_file(tmp_path, save_type):
|
|
28
|
+
"""Write a registry over an existing one, leaving no temporary files behind."""
|
|
29
|
+
reg_path = tmp_path / f"registered_plugins.{save_type}"
|
|
30
|
+
reg_path.write_text("old")
|
|
31
|
+
plugins = {"algorithms": {"fake_plugin": {"package": "fake"}}}
|
|
32
|
+
|
|
33
|
+
write_registered_plugins(str(tmp_path), plugins, save_type)
|
|
34
|
+
|
|
35
|
+
with open(reg_path) as fo:
|
|
36
|
+
written = json.load(fo) if save_type == "json" else yaml.safe_load(fo)
|
|
37
|
+
assert written == plugins
|
|
38
|
+
assert [p.name for p in tmp_path.iterdir()] == [reg_path.name]
|
|
39
|
+
|
|
40
|
+
|
|
21
41
|
class FakeInterface:
|
|
22
42
|
"""Dummy fake interface used to cause appropriate errors from the PluginRegistry."""
|
|
23
43
|
|
|
@@ -124,6 +144,15 @@ class TestPluginRegistry:
|
|
|
124
144
|
)
|
|
125
145
|
assert self.real_reg_validator.registered_plugins
|
|
126
146
|
|
|
147
|
+
def test_utils_modules_are_skipped(self):
|
|
148
|
+
"""Ensure utility modules under plugin trees are not registered as plugins."""
|
|
149
|
+
plugins = {}
|
|
150
|
+
error_message = add_class_plugin(
|
|
151
|
+
"pluginify", "plugins/classes/data_modifiers/utils/helper.py", plugins
|
|
152
|
+
)
|
|
153
|
+
assert error_message == ""
|
|
154
|
+
assert plugins == {}
|
|
155
|
+
|
|
127
156
|
def test_disabled_registry_creation(self):
|
|
128
157
|
"""Assert that the registries are not automatically rebuilt.
|
|
129
158
|
|
|
@@ -1,87 +0,0 @@
|
|
|
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
|
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
name: Nightly Badge Generation
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
schedule:
|
|
5
|
-
- cron: '0 2 * * *'
|
|
6
|
-
workflow_dispatch:
|
|
7
|
-
|
|
8
|
-
permissions:
|
|
9
|
-
contents: write
|
|
10
|
-
|
|
11
|
-
concurrency:
|
|
12
|
-
group: ${{ github.workflow }}-${{ github.ref }}
|
|
13
|
-
cancel-in-progress: true
|
|
14
|
-
|
|
15
|
-
env:
|
|
16
|
-
UV_SYSTEM_PYTHON: true
|
|
17
|
-
|
|
18
|
-
jobs:
|
|
19
|
-
check-commits:
|
|
20
|
-
runs-on: ${{ vars.RUNNER }}
|
|
21
|
-
outputs:
|
|
22
|
-
has_new_commits: ${{ steps.check.outputs.has_new_commits }}
|
|
23
|
-
steps:
|
|
24
|
-
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
25
|
-
with:
|
|
26
|
-
fetch-depth: 0
|
|
27
|
-
|
|
28
|
-
- name: Check for new commits in last 24 hours
|
|
29
|
-
id: check
|
|
30
|
-
run: |
|
|
31
|
-
COMMITS=$(git log --oneline --since="25 hours ago" --no-merges | grep -c -v "\[skip ci\]")
|
|
32
|
-
if [ "$COMMITS" -gt 0 ]; then
|
|
33
|
-
echo "has_new_commits=true" >> "$GITHUB_OUTPUT"
|
|
34
|
-
echo "Found $COMMITS new commits in the last 25 hours"
|
|
35
|
-
else
|
|
36
|
-
echo "has_new_commits=false" >> "$GITHUB_OUTPUT"
|
|
37
|
-
echo "No new commits in the last 25 hours"
|
|
38
|
-
fi
|
|
39
|
-
|
|
40
|
-
generate-badges:
|
|
41
|
-
needs: check-commits
|
|
42
|
-
if: needs.check-commits.outputs.has_new_commits == 'true'
|
|
43
|
-
runs-on: ${{ vars.RUNNER }}
|
|
44
|
-
|
|
45
|
-
steps:
|
|
46
|
-
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
47
|
-
with:
|
|
48
|
-
fetch-depth: 0
|
|
49
|
-
|
|
50
|
-
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
51
|
-
with:
|
|
52
|
-
python-version: "3.13"
|
|
53
|
-
|
|
54
|
-
- uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
|
|
55
|
-
|
|
56
|
-
- name: Install dependencies
|
|
57
|
-
run: |
|
|
58
|
-
uv pip install -e ".[doc,lint,test]"
|
|
59
|
-
uv pip install pytest mypy ruff commitizen coverage "genbadge[all]"
|
|
60
|
-
|
|
61
|
-
- name: Create directories
|
|
62
|
-
run: |
|
|
63
|
-
mkdir -p .github/badges
|
|
64
|
-
mkdir -p reports
|
|
65
|
-
|
|
66
|
-
- name: Run pytest with coverage
|
|
67
|
-
id: pytest
|
|
68
|
-
continue-on-error: true
|
|
69
|
-
run: coverage run -m pytest --junitxml=reports/junit.xml
|
|
70
|
-
|
|
71
|
-
- name: Generate pytest badge
|
|
72
|
-
run: |
|
|
73
|
-
if [ -f reports/junit.xml ]; then
|
|
74
|
-
genbadge tests -i reports/junit.xml -o .github/badges/tests-badge.svg -n "tests"
|
|
75
|
-
else
|
|
76
|
-
python -c "
|
|
77
|
-
from genbadge import Badge
|
|
78
|
-
b = Badge(left_txt='tests', right_txt='error', color='red')
|
|
79
|
-
b.write_to('.github/badges/tests-badge.svg', use_shields=False)
|
|
80
|
-
"
|
|
81
|
-
fi
|
|
82
|
-
|
|
83
|
-
- name: Generate coverage badge
|
|
84
|
-
run: |
|
|
85
|
-
if [ -f coverage.xml ]; then
|
|
86
|
-
genbadge coverage -i coverage.xml -o .github/badges/coverage-badge.svg -n "coverage"
|
|
87
|
-
else
|
|
88
|
-
python -c "
|
|
89
|
-
from genbadge import Badge
|
|
90
|
-
b = Badge(left_txt='coverage', right_txt='error', color='red')
|
|
91
|
-
b.write_to('.github/badges/coverage-badge.svg', use_shields=False)
|
|
92
|
-
"
|
|
93
|
-
fi
|
|
94
|
-
|
|
95
|
-
- name: Run mypy
|
|
96
|
-
id: mypy
|
|
97
|
-
continue-on-error: true
|
|
98
|
-
run: mypy ./pluginify --junit-xml reports/mypy.xml || true
|
|
99
|
-
|
|
100
|
-
- name: Generate mypy badge
|
|
101
|
-
run: |
|
|
102
|
-
if [ -f reports/mypy.xml ]; then
|
|
103
|
-
genbadge tests -i reports/mypy.xml -o .github/badges/mypy-badge.svg -n "mypy"
|
|
104
|
-
else
|
|
105
|
-
python -c "
|
|
106
|
-
from genbadge import Badge
|
|
107
|
-
b = Badge(left_txt='mypy', right_txt='passing', color='brightgreen')
|
|
108
|
-
b.write_to('.github/badges/mypy-badge.svg', use_shields=False)
|
|
109
|
-
"
|
|
110
|
-
fi
|
|
111
|
-
|
|
112
|
-
- name: Run ruff
|
|
113
|
-
id: ruff
|
|
114
|
-
continue-on-error: true
|
|
115
|
-
run: ruff check ./pluginify --output-format=junit -o reports/ruff.xml || true
|
|
116
|
-
|
|
117
|
-
- name: Generate ruff badge
|
|
118
|
-
run: |
|
|
119
|
-
if [ -f reports/ruff.xml ] && [ -s reports/ruff.xml ]; then
|
|
120
|
-
if grep -q "<testcase" reports/ruff.xml; then
|
|
121
|
-
genbadge tests -i reports/ruff.xml -o .github/badges/ruff-badge.svg -n "ruff"
|
|
122
|
-
else
|
|
123
|
-
python -c "
|
|
124
|
-
from genbadge import Badge
|
|
125
|
-
b = Badge(left_txt='ruff', right_txt='passing', color='brightgreen')
|
|
126
|
-
b.write_to('.github/badges/ruff-badge.svg', use_shields=False)
|
|
127
|
-
"
|
|
128
|
-
fi
|
|
129
|
-
else
|
|
130
|
-
python -c "
|
|
131
|
-
from genbadge import Badge
|
|
132
|
-
b = Badge(left_txt='ruff', right_txt='passing', color='brightgreen')
|
|
133
|
-
b.write_to('.github/badges/ruff-badge.svg', use_shields=False)
|
|
134
|
-
"
|
|
135
|
-
fi
|
|
136
|
-
|
|
137
|
-
- name: Test install
|
|
138
|
-
id: install
|
|
139
|
-
continue-on-error: true
|
|
140
|
-
run: uv pip install -e . --reinstall
|
|
141
|
-
|
|
142
|
-
- name: Generate install badge
|
|
143
|
-
run: |
|
|
144
|
-
if [ "${{ steps.install.outcome }}" == "success" ]; then
|
|
145
|
-
python -c "
|
|
146
|
-
from genbadge import Badge
|
|
147
|
-
b = Badge(left_txt='install', right_txt='passing', color='brightgreen')
|
|
148
|
-
b.write_to('.github/badges/install-badge.svg', use_shields=False)
|
|
149
|
-
"
|
|
150
|
-
else
|
|
151
|
-
python -c "
|
|
152
|
-
from genbadge import Badge
|
|
153
|
-
b = Badge(left_txt='install', right_txt='failing', color='red')
|
|
154
|
-
b.write_to('.github/badges/install-badge.svg', use_shields=False)
|
|
155
|
-
"
|
|
156
|
-
fi
|
|
157
|
-
|
|
158
|
-
- name: Check commitizen
|
|
159
|
-
id: commitizen
|
|
160
|
-
continue-on-error: true
|
|
161
|
-
env:
|
|
162
|
-
COMMITIZEN_START_REV: "9d83e6984277ccbe6c5f6713f65b75a90e7c7e40"
|
|
163
|
-
run: cz check --rev-range ${{ env.COMMITIZEN_START_REV }}..HEAD
|
|
164
|
-
|
|
165
|
-
- name: Generate commitizen badge
|
|
166
|
-
run: |
|
|
167
|
-
if [ "${{ steps.commitizen.outcome }}" == "success" ]; then
|
|
168
|
-
python -c "
|
|
169
|
-
from genbadge import Badge
|
|
170
|
-
b = Badge(left_txt='commitizen', right_txt='passing', color='brightgreen')
|
|
171
|
-
b.write_to('.github/badges/commitizen-badge.svg', use_shields=False)
|
|
172
|
-
"
|
|
173
|
-
else
|
|
174
|
-
python -c "
|
|
175
|
-
from genbadge import Badge
|
|
176
|
-
b = Badge(left_txt='commitizen', right_txt='failing', color='red')
|
|
177
|
-
b.write_to('.github/badges/commitizen-badge.svg', use_shields=False)
|
|
178
|
-
"
|
|
179
|
-
fi
|
|
180
|
-
|
|
181
|
-
- name: Check for badge changes
|
|
182
|
-
id: badge_changes
|
|
183
|
-
run: |
|
|
184
|
-
git add .github/badges/*.svg
|
|
185
|
-
if git diff --cached --quiet; then
|
|
186
|
-
echo "has_changes=false" >> "$GITHUB_OUTPUT"
|
|
187
|
-
echo "No badge changes detected"
|
|
188
|
-
else
|
|
189
|
-
echo "has_changes=true" >> "$GITHUB_OUTPUT"
|
|
190
|
-
echo "Badge changes detected:"
|
|
191
|
-
git diff --cached --name-status .github/badges/
|
|
192
|
-
fi
|
|
193
|
-
|
|
194
|
-
- name: Commit and push badges
|
|
195
|
-
if: steps.badge_changes.outputs.has_changes == 'true'
|
|
196
|
-
run: |
|
|
197
|
-
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
|
198
|
-
git config --local user.name "github-actions[bot]"
|
|
199
|
-
git commit -m "chore: update badges [skip ci]"
|
|
200
|
-
git push
|
|
201
|
-
|
|
202
|
-
- name: Generate summary
|
|
203
|
-
run: |
|
|
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"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/docs/source/releases/1.0.0/ci-fix-perms.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/docs/source/releases/1.0.0/pypi-publish-bug-fix.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/docs/source/releases/1.0.0/version-update.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pluginify/interfaces/class_based/data_modifiers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pluginify-1.0.0 → pluginify-1.0.0.post16.dev0}/pluginify/plugins/classes/data_modifiers/cuboid.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|