Repository: stephend017/sd_utils

Issue:
Allow plugins to return values
allow a plugin to return a value. along with this update a plugin should also be able to receive a value in the on_register hook

Discussion:

Patch:
diff --git a/sd_utils/plugins/plugin_base.py b/sd_utils/plugins/plugin_base.py
index 1aef059..21ff90a 100644
--- a/sd_utils/plugins/plugin_base.py
+++ b/sd_utils/plugins/plugin_base.py
@@ -10,10 +10,14 @@ class PluginBase:
         """
         pass
 
-    def on_register(self):
+    def on_register(self, data: Any = None):
         """
         runs when this plugin is registered with
         the plugin manager
+
+        Args:
+            data (Any): any parameters passed to this
+                plugin from the plugin manager
         """
         raise NotImplementedError
 
@@ -21,11 +25,19 @@ class PluginBase:
         """
         runs when the manager begins a query for
         any plugin.
+
+        Args:
+            data (Any): any parameters passed to this
+                plugin from the plugin manager
         """
         raise NotImplementedError
 
-    def on_find(self, data: Any = None):
+    def on_find(self, data: Any = None) -> Any:
         """
         runs when the manager specifically queries this plugin
+
+        Args:
+            data (Any): any parameters passed to this
+                plugin from the plugin manager
         """
         raise NotImplementedError
diff --git a/sd_utils/plugins/plugin_collector.py b/sd_utils/plugins/plugin_collector.py
index f40e3fe..44dc3d1 100644
--- a/sd_utils/plugins/plugin_collector.py
+++ b/sd_utils/plugins/plugin_collector.py
@@ -8,7 +8,7 @@ from importlib import import_module
 def collect_plugins(
     registering_file: str,
     registering_file_name: str,
-    cls: ClassVar[PluginBase],
+    cls: ClassVar[PluginBase] = PluginBase,
     exclude_files: List[str] = [],
     assert_one_per_source: bool = True,
 ) -> List[str]:
@@ -20,10 +20,13 @@ def collect_plugins(
         registering_file (str): should be `__file__` of the calling file
         registering_file_name (str): should be `__name__` of the calling file
         cls (ClassVar[PluginBase]): the type of plugin to collect
-        exclude_files (List[str]): any file to exclude from being collected as a plugin
-        assert_one_per_source (bool): asserts that only 1 plugin may be defined in each source file
+        exclude_files (List[str]): any file to exclude from being collected
+            as a plugin
+        assert_one_per_source (bool): asserts that only 1 plugin may be
+            defined in each source file
     Returns:
-        List[str]: a list of all the plugin files collected
+        List[str]: a list of all the plugin files collected. should be
+            stored in the calling files `__all__` variable
     """
     exports = []
 
diff --git a/sd_utils/plugins/plugin_manager.py b/sd_utils/plugins/plugin_manager.py
index 5331be0..deb41ff 100644
--- a/sd_utils/plugins/plugin_manager.py
+++ b/sd_utils/plugins/plugin_manager.py
@@ -1,15 +1,21 @@
 from sd_utils.plugins.plugin_base import PluginBase
-from typing import ClassVar
+from typing import Any, ClassVar, final
 
 
 class PluginManager:
     def __init__(self):
         self._plugins = {}
 
-    def register(self, name: str, **kwargs):
+    @final
+    def register(self, name: str, on_register_params: dict = {}, **kwargs):
         """
         decorator for registering a plugin to this instance of a
         plugin manager
+
+        Args:
+            name (str): the name to register this plugin under
+            **kwargs: parameters to be passed to the plugin
+                class when constructed
         """
 
         def decorator(plugin: ClassVar[PluginBase]):
@@ -24,15 +30,33 @@ class PluginManager:
             w = Wrapper(plugin(**kwargs))
 
             self._plugins[name] = w
-            w.plugin.on_register()
+            w.plugin.on_register(
+                self.get_on_register_params(name, **on_register_params)
+            )
 
             return w
 
         return decorator
 
-    def run(self, name: str):
+    @final
+    def run(
+        self, name: str, on_search_params: dict = {}, on_find_params: dict = {}
+    ) -> Any:
         """
-        runs a given plugin
+        runs a given plugin.
+
+        Note: this function
+
+        Args:
+            name (str): the name of the plugin to run
+            on_search_params (dict): parameters to pass to
+                the get_on_search_params function
+            on_find_params (dict): parameters to pass to
+                the get_on_find_params functions
+
+        Returns:
+            Any: The value returned by running the to_find
+                function of the called plugin
         """
 
         to_run = None
@@ -40,7 +64,9 @@ class PluginManager:
             if name == plugin_name:
                 to_run = wrapper
             try:
-                wrapper.plugin.on_search()
+                wrapper.plugin.on_search(
+                    self.get_on_search_params(name, **on_search_params)
+                )
             except NotImplementedError:
                 # just skip if its not implemented
                 pass
@@ -48,4 +74,55 @@ class PluginManager:
         if to_run is None:
             raise ValueError(f"Unable to find plugin with name [{name}]")
 
