pluginify 0.1.0__tar.gz → 1.19.0a0__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 (44) hide show
  1. {pluginify-0.1.0 → pluginify-1.19.0a0}/PKG-INFO +1 -1
  2. pluginify-1.19.0a0/docs/source/releases/latest/ignore-dot-files-and-dirs.yaml +17 -0
  3. pluginify-1.19.0a0/docs/source/releases/latest/obp-plugin-registry-updates.yaml +18 -0
  4. {pluginify-0.1.0 → pluginify-1.19.0a0}/pluginify/_version.py +2 -2
  5. {pluginify-0.1.0 → pluginify-1.19.0a0}/pluginify/create_plugin_registries.py +8 -0
  6. {pluginify-0.1.0 → pluginify-1.19.0a0}/pluginify/plugin_registry.py +77 -9
  7. {pluginify-0.1.0 → pluginify-1.19.0a0}/pyproject.toml +1 -1
  8. {pluginify-0.1.0 → pluginify-1.19.0a0}/.github/workflows/generate-badges.yaml +0 -0
  9. {pluginify-0.1.0 → pluginify-1.19.0a0}/.github/workflows/lint-and-test.yaml +0 -0
  10. {pluginify-0.1.0 → pluginify-1.19.0a0}/.github/workflows/package-and-publish.yaml +0 -0
  11. {pluginify-0.1.0 → pluginify-1.19.0a0}/.github/workflows/status-check.yaml +0 -0
  12. {pluginify-0.1.0 → pluginify-1.19.0a0}/LICENSE +0 -0
  13. {pluginify-0.1.0 → pluginify-1.19.0a0}/README.md +0 -0
  14. {pluginify-0.1.0 → pluginify-1.19.0a0}/docs/source/releases/latest/ci-fix-perms.yaml +0 -0
  15. {pluginify-0.1.0 → pluginify-1.19.0a0}/docs/source/releases/latest/copy-geoips-functionality.yaml +0 -0
  16. {pluginify-0.1.0 → pluginify-1.19.0a0}/docs/source/releases/latest/initial-commit.yaml +0 -0
  17. {pluginify-0.1.0 → pluginify-1.19.0a0}/docs/source/releases/latest/pluginify-updates-jeremy-comments.yaml +0 -0
  18. {pluginify-0.1.0 → pluginify-1.19.0a0}/docs/source/releases/latest/pypi-publish-bug-fix.yaml +0 -0
  19. {pluginify-0.1.0 → pluginify-1.19.0a0}/docs/source/releases/latest/remove-all-geoips-references.yaml +0 -0
  20. {pluginify-0.1.0 → pluginify-1.19.0a0}/docs/source/releases/latest/replace-geoips-functionality.yaml +0 -0
  21. {pluginify-0.1.0 → pluginify-1.19.0a0}/docs/source/releases/latest/update-black-formatting.yaml +0 -0
  22. {pluginify-0.1.0 → pluginify-1.19.0a0}/docs/source/releases/latest/version-update.yaml +0 -0
  23. {pluginify-0.1.0 → pluginify-1.19.0a0}/pluginify/__init__.py +0 -0
  24. {pluginify-0.1.0 → pluginify-1.19.0a0}/pluginify/commandline_typer.py +0 -0
  25. {pluginify-0.1.0 → pluginify-1.19.0a0}/pluginify/config.py +0 -0
  26. {pluginify-0.1.0 → pluginify-1.19.0a0}/pluginify/errors.py +0 -0
  27. {pluginify-0.1.0 → pluginify-1.19.0a0}/pluginify/interfaces/__init__.py +0 -0
  28. {pluginify-0.1.0 → pluginify-1.19.0a0}/pluginify/interfaces/base.py +0 -0
  29. {pluginify-0.1.0 → pluginify-1.19.0a0}/pluginify/interfaces/class_based/data_modifiers.py +0 -0
  30. {pluginify-0.1.0 → pluginify-1.19.0a0}/pluginify/interfaces/class_based_plugin.py +0 -0
  31. {pluginify-0.1.0 → pluginify-1.19.0a0}/pluginify/interfaces/yaml_based/configs.py +0 -0
  32. {pluginify-0.1.0 → pluginify-1.19.0a0}/pluginify/plugins/classes/data_modifiers/cuboid.py +0 -0
  33. {pluginify-0.1.0 → pluginify-1.19.0a0}/pluginify/plugins/yaml/configs/stucco.yaml +0 -0
  34. {pluginify-0.1.0 → pluginify-1.19.0a0}/pluginify/pydantic_models/v1/configs.py +0 -0
  35. {pluginify-0.1.0 → pluginify-1.19.0a0}/pluginify/utils/__init__.py +0 -0
  36. {pluginify-0.1.0 → pluginify-1.19.0a0}/pluginify/utils/context_managers.py +0 -0
  37. {pluginify-0.1.0 → pluginify-1.19.0a0}/pluginify/utils/validators.py +0 -0
  38. {pluginify-0.1.0 → pluginify-1.19.0a0}/tests/conftest.py +0 -0
  39. {pluginify-0.1.0 → pluginify-1.19.0a0}/tests/unit_tests/config/test_config.py +0 -0
  40. {pluginify-0.1.0 → pluginify-1.19.0a0}/tests/unit_tests/plugin_registries/files/bad/invalid_interfaces.yaml +0 -0
  41. {pluginify-0.1.0 → pluginify-1.19.0a0}/tests/unit_tests/plugin_registries/files/bad/missing_lowest_keys.yaml +0 -0
  42. {pluginify-0.1.0 → pluginify-1.19.0a0}/tests/unit_tests/plugin_registries/files/bad/missing_plugin_types.yaml +0 -0
  43. {pluginify-0.1.0 → pluginify-1.19.0a0}/tests/unit_tests/plugin_registries/files/good/pluginify.yaml +0 -0
  44. {pluginify-0.1.0 → pluginify-1.19.0a0}/tests/unit_tests/plugin_registries/test_plugin_registries.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pluginify
