parallelazy 0.0.1__tar.gz → 0.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. parallelazy-0.0.2/PKG-INFO +82 -0
  2. parallelazy-0.0.2/README.md +67 -0
  3. {parallelazy-0.0.1 → parallelazy-0.0.2}/parallelazy/plugin_data.py +1 -1
  4. {parallelazy-0.0.1 → parallelazy-0.0.2}/parallelazy/plugin_manager.py +6 -6
  5. {parallelazy-0.0.1 → parallelazy-0.0.2}/parallelazy/plugin_rpc.py +2 -2
  6. {parallelazy-0.0.1 → parallelazy-0.0.2}/parallelazy/plugin_transport.py +1 -1
  7. {parallelazy-0.0.1 → parallelazy-0.0.2}/parallelazy/plugin_worker.py +4 -4
  8. {parallelazy-0.0.1 → parallelazy-0.0.2}/parallelazy/utils.py +1 -1
  9. parallelazy-0.0.2/parallelazy.egg-info/PKG-INFO +82 -0
  10. parallelazy-0.0.2/parallelazy.egg-info/SOURCES.txt +17 -0
  11. {parallelazy-0.0.1 → parallelazy-0.0.2}/parallelazy.egg-info/requires.txt +1 -0
  12. {parallelazy-0.0.1 → parallelazy-0.0.2}/pyproject.toml +3 -2
  13. parallelazy-0.0.1/PKG-INFO +0 -17
  14. parallelazy-0.0.1/README.md +0 -3
  15. parallelazy-0.0.1/parallelazy/examples/__init__.py +0 -0
  16. parallelazy-0.0.1/parallelazy/examples/example_configuration.py +0 -194
  17. parallelazy-0.0.1/parallelazy/examples/example_count.py +0 -84
  18. parallelazy-0.0.1/parallelazy/examples/example_data_pipeline.py +0 -226
  19. parallelazy-0.0.1/parallelazy/examples/example_env_variables.py +0 -158
  20. parallelazy-0.0.1/parallelazy/examples/example_error_handling.py +0 -266
  21. parallelazy-0.0.1/parallelazy/examples/example_graceful_shutdown.py +0 -139
  22. parallelazy-0.0.1/parallelazy/examples/example_ml_training.py +0 -280
  23. parallelazy-0.0.1/parallelazy/examples/example_pubsub.py +0 -137
  24. parallelazy-0.0.1/parallelazy/examples/example_rpc_calls.py +0 -182
  25. parallelazy-0.0.1/parallelazy/examples/example_worker_pool.py +0 -188
  26. parallelazy-0.0.1/parallelazy/tests/__init__.py +0 -0
  27. parallelazy-0.0.1/parallelazy.egg-info/PKG-INFO +0 -17
  28. parallelazy-0.0.1/parallelazy.egg-info/SOURCES.txt +0 -29
  29. {parallelazy-0.0.1 → parallelazy-0.0.2}/LICENSE +0 -0
  30. {parallelazy-0.0.1 → parallelazy-0.0.2}/parallelazy/__init__.py +0 -0
  31. {parallelazy-0.0.1 → parallelazy-0.0.2}/parallelazy/environment_manager.py +0 -0
  32. {parallelazy-0.0.1 → parallelazy-0.0.2}/parallelazy/plugin.py +0 -0
  33. {parallelazy-0.0.1 → parallelazy-0.0.2}/parallelazy.egg-info/dependency_links.txt +0 -0
  34. {parallelazy-0.0.1 → parallelazy-0.0.2}/parallelazy.egg-info/top_level.txt +0 -0
  35. {parallelazy-0.0.1 → parallelazy-0.0.2}/setup.cfg +0 -0
