How to write a custom PyZeta plugin¶
Imports¶
[1]:
# some standard library imports
from json import load
from os.path import dirname, join
from typing import Callable, Optional, Tuple, Type
# the core imports for writing your custom logic and the plugin
from pyzeta.core.pyzeta_types.special import tGroupElement
from pyzeta.core.symmetries.symmetry_group import SymmetryGroup
from pyzeta.core.symmetries.trivial_group import TrivialGroup
from pyzeta.framework.plugins.installation_helper import InstallationHelper
from pyzeta.framework.plugins.pyzeta_plugin import PyZetaPlugin
Implement your custom logic¶
[2]:
class TestGroup(TrivialGroup):
"Custom (trivial) symmetry group implementation to supply as a plugin."
def __init__(self, arg1: str, arg2: int) -> None:
"Initialize our custom symmetry group implementation."
super().__init__()
self.arg1 = arg1
self.arg2 = arg2
def getElements(self) -> Tuple[tGroupElement, ...]:
"Override this in our custom symmetry group."
raise NotImplementedError(
f"test group[{self.arg1} | {self.arg2}] is not fully implemented!"
)
def __str__(self) -> str:
"Just for printing - generic plugins don't actually need this."
return f"TestGroup({self.arg1}, {self.arg2})"
How to include custom configuration data¶
[3]:
# here is an example of how to include custom configuration data with your
# plugin (once the data file is installed!):
configFile = InstallationHelper.returnDataPath("group_data.json")
with open(configFile, "r", encoding="utf-8") as f:
customData = load(f)
The actual plugin class¶
[4]:
class GroupPlugin(PyZetaPlugin[SymmetryGroup]):
"Test plugin providing a simple custom symmetry group to PyZeta."
_instance: Optional[PyZetaPlugin[SymmetryGroup]] = None
@staticmethod
def initialize() -> Callable[..., SymmetryGroup]:
"This is the hook of plugins into `PyZeta`."
arg1, arg2 = customData["arg1"], customData["arg2"]
return lambda: TestGroup(arg1=arg1, arg2=arg2)
@staticmethod
def getInstance() -> PyZetaPlugin[SymmetryGroup]:
"Plugins should be realized as singletons."
if GroupPlugin._instance is None:
GroupPlugin._instance = GroupPlugin()
return GroupPlugin._instance
@property
def pluginType(self) -> Type[SymmetryGroup]:
"The type provided by the plugin."
return SymmetryGroup
@property
def pluginName(self) -> str:
"The name of the plugin."
return "TestGroupPlugin"
@property
def pluginVersion(self) -> Tuple[int, int, int]:
"""
The version of the plugin (the combination of version and name should
be unique). The semantics are (`major`, `minor`, `patch`).
"""
return (22, 1, 0)
if __name__ == "__main__":
print(f"the plugin itself: {GroupPlugin.getInstance()}")
print(f"the provided service: {GroupPlugin.initialize()()}")
the plugin itself: MyTestAlgorithmPlugin @ v22.1.0
the provided service: TestAlgorithm(hi from algorithm_data.json!, 9)...! :)
Installing the plugin¶
With the prerequisits above placed in a single .py source file named group_plugin.py you can now install your plugin as follows:
$ pyzeta plugin --install group_plugin.py
$ pyzeta plugin --install group_data.json
Your group can now be used e.g. in conjunction with symmetry reduction! If you would like to change the configuration data provided via group_data.json, simple adjust the file contents and issue the second command again.
Note that your plugin overrides the default groups contained in PyZeta. To restore these defaults simply --uninstall your plugin. By adapting the example above it is also quite straightforward to replace a given default group with your custom plugin and leave the remaining ones untouched. To achieve this the return value of your plugin’s initialize must accept a groupType parameter of type pyzeta.core.pyzeta_types.group_types.GroupType. You may then return any group of your
choosing upon a given value of groupType.