3
- Version: 0.1.0
3
+ Version: 1.19.0a0
4
4
  Summary: Pluginify package
5
5
  License: LICENSE
6
6
  License-File: LICENSE
@@ -0,0 +1,17 @@
1
+ enhancement:
2
+ - title: 'Omit dot files and directories from registry.'
3
+ description: |
4
+ Updated plugin registry code to ignore any instance of dot files or directories
5
+ from the plugin registry. This is a minor update to prevent .ipynb files and other
6
+ irrelevant files from sometimes leaking into the registry and causing problems
7
+ (such as duplicate keys).
8
+ files:
9
+ modified:
10
+ - pluginify/create_plugin_registries.py
11
+ related-issue:
12
+ number: null
13
+ repo_url: ''
14
+ date:
15
+ start: null
16
+ finish: null
17
+
@@ -0,0 +1,18 @@
1
+ enhancement:
2
+ - title: 'Migrate OBP "expand" functionality to pluginify.'
3
+ description: |
4
+ Direct copy over of changes made in a GeoIPS PR to the plugin_registry.py file.
5
+
6
+ Changes made added support for pluginify to dynamically 'expand' a workflow if a
7
+ product, product_default, or workflow was found within a workflow plugin. This is
8
+ only done if the '_expand' argument is set to True, which is done via the
9
+ 'geoips expand <workflow_name>' command.
10
+ files:
11
+ modified:
12
+ - pluginify/plugin_registry.py
13
+ related-issue:
14
+ number: null
15
+ repo_url: ''
16
+ date:
17
+ start: null
18
+ finish: null
@@ -3,5 +3,5 @@
3
3
 
4
4
  # DO NOT EDIT
5
5
  # managed by poetry-dynamic-versioning