@@ -0,0 +1,82 @@
1
+ Metadata-Version: 2.4
2
+ Name: parallelazy
3
+ Version: 0.0.2
4
+ Summary: A lightweight multiprocess worker-plugin framework. Topic-based pub/sub, global enviroment, using process spawn and pipes, pytorch and CUDA ready.
5
+ Author: Cesare Montresor
6
+ Project-URL: Homepage, https://github.com/cesare-montresor/parallelazy
7
+ Project-URL: Repository, https://github.com/cesare-montresor/parallelazy
8
+ Project-URL: Issues, https://github.com/cesare-montresor/parallelazy/issues
9
+ Requires-Python: >=3.8
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: debugpy
13
+ Requires-Dist: torch
14
+ Dynamic: license-file
15
+
16
+ # parallelazy
17
+
18
+ A lightweight Python plugin/worker framework with:
19
+
20
+ - isolated plugin processes started with `spawn`;
21
+ - topic-based publish/subscribe;
22
+ - shared environment values and change notifications;
23
+ - plugin-to-plugin RPC; and
24
+ - PyTorch/CUDA-aware multiprocessing support.
25
+
26
+ ## Install
27
+
28
+ ```bash
29
+ python -m pip install .
30
+ ```
31
+
32
+ ## Quick start
33
+
34
+ ```python
35
+ import time
36
+
37
+ from parallelazy.plugin import Plugin
38
+ from parallelazy.plugin_manager import PluginManager
39
+
40
+
41
+ class Worker(Plugin):
42
+ def on_start(self):
43
+ self.env_set("worker.ready", True)
44
+
45
+ def main(self):
46
+ pass
47
+
48
+
49
+ def main():
50
+ manager = PluginManager()
51
+ descriptor = Worker.Descriptor(
52
+ version="1.0.0",
53
+ author="Application team",
54
+ description="Example worker",
55
+ )
56
+ if not manager.load_plugin(descriptor):
57
+ raise RuntimeError("Plugin failed to load")
58
+ if not manager.start_plugin(descriptor.name):
59
+ raise RuntimeError("Plugin failed to start")
60
+ try:
61
+ time.sleep(0.1)
62
+ print(manager.env_get("worker.ready"))
63
+ finally:
64
+ manager.unload_plugin(descriptor.name)
65
+
66
+
67
+ if __name__ == "__main__":
68
+ main()
69
+ ```
70
+
71
+ ## Documentation
72
+
73
+ Read the [documentation index](docs/index.md) for installation, concepts,
74
+ API reference, usage patterns, and troubleshooting.
75
+
76
+ The complete runnable examples are in
77
+ [examples/](examples/). For example:
78
+
79
+ ```bash
80
+ python -m examples.example_pubsub
81
+ python -m examples.example_rpc_calls
82
+ ```
@@ -0,0 +1,67 @@
1
+ # parallelazy
2
+
3
+ A lightweight Python plugin/worker framework with:
4
+
5
+ - isolated plugin processes started with `spawn`;
6
+ - topic-based publish/subscribe;
7
+ - shared environment values and change notifications;
8
+ - plugin-to-plugin RPC; and
9
+ - PyTorch/CUDA-aware multiprocessing support.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ python -m pip install .
15
+ ```
16
+
17
+ ## Quick start
18
+
19
+ ```python
20
+ import time
21
+
22
+ from parallelazy.plugin import Plugin
23
+ from parallelazy.plugin_manager import PluginManager
24
+
25
+
26
+ class Worker(Plugin):
27
+ def on_start(self):
28
+ self.env_set("worker.ready", True)
29
+
30
+ def main(self):
31
+ pass
32
+
33
+
34
+ def main():
35
+ manager = PluginManager()
36
+ descriptor = Worker.Descriptor(
37
+ version="1.0.0",
38
+ author="Application team",
39
+ description="Example worker",
40
+ )
41
+ if not manager.load_plugin(descriptor):
42
+ raise RuntimeError("Plugin failed to load")
43
+ if not manager.start_plugin(descriptor.name):
44
+ raise RuntimeError("Plugin failed to start")
45
+ try:
46
+ time.sleep(0.1)
47
+ print(manager.env_get("worker.ready"))
48
+ finally:
49
+ manager.unload_plugin(descriptor.name)
50
+
51
+
52
+ if __name__ == "__main__":
53
+ main()
54
+ ```
55
+
56
+ ## Documentation
57
+
58
+ Read the [documentation index](docs/index.md) for installation, concepts,
59
+ API reference, usage patterns, and troubleshooting.
60
+
61
+ The complete runnable examples are in
62
+ [examples/](examples/). For example:
63
+
64
+ ```bash
65
+ python -m examples.example_pubsub
66
+ python -m examples.example_rpc_calls
67
+ ```
@@ -29,7 +29,7 @@ import threading
29
29
 
30
30
 
31
31
  if TYPE_CHECKING:
32
- from parallelazy.plugin.plugin_worker import PluginRPC
32
+ from parallelazy.plugin_rpc import PluginRPC
33
33
 
34
34
 
35
35
 
@@ -13,12 +13,12 @@ import torch.multiprocessing as mp
13
13
  import time
14
14
  from typing import Any, Dict, List, Optional
15
15
 
16
- from parallelazy.utils.utils import process_start_spawn
17
- from parallelazy.plugin.plugin_base import PluginDescriptor
18
- from parallelazy.plugin.plugin_rpc import PluginRPC, RequestEnvGetAll, RequestEnvUnsubscribe, RequestTopicAnnounce
19
- from parallelazy.plugin.plugin_worker import PluginWorker, Queue, RequestPluginCall, RequestTopicSubscribe, RequestTopicUnsubscribe
20
- from parallelazy.plugin.plugin_data import CommandType, ProcessStatus, RequestEnvGet, RequestEnvSet, RequestEnvSubscribe, PluginStatus, Subscriber
21
- from parallelazy.plugin.environment_manager import EnvironmentManager
16
+ from parallelazy.utils import process_start_spawn
17
+ from parallelazy.plugin import PluginDescriptor
18
+ from parallelazy.plugin_rpc import PluginRPC, RequestEnvGetAll, RequestEnvUnsubscribe, RequestTopicAnnounce
19
+ from parallelazy.plugin_worker import PluginWorker, Queue, RequestPluginCall, RequestTopicSubscribe, RequestTopicUnsubscribe
20
+ from parallelazy.plugin_data import CommandType, ProcessStatus, RequestEnvGet, RequestEnvSet, RequestEnvSubscribe, PluginStatus, Subscriber
21
+ from parallelazy.environment_manager import EnvironmentManager
22
22
 
23
23
 
24
24
  logger = logging.getLogger(__name__)
@@ -8,8 +8,8 @@ from torch import multiprocessing as mp
8
8
  import threading
9
9
  from concurrent.futures import ThreadPoolExecutor
10
10
  from multiprocessing.connection import wait
11
- from parallelazy.plugin.plugin_data import Channel, CommandType, Message, PendingRequest, Queue, Request, RequestCallback, RequestEnvGet, RequestEnvGetAll, RequestEnvSet, RequestEnvSubscribe, RequestEnvUnsubscribe, RequestEnvUpdate, RequestPluginCall, RequestPluginErrors, RequestPluginStart, RequestPluginStatus, RequestPluginStatusAll, RequestPluginStop, RequestTopicAnnounce, RequestTopicList, RequestTopicSubscribe, RequestTopicUnsubscribe, Response, Subscriber
12
- from parallelazy.plugin.plugin_transport import sanitize_for_ipc
11
+ from parallelazy.plugin_data import Channel, CommandType, Message, PendingRequest, Queue, Request, RequestCallback, RequestEnvGet, RequestEnvGetAll, RequestEnvSet, RequestEnvSubscribe, RequestEnvUnsubscribe, RequestEnvUpdate, RequestPluginCall, RequestPluginErrors, RequestPluginStart, RequestPluginStatus, RequestPluginStatusAll, RequestPluginStop, RequestTopicAnnounce, RequestTopicList, RequestTopicSubscribe, RequestTopicUnsubscribe, Response, Subscriber
12
+ from parallelazy.plugin_transport import sanitize_for_ipc
13
13
 
14
14
 
15
15
  logger = logging.getLogger(__name__)
@@ -3,7 +3,7 @@ from dataclasses import dataclass
3
3
  import logging
4
4
  from collections import OrderedDict
5
5
  import time
6
- from typing import Any, Dict, List, Optional
6
+ from typing import List, Optional
7
7
 
8
8
  import torch
9
9
  from torch import cuda
@@ -18,11 +18,11 @@ import threading
18
18
  import time
19
19
 
20
20
 
21
- from parallelazy.utils.utils import init_debugger, process_start_spawn
22
- from parallelazy.plugin.plugin_data import Channel, CommandType, Queue,QueueDescriptor, PendingRequest, PluginStatus, RequestPluginErrors, RequestPluginStart, RequestPluginStatus, RequestPluginStop, RequestTopicList, Subscriber, Subscription
23
- from parallelazy.plugin.plugin_base import Plugin, PluginDescriptor, PluginState
21
+ from parallelazy.utils import init_debugger, process_start_spawn
22
+ from parallelazy.plugin_data import Channel, CommandType, Queue,QueueDescriptor, PendingRequest, PluginStatus, RequestPluginErrors, RequestPluginStart, RequestPluginStatus, RequestPluginStop, RequestTopicList, Subscriber, Subscription
23
+ from parallelazy.plugin import Plugin, PluginDescriptor, PluginState
24
24
 
25
- from parallelazy.plugin.plugin_rpc import PluginRPC, RequestEnvUpdate, RequestPluginCall, RequestTopicList, RequestTopicSubscribe, RequestTopicUnsubscribe, sanitize_for_ipc
25
+ from parallelazy.plugin_rpc import PluginRPC, RequestEnvUpdate, RequestPluginCall, RequestTopicList, RequestTopicSubscribe, RequestTopicUnsubscribe, sanitize_for_ipc
26
26
  from multiprocessing.synchronize import Event
27
27
 
28
28
 
@@ -3,7 +3,7 @@ import os
3
3
  import re
4
4
  import socket
5
5
  import logging
6
- import multiprocessing as mp
6
+ import torch.multiprocessing as mp
7
7
  import warnings
8
8
 
9
9
  logger = logging.getLogger(__name__)
@@ -0,0 +1,82 @@
1
+ Metadata-Version: 2.4
2
+ Name: parallelazy
3
+ Version: 0.0.2
4
+ Summary: A lightweight multiprocess worker-plugin framework. Topic-based pub/sub, global enviroment, using process spawn and pipes, pytorch and CUDA ready.
5
+ Author: Cesare Montresor
6
+ Project-URL: Homepage, https://github.com/cesare-montresor/parallelazy
7
+ Project-URL: Repository, https://github.com/cesare-montresor/parallelazy
8
+ Project-URL: Issues, https://github.com/cesare-montresor/parallelazy/issues
9
+ Requires-Python: >=3.8
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: debugpy
13
+ Requires-Dist: torch
14
+ Dynamic: license-file
15
+
16
+ # parallelazy
17
+
18
+ A lightweight Python plugin/worker framework with:
19
+
20
+ - isolated plugin processes started with `spawn`;
21
+ - topic-based publish/subscribe;
22
+ - shared environment values and change notifications;
23
+ - plugin-to-plugin RPC; and
24
+ - PyTorch/CUDA-aware multiprocessing support.
25
+
26
+ ## Install
27
+
28
+ ```bash
29
+ python -m pip install .
30
+ ```
31
+
32
+ ## Quick start
33
+
34
+ ```python
35
+ import time
36
+
37
+ from parallelazy.plugin import Plugin
38
+ from parallelazy.plugin_manager import PluginManager
39
+
40
+
41
+ class Worker(Plugin):
42
+ def on_start(self):
43
+ self.env_set("worker.ready", True)
44
+
45
+ def main(self):
46
+ pass
47
+
48
+
49
+ def main():
50
+ manager = PluginManager()
51
+ descriptor = Worker.Descriptor(
52
+ version="1.0.0",
53
+ author="Application team",
54
+ description="Example worker",
55
+ )
56
+ if not manager.load_plugin(descriptor):
57
+ raise RuntimeError("Plugin failed to load")
58
+ if not manager.start_plugin(descriptor.name):
59
+ raise RuntimeError("Plugin failed to start")
60
+ try:
61
+ time.sleep(0.1)
62
+ print(manager.env_get("worker.ready"))
63
+ finally:
64
+ manager.unload_plugin(descriptor.name)
65
+
66
+
67
+ if __name__ == "__main__":
68
+ main()
69
+ ```
70
+
71
+ ## Documentation
72
+
73
+ Read the [documentation index](docs/index.md) for installation, concepts,
74
+ API reference, usage patterns, and troubleshooting.
75
+
76
+ The complete runnable examples are in
77
+ [examples/](examples/). For example:
78
+
79
+ ```bash
80
+ python -m examples.example_pubsub
81
+ python -m examples.example_rpc_calls
82
+ ```
@@ -0,0 +1,17 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ parallelazy/__init__.py
5
+ parallelazy/environment_manager.py
6
+ parallelazy/plugin.py
7
+ parallelazy/plugin_data.py
8
+ parallelazy/plugin_manager.py
9
+ parallelazy/plugin_rpc.py
10
+ parallelazy/plugin_transport.py
11
+ parallelazy/plugin_worker.py
12
+ parallelazy/utils.py
13
+ parallelazy.egg-info/PKG-INFO
14
+ parallelazy.egg-info/SOURCES.txt
15
+ parallelazy.egg-info/dependency_links.txt
16
+ parallelazy.egg-info/requires.txt
17
+ parallelazy.egg-info/top_level.txt
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "parallelazy"
7
- version = "0.0.1"
8
- description = "A lightweight multiprocess worker-plugin framework. Topic-based pub/sub, gloval enviroment, using process spawn and pipes, pytorch and CUDA ready."
7
+ version = "0.0.2"
8
+ description = "A lightweight multiprocess worker-plugin framework. Topic-based pub/sub, global enviroment, using process spawn and pipes, pytorch and CUDA ready."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
11
11
  authors = [
@@ -14,6 +14,7 @@ authors = [
14
14
 
15
15
  dependencies = [
16
16
  "debugpy",
17
+ "torch"
17
18
  ]
18
19
 
19
20
 
@@ -1,17 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: parallelazy
3
- Version: 0.0.1
4
- Summary: A lightweight multiprocess worker-plugin framework. Topic-based pub/sub, gloval enviroment, using process spawn and pipes, pytorch and CUDA ready.
5
- Author: Cesare Montresor
6
- Project-URL: Homepage, https://github.com/cesare-montresor/parallelazy
7
- Project-URL: Repository, https://github.com/cesare-montresor/parallelazy
8
- Project-URL: Issues, https://github.com/cesare-montresor/parallelazy/issues
9
- Requires-Python: >=3.8
10
- Description-Content-Type: text/markdown
11
- License-File: LICENSE
12
- Requires-Dist: debugpy
13
- Dynamic: license-file
14
-
15
- # parallelazy
16
-
17
- A python lightweight, plugin/worker framework, with topic-based pub/sub and shared env using spawn and pipes, pytorch and CUDA ready.
@@ -1,3 +0,0 @@
1
- # parallelazy
2
-
3
- A python lightweight, plugin/worker framework, with topic-based pub/sub and shared env using spawn and pipes, pytorch and CUDA ready.
File without changes
@@ -1,194 +0,0 @@
1
- """
2
- Configuration & Options Example: Plugin customization at load time.
3
-
4
- This example shows how plugins can:
5
- 1. Accept configuration options when loaded
6
- 2. Use options to customize behavior
7
- 3. Override configuration dynamically
8
- 4. Validate configuration options
9
- """
10
-
11
- import logging
12
- import time
13
- from typing import Any, Dict
14
-
15
- from parallelazy.plugin import Plugin, PluginDescriptor
16
- from parallelazy.plugin_worker import PluginWorker
17
- from parallelazy.plugin_manager import PluginManager
18
-
19
- logger = logging.getLogger(__name__)
20
-
21
-
22
- class Sensor(Plugin):
23
- """
24
- Plugin that simulates a sensor with configurable sampling.
25
- """
26
-
27
- @classmethod
28
- def Descriptor(cls, options: Dict[str, Any] = None) -> PluginDescriptor:
29
- default_options = {
30
- "sample_rate": 10, # Hz
31
- "noise_level": 0.1,
32
- "sensor_type": "temperature",
33
- }
34
- if options:
35
- default_options.update(options)
36
-
37
- return super().Descriptor(
38
- version="1.0.0",
39
- author="ModularNet Team",
40
- description="Configurable sensor plugin",
41
- options=default_options
42
- )
43
-
44
- def __init__(self, worker: PluginWorker, plugin_id: str, options: Dict[str, Any]):
45
- super().__init__(worker, plugin_id, options)
46
- self.sample_count = 0
47
- self.sample_rate = options.get("sample_rate", 10)
48
- self.noise_level = options.get("noise_level", 0.1)
49
- self.sensor_type = options.get("sensor_type", "temperature")
50
-
51
- def on_start(self) -> None:
52
- logger.info(f"[{self.plugin_id}] Sensor started with options:")
53
- logger.info(f" - type: {self.sensor_type}")
54
- logger.info(f" - sample_rate: {self.sample_rate} Hz")
55
- logger.info(f" - noise_level: {self.noise_level}")
56
- self.env_set("sensor.config", {
57
- "type": self.sensor_type,
58
- "sample_rate": self.sample_rate,
59
- "noise_level": self.noise_level
60
- })
61
- self.env_set("sensor.samples", 0)
62
-
63
- def main(self):
64
- self.sample_count += 1
65
- # Generate simulated sensor reading
66
- base_value = 20 + (self.sample_count % 10) # Temperature 20-30°C
67
- import random
68
- noise = random.gauss(0, self.noise_level)
69
- reading = base_value + noise
70
-
71
- if self.sample_count % 5 == 0:
72
- logger.info(f"[{self.plugin_id}] Sample #{self.sample_count}: {reading:.2f}")
73
- self.topic_publish("sensor.readings", {
74
- "sample": self.sample_count,
75
- "value": reading,
76
- "type": self.sensor_type
77
- })
78
- self.env_set("sensor.samples", self.sample_count, wait=False)
79
-
80
- def on_stop(self) -> None:
81
- logger.info(f"[{self.plugin_id}] Sensor stopped, collected {self.sample_count} samples")
82
-
83
-
84
- class SensorLogger(Plugin):
85
- """
86
- Plugin that logs sensor readings with configurable verbosity.
87
- """
88
-
89
- @classmethod
90
- def Descriptor(cls, options: Dict[str, Any] = None) -> PluginDescriptor:
91
- default_options = {
92
- "verbose": False,
93
- "log_every_n": 5,
94
- }
95
- if options:
96
- default_options.update(options)
97
-
98
- return super().Descriptor(
99
- version="1.0.0",
100
- author="ModularNet Team",
101
- description="Sensor logger with configurable output",
102
- options=default_options
103
- )
104
-
105
- def __init__(self, worker: PluginWorker, plugin_id: str, options: Dict[str, Any]):
106
- super().__init__(worker, plugin_id, options)
107
- self.verbose = options.get("verbose", False)
108
- self.log_every_n = options.get("log_every_n", 5)
109
- self.readings = []
110
-
111
- def on_start(self) -> None:
112
- logger.info(f"[{self.plugin_id}] SensorLogger started (verbose={self.verbose})")
113
- self.topic_subscribe("sensor.readings", self.on_reading)
114
-
115
- def on_reading(self, reading: Dict[str, Any]):
116
- self.readings.append(reading)
117
- if self.verbose:
118
- logger.info(f"[{self.plugin_id}] Received: {reading}")
119
- elif len(self.readings) % self.log_every_n == 0:
120
- avg_value = sum(r["value"] for r in self.readings) / len(self.readings)
121
- logger.info(f"[{self.plugin_id}] {len(self.readings)} readings, avg={avg_value:.2f}")
122
- self.env_set("logger.avg_value", avg_value, wait=False)
123
-
124
- def main(self):
125
- pass
126
-
127
- def on_stop(self) -> None:
128
- logger.info(f"[{self.plugin_id}] SensorLogger stopped, logged {len(self.readings)} readings")
129
-
130
-
131
- def main():
132
- """Run the configuration example."""
133
- manager = PluginManager()
134
-
135
- # Load sensor with custom options
136
- sensor_desc = Sensor.Descriptor(options={
137
- "sample_rate": 20,
138
- "noise_level": 0.5,
139
- "sensor_type": "humidity"
140
- })
141
-
142
- # Load logger with verbose mode
143
- logger_desc = SensorLogger.Descriptor(options={
144
- "verbose": False,
145
- "log_every_n": 3
146
- })
147
-
148
- manager.load_plugin(sensor_desc)
149
- manager.load_plugin(logger_desc)
150
-
151
- manager.start_plugin(sensor_desc.name)
152
- manager.start_plugin(logger_desc.name)
153
-
154
- print("Sensor and logger running... Press Ctrl+C to stop.")
155
- time.sleep(5)
156
- print("Stopping plugins...")
157
-
158
- manager.stop_plugin(logger_desc.name)
159
- manager.stop_plugin(sensor_desc.name)
160
-
161
- # Show configuration
162
- print("\nFinal state:")
163
- all_vars = manager.env_get()
164
- for name, value in all_vars.items():
165
- if name.startswith("sensor.") or name.startswith("logger."):
166
- print(f" {name}: {value}")
167
-
168
- # VERIFICATION
169
- print("\n=== VERIFICATION ===")
170
- print("PREDICTED BEHAVIOR:")
171
- print("1. Sensor loads with custom options (sample_rate=20, noise_level=0.5, type=humidity)")
172
- print("2. Logger loads with verbose=False, log_every_n=3")
173
- print("3. Sensor publishes readings, logger subscribes and aggregates")
174
- print("4. Config persists in environment\n")
175
-
176
- sensor_config = all_vars.get("sensor.config")
177
- logger_avg = all_vars.get("logger.avg_value")
178
-
179
- assert sensor_config is not None, "sensor.config should be set"
180
- assert sensor_config.get("type") == "humidity", f"Sensor type should be humidity, got {sensor_config.get('type')}"
181
- assert sensor_config.get("sample_rate") == 20, f"Sample rate should be 20, got {sensor_config.get('sample_rate')}"
182
- assert sensor_config.get("noise_level") == 0.5, f"Noise level should be 0.5, got {sensor_config.get('noise_level')}"
183
-
184
- print(f"✓ Sensor config: type={sensor_config['type']}, rate={sensor_config['sample_rate']}Hz, noise={sensor_config['noise_level']}")
185
- if logger_avg is not None:
186
- print(f"✓ Logger computed average: {logger_avg:.2f}")
187
- print("✓ All configuration assertions passed!")
188
-
189
- manager.unload_plugin(sensor_desc.name)
190
- manager.unload_plugin(logger_desc.name)
191
-
192
-
193
- if __name__ == "__main__":
194
- main()
@@ -1,84 +0,0 @@
1
- """
2
- Basic test plugin for lifecycle testing.
3
-
4
- A minimal plugin that exercises the load/unload/start/stop/status lifecycle
5
- without any external dependencies.
6
- """
7
-
8
- import logging
9
- from typing import Any, Dict
10
-
11
- from parallelazy.plugin import Plugin, PluginDescriptor
12
- from parallelazy.plugin_worker import PluginWorker
13
- import time
14
- from parallelazy.plugin_manager import PluginManager
15
-
16
-
17
-
18
- logger = logging.getLogger(__name__)
19
-
20
- class ExamplePluginCount(Plugin):
21
- """
22
- Minimal test plugin that exercises core lifecycle.
23
-
24
- Features:
25
- - Simple on_start/on_stop implementation
26
- - Tracks call count
27
- - Can be used to verify manager lifecycle
28
- """
29
-
30
- @classmethod
31
- def Descriptor(cls, options: Dict[str, Any] = None) -> PluginDescriptor:
32
- """Create plugin descriptor."""
33
- return super().Descriptor(
34
- version="1.0.0",
35
- author="ModularNet Team",
36
- description="Basic test plugin for lifecycle verification",
37
- options=options or {}
38
- )
39
-
40
- def __init__(
41
- self,
42
- worker: PluginWorker,
43
- plugin_id: str,
44
- options: Dict[str, Any],
45
- ):
46
- super().__init__(worker, plugin_id, options)
47
- self.count = None
48
-
49
- def main(self):
50
- self.count +=1
51
- self.env_set("count", self.count, wait=False)
52
-
53
-
54
- def on_start(self) -> None:
55
- logger.info(f"[{self.plugin_id}] ExamplePluginCount starting...")
56
- self.count = 0
57
- self.env_set("count", self.count)
58
-
59
- def on_stop(self) -> None:
60
- logger.info(f"[{self.plugin_id}] Total loop: {self.count}")
61
- self.env_set("count", self.count)
62
-
63
-
64
- def main():
65
- """Example main function to run the plugin standalone for testing."""
66
- manager = PluginManager()
67
- descriptor = ExamplePluginCount.Descriptor()
68
- manager.load_plugin(descriptor)
69
- manager.start_plugin(descriptor.name)
70
-
71
- # Let it run for a few seconds
72
- time.sleep(3)
73
-
74
-
75
- manager.unload_plugin(descriptor.name)
76
-
77
- all_vars = manager.env_get()
78
-
79
- print("All environment variables:")
80
- for name, value in all_vars.items():
81
- print(f" {name}: {value}")
82
-
83
- if __name__ == "__main__": main()
84
-