Skip to content

Commit 42f0988

Browse files
authored
Plugin Import Fix; Keep List of ServiceAPIs (#63)
- Use relative file path for plugin imports. - External dependents need access to the list of ServiceAPIs. - `Service` must not be a dataclass, since they are unhashable and can therefore not be stored in dicts.
1 parent e52f76f commit 42f0988

6 files changed

Lines changed: 21 additions & 17 deletions

File tree

pfdl_scheduler/model/service.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
from pfdl_scheduler.model.array import Array
2020

2121

22-
@dataclass
2322
class Service:
2423
"""Represents a Service or Service Call in the PFDL.
2524

pfdl_scheduler/petri_net/generator.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ def __init__(
127127
self.tree = None
128128
self.file_name = file_name
129129
self.pfdl_base_classes = pfdl_base_classes
130+
self.service_apis: list[ServiceAPI] = []
130131

131132
def add_callback(self, transition_uuid: str, callback_function: Callable, *args: Any) -> None:
132133
"""Registers the given callback function in the transition_dict.
@@ -288,6 +289,7 @@ def generate_service(
288289
service_api = self.pfdl_base_classes.get_class("ServiceAPI")(
289290
service, task_context, in_loop=in_loop
290291
)
292+
self.service_apis.append(service_api)
291293

292294
service_started_uuid = create_place(service.name + " started", self.net, service_node)
293295
service_finished_uuid = create_place(service.name + " finished", self.net, service_node)

pfdl_scheduler/plugins/plugin_loader.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,12 @@
1212
import sys
1313
import inspect
1414
from typing import List
15+
from pathlib import Path
1516

1617
from pfdl_scheduler.pfdl_base_classes import PFDLBaseClasses
1718

1819
base_classes_registry = {}
1920

20-
PLUGIN_FOLDER_PATH = "./pfdl_scheduler/plugins"
21-
2221

2322
def base_class(existing_class_name):
2423
"""A Decorator to mark a class that will extend an existing class.
@@ -160,16 +159,18 @@ def load_plugin_modules(self, module_name, module_path):
160159
def load_plugins(self, plugins: List[str]):
161160
"""Recursively load all Python files from plugin folders."""
162161
for plugin_folder in plugins:
163-
plugin_path = os.path.join(PLUGIN_FOLDER_PATH, plugin_folder)
164-
165-
if os.path.isdir(plugin_path):
166-
# Walk through all files in the plugin folder
167-
for root, _, files in os.walk(plugin_path):
168-
for file in files:
169-
if file.endswith(".py"):
170-
module_name = f"{plugin_folder}.{file[:-3]}" # Plugin folder + filename without .py
171-
module_path = os.path.join(root, file)
172-
self.load_plugin_modules(module_name, module_path)
162+
plugin_path = Path(__file__).parent / plugin_folder
163+
164+
if not plugin_path.is_dir():
165+
raise ValueError("given plugin could not be found")
166+
167+
# Walk through all files in the plugin folder
168+
for root, _, files in os.walk(plugin_path):
169+
for file in files:
170+
if file.endswith(".py"):
171+
module_name = f"{plugin_folder}.{file[:-3]}" # Plugin folder + filename without .py
172+
module_path = os.path.join(root, file)
173+
self.load_plugin_modules(module_name, module_path)
173174

174175
def get_final_classes(self):
175176
"""Return a dictionary of final classes after applying plugins."""

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
setup(
1313
name="pfdl_scheduler",
14-
version="0.9.0",
14+
version="0.9.2",
1515
description="Parser and Scheduler for Production Flow Description Language (PFDL) files.",
1616
long_description=long_description,
1717
long_description_content_type='text/markdown',

tests/unit_test/model/test_condition.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ def test_init(self):
3232
context = ParserRuleContext()
3333
condition = Condition({"a": 1}, [Service("service")], [TaskCall("task")], context=context)
3434
self.assertEqual(condition.expression, {"a": 1})
35-
self.assertEqual(condition.passed_stmts, [Service("service")])
35+
self.assertEqual(1, len(condition.passed_stmts))
36+
self.assertIsInstance(condition.passed_stmts[0], Service)
37+
self.assertEqual("service", condition.passed_stmts[0].name)
3638
self.assertEqual(condition.failed_stmts, [TaskCall("task")])
3739
self.assertEqual(condition.context, context)
3840
self.assertEqual(condition.context_dict, {})

tests/unit_test/model/test_task.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ def test_init(self):
4242
)
4343
self.assertEqual(task.name, "task1")
4444
self.assertEqual(len(task.statements), 4)
45-
self.assertEqual(task.statements[0], Service())
45+
self.assertIsInstance(task.statements[0], Service)
4646
self.assertEqual(task.statements[1], CountingLoop())
4747
self.assertEqual(task.statements[2], CountingLoop())
48-
self.assertEqual(task.statements[3], Service())
48+
self.assertIsInstance(task.statements[3], Service)
4949
self.assertEqual(task.variables, {"var1": "val1", "var2": "val2"})
5050
self.assertEqual(task.input_parameters, {"in1": "val4", "in2": "val5"})
5151
self.assertEqual(task.output_parameters, ["out1", "out2"])

0 commit comments

Comments
 (0)