6
- __version__ = "0.1.0"
7
- __version_tuple__ = (0, 1, 0)
6
+ __version__ = "1.19.0a0"
7
+ __version_tuple__ = (1, 19, "0a0")
@@ -27,6 +27,7 @@ from os.path import (
27
27
  split,
28
28
  splitext,
29
29
  )
30
+ from pathlib import Path
30
31
  import re
31
32
  import warnings
32
33
 
@@ -481,6 +482,13 @@ def parse_plugin_paths(plugin_paths, package, package_dir, plugins, namespace):
481
482
  for plugin_type in plugin_paths:
482
483
  # Loop through each file of the current plugin type.
483
484
  for filepath in plugin_paths[plugin_type]:
485
+ # If any 'part' of the full filepath starts with a '.' (dot) directory or
486
+ # file, do not use this filepath. Just continue to the next filepath
487
+ # provided. Resolving path to prevent false-positives on "." or ".."
488
+ # paths for relative paths as an edge case.
489
+ if any(part.startswith(".") for part in Path(filepath).resolve().parts):
490
+ continue
491
+
484
492
  filepath = str(filepath)
485
493
  # Path relative to the package directory
486
494
  relpath = os_relpath(filepath, start=package_dir)
@@ -36,6 +36,34 @@ from pluginify.utils import merge_nested_dicts
36
36
  LOG = logging.getLogger(__name__)
37
37
 
38
38
 
39
+ def env_constructor(loader, node):
40
+ """YAML constructor for the ``!ENV`` tag that expands environment variables.
41
+
42
+ This function allows YAML files to include environment variables using
43
+ the ``!ENV`` tag. The scalar value associated with the tag is read and
44
+ any environment variables within the string (e.g. ``${VAR_NAME}``) are
45
+ expanded using :func:`os.path.expandvars`.
46
+
47
+ Parameters
48
+ ----------
49
+ loader : yaml.Loader
50
+ The YAML loader instance currently parsing the document.
51
+ node : yaml.Node
52
+ The YAML node containing the scalar value associated with the ``!ENV`` tag.
53
+
54
+ Returns
55
+ -------
56
+ str
57
+ The scalar value with any environment variables expanded using the
58
+ current process environment.
59
+ """
60
+ value = loader.construct_scalar(node)
61
+ return os.path.expandvars(value)
62
+
63
+
64
+ yaml.SafeLoader.add_constructor("!ENV", env_constructor)
65
+
66
+
39
67
  class PluginRegistry:
40
68
  """Plugin Registry class definition.
41
69
 
@@ -372,7 +400,7 @@ class PluginRegistry:
372
400
 
373
401
  return metadata
374
402
 
375
- def load_plugin(self, data: dict) -> BaseModel:
403
+ def load_plugin(self, data: dict, _expand: bool = False) -> BaseModel:
376
404
  """
377
405
  Dynamically load and validate pydantic models based on apiVersion and interface.
378
406
 
@@ -387,6 +415,10 @@ class PluginRegistry:
387
415
  Dictionary representing a plugin definition. Must include the `interface`
388
416
  field. May optionally include `apiVersion`. If not present, "pluginify/v1"
389
417
  is assumed.
418
+ _expand : private bool (default=False)
419
+ If true, fully expand the workflow plugin in place. Otherwise, load as is
420
+ done usually. This should only be used for the
421
+ 'geoips expand <workflow>' command.
390
422
 
391
423
  Returns
392
424
  -------
@@ -400,7 +432,9 @@ class PluginRegistry:
400
432
  ImportError
401
433
  If the specified module for the given model version cannot be imported.
