diff --git a/.github/ISSUE_TEMPLATE/issue.yml b/.github/ISSUE_TEMPLATE/issue.yml index dd84824..12c0bef 100644 --- a/.github/ISSUE_TEMPLATE/issue.yml +++ b/.github/ISSUE_TEMPLATE/issue.yml @@ -45,4 +45,4 @@ body: attributes: label: Environment (optional, bugs only) description: Python version, OS, mloda version. - placeholder: Python 3.12, Linux, mloda 0.9.0 + placeholder: Python 3.12, Linux, mloda 0.10.0 diff --git a/README.md b/README.md index 203fbaf..e9901b1 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ placeholder/ ### Plugin discovery -mloda 0.9+ auto-discovers installed plugins via `PluginLoader.all()`, no manual import needed. Each +mloda auto-discovers installed plugins via `PluginLoader.all()`, no manual import needed. Each `manifest.py` lists its concrete classes (`FEATURE_GROUPS`, `COMPUTE_FRAMEWORKS`, `EXTENDERS`) and `pyproject.toml` wires them up under `[project.entry-points."mloda.*"]`. Add a plugin by appending it to the relevant list. diff --git a/placeholder/compute_frameworks/my_plugin/my_compute_framework.py b/placeholder/compute_frameworks/my_plugin/my_compute_framework.py index 1cb5df4..55f6043 100644 --- a/placeholder/compute_frameworks/my_plugin/my_compute_framework.py +++ b/placeholder/compute_frameworks/my_plugin/my_compute_framework.py @@ -1,6 +1,5 @@ """Example ComputeFramework implementation.""" -from typing import Optional, Set from uuid import UUID, uuid4 from mloda.core.abstract_plugins.components.parallelization_modes import ParallelizationMode @@ -15,8 +14,10 @@ def __init__( self, mode: ParallelizationMode = ParallelizationMode.SYNC, children_if_root: frozenset[UUID] = frozenset(), - uuid: UUID = uuid4(), - function_extender: Optional[Set[Extender]] = None, + uuid: UUID | None = None, + function_extender: set[Extender] | None = None, ) -> None: """Initialize with default values for minimal instantiation.""" - super().__init__(mode, children_if_root, uuid, function_extender) + # uuid defaults to None, not uuid4(): a default is evaluated once, so every + # instance would otherwise share one id. + super().__init__(mode, children_if_root, uuid or uuid4(), function_extender) diff --git a/placeholder/compute_frameworks/my_plugin/tests/test_my_compute_framework.py b/placeholder/compute_frameworks/my_plugin/tests/test_my_compute_framework.py index 3c10722..9e4dbfe 100644 --- a/placeholder/compute_frameworks/my_plugin/tests/test_my_compute_framework.py +++ b/placeholder/compute_frameworks/my_plugin/tests/test_my_compute_framework.py @@ -1,5 +1,7 @@ """Tests for MyComputeFramework.""" +from uuid import uuid4 + from placeholder.compute_frameworks.my_plugin import MyComputeFramework from mloda.provider import ComputeFramework @@ -13,3 +15,14 @@ def test_instantiation() -> None: """MyComputeFramework should instantiate with no arguments.""" instance = MyComputeFramework() assert instance is not None + + +def test_default_uuid_is_per_instance() -> None: + """Each instance gets its own uuid; a uuid4() default would be shared by all.""" + assert MyComputeFramework().uuid != MyComputeFramework().uuid + + +def test_explicit_uuid_is_respected() -> None: + """An explicitly passed uuid is not overwritten.""" + given = uuid4() + assert MyComputeFramework(uuid=given).uuid == given diff --git a/placeholder/extenders/my_plugin/my_extender.py b/placeholder/extenders/my_plugin/my_extender.py index f0d761d..4ec2d20 100644 --- a/placeholder/extenders/my_plugin/my_extender.py +++ b/placeholder/extenders/my_plugin/my_extender.py @@ -1,6 +1,6 @@ """Example Extender implementation.""" -from typing import Any, Set +from typing import Any from mloda.core.abstract_plugins.function_extender import Extender, ExtenderHook @@ -8,7 +8,7 @@ class MyExtender(Extender): """Example Extender - rename and customize for your use case.""" - def wraps(self) -> Set[ExtenderHook]: + def wraps(self) -> set[ExtenderHook]: """Return the set of hooks this extender wraps.""" return set() diff --git a/pyproject.toml b/pyproject.toml index 0e9c803..f5104f0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,10 +10,10 @@ version = "0.4.0" description = "TEMPLATE PLACEHOLDER - Do not install directly. This package reserves the name for mloda-plugin-template. See https://github.com/mloda-ai/mloda-plugin-template" license = "Apache-2.0" authors = [{ name = "Your Name placeholder", email = "placeholder@placeholder.com" }] -dependencies = ["mloda>=0.9.0", "mloda-testing>=0.3.2"] +dependencies = ["mloda>=0.10.0", "mloda-testing>=0.3.2"] requires-python = ">=3.10" -# mloda 0.9 discovers installed plugins through these entry points: each resolves to a +# mloda discovers installed plugins through these entry points: each resolves to a # manifest list of concrete classes. customize.sh rewrites the dotted paths on rename. [project.entry-points."mloda.feature_groups"] placeholder = "placeholder.feature_groups.manifest:FEATURE_GROUPS" diff --git a/tests/test_entry_points.py b/tests/test_entry_points.py index 191fd28..e81a61c 100644 --- a/tests/test_entry_points.py +++ b/tests/test_entry_points.py @@ -24,8 +24,12 @@ def test_entry_points_declared() -> None: assert any(v.endswith(suffix) for v in values), f"{group}: no entry point ending in {suffix}; got {values}" -def test_plugin_loader_discovers_example_classes() -> None: - """PluginLoader.all() registers the example classes via entry points, without importing the package.""" +def test_plugin_loader_discovers_example_classes(isolated_plugin_registry: PluginRegistry) -> None: + """PluginLoader.all() registers the example classes via entry points, without importing the package. + + isolated_plugin_registry (shipped by mloda as a pytest plugin) restores the process-global + registry on teardown, so this force_reload does not leak into later tests. + """ PluginLoader.all(force_reload=True) - registered = {cls.__name__ for cls in PluginRegistry.default().registered_classes()} + registered = {cls.__name__ for cls in isolated_plugin_registry.registered_classes()} assert {"MyFeatureGroup", "MyComputeFramework", "MyExtender"} <= registered diff --git a/uv.lock b/uv.lock index 882825c..7abcd5e 100644 --- a/uv.lock +++ b/uv.lock @@ -233,10 +233,10 @@ wheels = [ [[package]] name = "mloda" -version = "0.9.0" +version = "0.10.0" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f2/82/a7893ddd9ab26dd839671c594e9c16437364a8b8ed5dffb02e9b2de52d7f/mloda-0.9.0-py3-none-any.whl", hash = "sha256:d193b03622e6c8670ccde500c9e6d74eba9ef4ed70ca3bd6adbcb9330a370585", size = 430826, upload-time = "2026-07-07T08:48:32.032Z" }, + { url = "https://files.pythonhosted.org/packages/d6/9d/2251f947bfde5e168b9f6759079c8b54af0393c3e854987268459b860776/mloda-0.10.0-py3-none-any.whl", hash = "sha256:13fd1482566de203cac661c29f5736423ce7d1cc8e43ec26f8d24d19e6386229", size = 456550, upload-time = "2026-07-13T18:35:02.322Z" }, ] [[package]] @@ -360,7 +360,7 @@ dev = [ [package.metadata] requires-dist = [ { name = "bandit", marker = "extra == 'dev'" }, - { name = "mloda", specifier = ">=0.9.0" }, + { name = "mloda", specifier = ">=0.10.0" }, { name = "mloda-testing", specifier = ">=0.3.2" }, { name = "mypy", marker = "extra == 'dev'" }, { name = "pytest", marker = "extra == 'dev'" },