-        to_run.plugin.on_find()
+        return to_run.plugin.on_find(
+            self.get_on_find_params(name, **on_find_params)
+        )
+
+    def get_on_search_params(self, name: str, **kwargs) -> Any:
+        """
+        function that generates parameters for the on
+        search function of a plugin given its name
+
+        Args:
+            name (str): the name of the command to
+                call on_search for
+            **kwargs: any arguments sent from the run
+                function
+
+        Returns:
+            Any: the arguments to be sent to the on_search function
+        """
+        return kwargs
+
+    def get_on_find_params(self, name: str, **kwargs) -> Any:
+        """
+        function that generates parameters for the on
+        find function of a plugin given its name
+
+        Args:
+            name (str): the name of the command to
+                call on_find for
+            **kwargs: any arguments sent from the run
+                function
+
+        Returns:
+            Any: the arguments to be sent to the on_find function
+        """
+        return kwargs
+
+    def get_on_register_params(self, name: str, **kwargs) -> Any:
+        """
+        function that generates parameters for the on
+        register function of a plugin given its name
+
+        Args:
+            name (str): the name of the command to
+                call on_register for
+            **kwargs: any arguments sent from the
+                register function
+
+        Returns:
+            Any: the arguments to be sent to the
+                on_register function
+        """
+        return kwargs
diff --git a/setup.py b/setup.py
index 4f7f17d..340de1c 100644
--- a/setup.py
+++ b/setup.py
@@ -7,7 +7,7 @@ with open("README.md", "r") as file:
 
 setup(
     name="sd_utils",
-    version="0.1.0",
+    version="0.2.0",
     description="A python module with basic utils I tend to use in my projects",
     long_description=readme,
     long_description_content_type="text/markdown",


Test patch:
diff --git a/tests/plugins/__init__.py b/tests/plugins/__init__.py
index 6d5fcb4..b5792c1 100644
--- a/tests/plugins/__init__.py
+++ b/tests/plugins/__init__.py
@@ -1,7 +1,6 @@
-from sd_utils.plugins.plugin_base import PluginBase
 from sd_utils.plugins.plugin_collector import collect_plugins
 from sd_utils.plugins.plugin_manager import PluginManager
 
 mypluginmanager = PluginManager()
 
-collect_plugins(__file__, __name__, PluginBase)
+__all__ = collect_plugins(__file__, __name__)
diff --git a/tests/plugins/my_other_plugin.py b/tests/plugins/my_other_plugin.py
index bb73b4d..2f2542a 100644
--- a/tests/plugins/my_other_plugin.py
+++ b/tests/plugins/my_other_plugin.py
@@ -13,7 +13,7 @@ class MyOtherPlugin(PluginBase):
         """
         self.operations = []
 
-    def on_register(self):
+    def on_register(self, data: Any = None):
         """
         runs when this plugin is registered with
         the plugin manager
diff --git a/tests/plugins/my_plugin.py b/tests/plugins/my_plugin.py
index 23bf7a1..cc75323 100644
--- a/tests/plugins/my_plugin.py
+++ b/tests/plugins/my_plugin.py
@@ -12,8 +12,9 @@ class MyPlugin(PluginBase):
         """
         """
         self.operations = []
+        self.data = []
 
-    def on_register(self):
+    def on_register(self, data: Any = None):
         """
         runs when this plugin is registered with
         the plugin manager
@@ -26,9 +27,12 @@ class MyPlugin(PluginBase):
         any plugin.
         """
         self.operations.append("searched")
+        self.data.append(data)
 
     def on_find(self, data: Any = None):
         """
         runs when the manager specifically queries this plugin
         """
         self.operations.append("found")
+        self.data.append(data)
+        return data
diff --git a/tests/plugins/test_plugins.py b/tests/plugins/test_plugins.py
index 3f7a6c7..4f75aa5 100644
--- a/tests/plugins/test_plugins.py
+++ b/tests/plugins/test_plugins.py
@@ -22,8 +22,7 @@ def test_search_and_find():
     assert "searched" in mypluginmanager._plugins["myplugin"].plugin.operations
     assert "found" in mypluginmanager._plugins["myplugin"].plugin.operations
 
-    mypluginmanager._plugins["myplugin"].plugin.operations.remove("searched")
-    mypluginmanager._plugins["myplugin"].plugin.operations.remove("found")
+    mypluginmanager._plugins["myplugin"].plugin.operations.clear()
 
 
 def test_plugin_doesnt_exist():
@@ -34,7 +33,7 @@ def test_plugin_doesnt_exist():
     with pytest.raises(ValueError):
         mypluginmanager.run("notmyplugin")
 
-    mypluginmanager._plugins["myplugin"].plugin.operations.remove("searched")
+    mypluginmanager._plugins["myplugin"].plugin.operations.clear()
 
 
 def test_search_only():
@@ -49,4 +48,46 @@ def test_search_only():
         "found" not in mypluginmanager._plugins["myplugin"].plugin.operations
     )
 
-    mypluginmanager._plugins["myplugin"].plugin.operations.remove("searched")
+    mypluginmanager._plugins["myplugin"].plugin.operations.clear()
+
+
+def test_get_on_search_params():
+    """
+    Tests that get_on_search params properly takes in
+    the correct arguments
+    """
+
+    mydata = {"data": "value"}
+    mypluginmanager.run("myplugin", mydata)
+
+    assert mydata in mypluginmanager._plugins["myplugin"].plugin.data
+
+    mypluginmanager._plugins["myplugin"].plugin.data.clear()
+
+
+def test_get_on_find_params():
+    """
+    Tests that get_on_search params properly takes in
+    the correct arguments
+    """
+
+    mydata = {"data": "value"}
+    mypluginmanager.run("myplugin", on_find_params=mydata)
+
+    assert mydata in mypluginmanager._plugins["myplugin"].plugin.data
+
+    mypluginmanager._plugins["myplugin"].plugin.data.clear()
+
+
+def test_on_find_return_value():
+    """
+    Tests that get_on_search params properly takes in
+    the correct arguments
+    """
+
+    mydata = {"data": "value"}
+    response = mypluginmanager.run("myplugin", on_find_params=mydata)
+
+    assert response == mydata
+
+    mypluginmanager._plugins["myplugin"].plugin.data.clear()