402
434
  """
403
- api_version = data.get("apiVersion", "pluginify/v1")
435
+ # Make this GeoIPS for now, change later once apiVersion is set on all yaml
436
+ # plugins.
437
+ api_version = data.get("apiVersion", "geoips/v1")
404
438
 
405
439
  # Split "package_name/model_version"
406
440
  # Use package_name to select the appropriate package to search for the api.
@@ -418,9 +452,15 @@ class PluginRegistry:
418
452
 
419
453
  # Construct module path and import
420
454
  try:
421
- module = import_module(
422
- f"{package_name}.pydantic_models.{model_version}.{interface}"
423
- )
455
+ if interface == "product_defaults":
456
+ # product_defaults model defined in products pydantic module
457
+ module = import_module(
458
+ f"{package_name}.pydantic_models.{model_version}.products"
459
+ )
460
+ else:
461
+ module = import_module(
462
+ f"{package_name}.pydantic_models.{model_version}.{interface}"
463
+ )
424
464
  except ImportError as e:
425
465
  raise ImportError(
426
466
  f"Could not import models from '{api_version}': {e}"
@@ -431,15 +471,20 @@ class PluginRegistry:
431
471
 
432
472
  try:
433
473
  model_class = getattr(module, model_name)
434
- print("model class \t", model_class)
435
474
  except AttributeError as e:
436
475
  raise ValueError(
437
476
  f"Model '{model_name}' not found in '{api_version}'"
438
477
  ) from e
439
478
 
440
- return model_class.model_validate(data)
479
+ if _expand:
480
+ # Only applies to workflow plugins
481
+ return model_class.model_validate(data, context={"expand": True})
441
482
 
442
- def get_yaml_plugin(self, interface_obj, name, rebuild_registries=None):
483
+ return model_class(**data)
484
+
485
+ def get_yaml_plugin(
486
+ self, interface_obj, name, rebuild_registries=None, _expand=False
487
+ ):
443
488
  """Get a YAML plugin by its name.
444
489
 
445
490
  Parameters
@@ -456,7 +501,16 @@ class PluginRegistry:
456
501
  is true and get_plugin fails, rebuild the plugin registry, call then call
457
502
  get_plugin once more with rebuild_registries toggled off, so it only gets
458
503
  rebuilt once.
504
+ _expand: private bool (default=False)
505
+ - If true, fully expand the workflow plugin in place. Otherwise, load as is
506
+ done usually. This should only be used for the
507
+ 'geoips expand <workflow>' command.
459
508
  """
509
+ if _expand and interface_obj.name != "workflows":
510
+ raise AssertionError(
511
+ "Error: you cannot set argument 'expand' to true unless you are "
512
+ "requesting a workflow plugin."
513
+ )
460
514
  try:
461
515
  registered_yaml_plugins = self.registered_plugins["yaml_based"]
462
516
  except KeyError:
@@ -562,7 +616,21 @@ class PluginRegistry:
562
616
  plugin["relpath"] = relpath
563
617
 
564
618
  if getattr(interface_obj, "use_pydantic", False):
565
- return self.load_plugin(plugin).model_dump()
619
+
620
+ def remove_none(d: dict) -> dict:
621
+ """Recursively remove all keys with value None from a dictionary."""
622
+ if not isinstance(d, dict):
623
+ return d
624
+ return {k: remove_none(v) for k, v in d.items() if v is not None}
625
+
626
+ validated = self.load_plugin(plugin, _expand).model_dump()
627
+ validated = remove_none(validated)
628
+
629
+ if "package" not in validated or "relpath" not in validated:
630
+ validated["package"] = package
631
+ validated["relpath"] = relpath
632
+
633
+ return interface_obj._plugin_yaml_to_obj(name, validated)
566
634
  else:
567
635
  validated = interface_obj.validator.validate(plugin)
568
636
  return interface_obj._plugin_yaml_to_obj(name, validated)
@@ -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"
3
+ version = "1.19.0a0"
4
4
  description = "Pluginify package"
5
5
  authors = ["Evan Rose", "evrose54@colostate.edu"]
6
6
  readme = "README.md"
File without changes
File without changes