14 Commits
7 changed files with 37 additions and 8 deletions
+4 -3
View File
@@ -1,6 +1,6 @@
# XtendR # XtendR
A very basic Python 3.12 plugin system based on the K.I.S.S principle. A very basic Python 3.12 friendly plugin system based on the K.I.S.S principle.
I was in need of a new plugin system, which should meet these requirements: I was in need of a new plugin system, which should meet these requirements:
:heavy_plus_sign: Simple to use :heavy_plus_sign: Simple to use
@@ -16,7 +16,8 @@ I didn't find anything that suited my needs, so I decided to make my own plugin
It simply contains 2 classes, one for the plugin system and one abstraction base class for the plugins themselves. It simply contains 2 classes, one for the plugin system and one abstraction base class for the plugins themselves.
At the moment only 4 functions are available: At the moment only 4 functions are available:
- Attach
- Attach - including call to pre-load data in plugin.
- Run - Run
- Stop - Stop
- Detach - Detach
@@ -27,4 +28,4 @@ The Run and Stop functions are mandatory in the plugin modules.
The system expects a folder called 'plugins', placed at the root, along side your main python file. The system expects a folder called 'plugins', placed at the root, along side your main python file.
Each plugin should be placed in subfolders, named as the plugin, inside the 'plugins' folder. Each plugin should be placed in subfolders, named as the plugin, inside the 'plugins' folder.
The example.py along with the plugins/example_plugin/example_plugin.py and plugins/example_plugin/example_plugin.json shows the workings of this plugin system. The example.py along with the plugins/example_plugin/example_plugin.py and plugins/example_plugin/example_plugin.json shows the workings of this plugin system.
+8 -1
View File
@@ -1,5 +1,9 @@
import time
from xtendr.xtendrsystem import XtendRSystem from xtendr.xtendrsystem import XtendRSystem
def my_callback():
print("'example_plugin is finished pre-loading")
if __name__ == "__main__": if __name__ == "__main__":
"""Example usage of the PluginSystem. """Example usage of the PluginSystem.
@@ -15,7 +19,10 @@ if __name__ == "__main__":
Detached plugin 'example_plugin'. Detached plugin 'example_plugin'.
""" """
system = XtendRSystem() system = XtendRSystem()
system.attach("example_plugin") # Assuming 'example_plugin/plugin_info.json' exists system.attach("example_plugin", my_callback) # Assuming 'example_plugin/plugin_info.json' exists
for i in range(3):
print(f"Main program is running iteration {i+1}...")
time.sleep(2)
system.run("example_plugin", test="Hello!") system.run("example_plugin", test="Hello!")
system.stop("example_plugin") system.stop("example_plugin")
system.run("example_plugin", 25) system.run("example_plugin", 25)
+6
View File
@@ -1,3 +1,5 @@
import threading
import time
from xtendr.xtendrbase import XtendRBase from xtendr.xtendrbase import XtendRBase
class ExamplePlugin(XtendRBase): class ExamplePlugin(XtendRBase):
@@ -31,3 +33,7 @@ class ExamplePlugin(XtendRBase):
def stop(self): def stop(self):
print("ExamplePlugin has stopped!") print("ExamplePlugin has stopped!")
def pre_load(self, callback):
time.sleep(5) # Indicate long running pre-load.
callback()
+1
View File
@@ -0,0 +1 @@
setuptools==68.2.2
+7 -2
View File
@@ -1,9 +1,12 @@
if __name__ == "__main__": if __name__ == "__main__":
from setuptools import setup, find_packages from setuptools import setup, find_packages
from pathlib import Path
this_directory = Path(__file__).parent
long_description = (this_directory / "README.md").read_text()
setup( setup(
name="XtendR", name="XtendR",
version="0.2.1", version="0.3.3.1",
packages=find_packages(), packages=find_packages(),
install_requires=[], install_requires=[],
author="Jan Lerking", author="Jan Lerking",
@@ -16,4 +19,6 @@ if __name__ == "__main__":
"Operating System :: OS Independent", "Operating System :: OS Independent",
], ],
python_requires='>=3.11', python_requires='>=3.11',
long_description=long_description,
long_description_content_type='text/markdown'
) )
+5
View File
@@ -23,3 +23,8 @@ class XtendRBase(ABC):
@abstractmethod @abstractmethod
def stop(self): def stop(self):
pass pass
@abstractmethod
def pre_load(self, *args):
pass
+6 -2
View File
@@ -2,9 +2,10 @@ import importlib
import sys import sys
import os import os
import json import json
import threading
from xtendr.xtendrbase import XtendRBase from xtendr.xtendrbase import XtendRBase
__version__ = "0.1.3" __version__ = "0.3.3.1"
class XtendRSystem: class XtendRSystem:
"""Plugin system to manage plugins. """Plugin system to manage plugins.
@@ -28,7 +29,7 @@ class XtendRSystem:
def version(self) -> str: def version(self) -> str:
return "XtendR v" + __version__ return "XtendR v" + __version__
def attach(self, name: str) -> None: def attach(self, name: str, callback) -> None:
"""Dynamically load a plugin from its folder.""" """Dynamically load a plugin from its folder."""
if name in self.plugins: if name in self.plugins:
print(f"Plugin '{name}' is already attached.") print(f"Plugin '{name}' is already attached.")
@@ -67,6 +68,9 @@ class XtendRSystem:
'autorun': False 'autorun': False
} }
print(f"Attached plugin '{name}'.") print(f"Attached plugin '{name}'.")
print(f"Running pre-load on '{name}'.")
thread = threading.Thread(target=self.plugins[name]['instance'].pre_load, args=(callback,))
thread.start()
except (ModuleNotFoundError, json.JSONDecodeError, AttributeError) as e: except (ModuleNotFoundError, json.JSONDecodeError, AttributeError) as e:
print(f"Failed to attach plugin '{name}': {e}") print(f"Failed to attach plugin '{name}': {e}")