leaf-framework 0.10.1__tar.gz → 0.10.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 (104) hide show
  1. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/PKG-INFO +1 -1
  2. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/phase_modules/measure.py +63 -16
  3. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/pyproject.toml +1 -1
  4. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/LICENSE +0 -0
  5. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/README.md +0 -0
  6. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/__init__.py +0 -0
  7. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/adapters/__init__.py +0 -0
  8. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/adapters/core_adapters/__init__.py +0 -0
  9. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/adapters/core_adapters/continuous_experiment_adapter.py +0 -0
  10. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/adapters/core_adapters/discrete_experiment_adapter.py +0 -0
  11. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/adapters/core_adapters/upload_adapter.py +0 -0
  12. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/adapters/equipment_adapter.py +0 -0
  13. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/config/configuration.yaml +0 -0
  14. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/data/marketplace.yaml +0 -0
  15. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/error_handler/__init__.py +0 -0
  16. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/error_handler/error_holder.py +0 -0
  17. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/error_handler/exceptions.py +0 -0
  18. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/measurement_handler/__init__.py +0 -0
  19. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/measurement_handler/handler.py +0 -0
  20. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/measurement_handler/measurements.yaml +0 -0
  21. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/measurement_handler/terms.py +0 -0
  22. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/.gitkeep +0 -0
  23. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/__init__.py +0 -0
  24. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/input_modules/__init__.py +0 -0
  25. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/input_modules/ble_watcher.py +0 -0
  26. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/input_modules/db_watcher.py +0 -0
  27. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/input_modules/event_watcher.py +0 -0
  28. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/input_modules/external_api_watcher.py +0 -0
  29. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/input_modules/external_event_watcher.py +0 -0
  30. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/input_modules/file_watcher.py +0 -0
  31. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/input_modules/http_watcher.py +0 -0
  32. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/input_modules/modbus_watcher.py +0 -0
  33. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/input_modules/mqtt_external_event_watcher.py +0 -0
  34. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/input_modules/mqtt_watcher.py +0 -0
  35. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/input_modules/opc_watcher.py +0 -0
  36. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/input_modules/polling_watcher.py +0 -0
  37. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/input_modules/simple_watcher.py +0 -0
  38. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/measurement_modules/__init__.py +0 -0
  39. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/measurement_modules/carbon_dioxide.py +0 -0
  40. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/measurement_modules/dissolved_oxygen.py +0 -0
  41. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/measurement_modules/fluorescence.py +0 -0
  42. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/measurement_modules/measurement_module.py +0 -0
  43. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/measurement_modules/optical_density.py +0 -0
  44. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/measurement_modules/ph.py +0 -0
  45. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/measurement_modules/temperature.py +0 -0
  46. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/output_modules/__init__.py +0 -0
  47. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/output_modules/file.py +0 -0
  48. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/output_modules/keydb.py +0 -0
  49. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/output_modules/mqtt.py +0 -0
  50. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/output_modules/output_module.py +0 -0
  51. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/output_modules/sql.py +0 -0
  52. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/output_modules/topic_store.py +0 -0
  53. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/phase_modules/__init__.py +0 -0
  54. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/phase_modules/control.py +0 -0
  55. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/phase_modules/error.py +0 -0
  56. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/phase_modules/external_event_phase.py +0 -0
  57. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/phase_modules/initialisation.py +0 -0
  58. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/phase_modules/phase.py +0 -0
  59. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/phase_modules/start.py +0 -0
  60. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/phase_modules/stop.py +0 -0
  61. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/process_modules/__init__.py +0 -0
  62. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/process_modules/continous_module.py +0 -0
  63. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/process_modules/discrete_module.py +0 -0
  64. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/process_modules/external_event_process.py +0 -0
  65. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/process_modules/process_module.py +0 -0
  66. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/modules/process_modules/upload_module.py +0 -0
  67. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/register/__init__.py +0 -0
  68. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/register/abstract_leaf.py +0 -0
  69. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/register/equipment_actions.yaml +0 -0
  70. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/register/equipment_data.yaml +0 -0
  71. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/register/metadata.py +0 -0
  72. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/register/py.typed +0 -0
  73. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/register/topic_utilities.py +0 -0
  74. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/registry/discovery.py +0 -0
  75. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/registry/loader.py +0 -0
  76. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/registry/registry.py +0 -0
  77. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/registry/utils.py +0 -0
  78. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/start.py +0 -0
  79. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/__init__.py +0 -0
  80. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/adapter_ui_extension.py +0 -0
  81. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/components/__init__.py +0 -0
  82. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/components/header.py +0 -0
  83. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/constants.py +0 -0
  84. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/desktop_launcher.py +0 -0
  85. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/images/icon.icns +0 -0
  86. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/images/icon.ico +0 -0
  87. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/images/icon.svg +0 -0
  88. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/interface.py +0 -0
  89. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/markdown/configuration_help.md +0 -0
  90. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/markdown/documentation_main.md +0 -0
  91. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/markdown/documentation_protips.md +0 -0
  92. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/scripts.js +0 -0
  93. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/styles.css +0 -0
  94. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/tabs/__init__.py +0 -0
  95. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/tabs/adapters.py +0 -0
  96. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/tabs/configuration.py +0 -0
  97. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/tabs/documentation.py +0 -0
  98. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/tabs/logs.py +0 -0
  99. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/tabs/monitoring.py +0 -0
  100. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/ui/utils.py +0 -0
  101. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/utility/config_utils.py +0 -0
  102. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/utility/logger/__init__.py +0 -0
  103. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/utility/logger/logger_utils.py +0 -0
  104. {leaf_framework-0.10.1 → leaf_framework-0.10.2}/leaf/utility/running_utilities.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: leaf-framework
3
- Version: 0.10.1
3
+ Version: 0.10.2
4
4
  Summary: Lightweight Adapter Framework (LEAF)
5
5
  License: Apache-2.0
6
6
  License-File: LICENSE
@@ -94,11 +94,11 @@ class MeasurePhase(PhaseModule):
94
94
  for index, chunk in enumerate(chunks):
95
95
  if index % 10 == 0:
96
96
  logger.debug(f"Sending chunk {index + 1} of {len(chunks)} with {len(chunk)} measurements.")
97
- messages.append(self._form_message(exp_id, chunk))
97
+ messages.extend(self._form_message(exp_id, chunk))
98
98
  time.sleep(0.1)
99
99
  return messages
100
100
  else:
101
- return [self._form_message(exp_id, result)]
101
+ return self._form_message(exp_id, result)
102
102
  else:
103
103
  experiment_id = kwargs.get("experiment_id", "unknown")
104
104
  measurement = kwargs.get("measurement", "unknown")
@@ -106,28 +106,75 @@ class MeasurePhase(PhaseModule):
106
106
  action = self._term_builder(experiment_id=experiment_id, measurement=measurement)
107
107
  return [(action, data)]
108
108
 
109
- def _form_message(self, experiment_id: str, result: Any) -> tuple:
109
+ def _form_message(self, experiment_id: str, result: Any) -> list[tuple]:
110
110
  """
111
- Formulate a message with the experiment ID and result.
111
+ Formulate one or more (topic, data) messages for a measurement result.
112
+
113
+ A list/set of points can mix several distinct measurement types
114
+ (e.g. pH, temperature, oxygen) in the same batch. Since the topic
115
+ encodes a single measurement type, each distinct type present in
116
+ the batch is split out into its own message rather than all being
117
+ published under whichever type happened to come first.
112
118
 
113
119
  Args:
114
120
  experiment_id (str): The ID of the experiment.
115
121
  result (Any): The measurement result data.
116
122
 
117
123
  Returns:
118
- tuple: A tuple containing the action and result.
124
+ list[tuple]: A list of (action, result) tuples.
119
125
  """
120
- measurement = "unknown"
121
126
  if isinstance(result, dict):
122
- measurement = result.get("measurement", "unknown")
123
- elif isinstance(result, InfluxPoint):
127
+ measurement = self._resolve_measurement(result)
128
+ action = self._term_builder(experiment_id=experiment_id, measurement=measurement)
129
+ return [(action, result)]
130
+
131
+ if isinstance(result, InfluxPoint):
124
132
  result = result.to_json()
125
- measurement = result.get("measurement", "unknown")
126
- elif isinstance(result, list):
127
- result = [l.to_json() if isinstance(l, InfluxPoint) else l for l in result]
128
- else:
129
- excp = AdapterLogicError(f"Unknown measurement data type: {type(result)}")
130
- self._handle_exception(excp)
133
+ measurement = self._resolve_measurement(result)
134
+ action = self._term_builder(experiment_id=experiment_id, measurement=measurement)
135
+ return [(action, result)]
136
+
137
+ if isinstance(result, list):
138
+ converted = []
139
+ for item in result:
140
+ if isinstance(item, InfluxPoint):
141
+ converted.append(item.to_json())
142
+ else:
143
+ converted.append(item)
144
+
145
+ groups: dict[str, list] = {}
146
+ for item in converted:
147
+ if isinstance(item, dict):
148
+ key = self._resolve_measurement(item)
149
+ else:
150
+ key = "unknown"
151
+ groups.setdefault(key, []).append(item)
152
+
153
+ messages = []
154
+ for key, group in groups.items():
155
+ action = self._term_builder(experiment_id=experiment_id, measurement=key)
156
+ messages.append((action, group))
157
+ return messages
158
+
159
+ excp = AdapterLogicError(f"Unknown measurement data type: {type(result)}")
160
+ self._handle_exception(excp)
161
+ return []
162
+
163
+ def _resolve_measurement(self, item: dict) -> str:
164
+ """
165
+ Resolve the measurement label used for the topic's last segment.
166
+
167
+ Prefers the "metric" tag (e.g. "temperature", "ph") over the
168
+ top-level "measurement" field, since adapters commonly set
169
+ "measurement" to a constant device/point type shared by every
170
+ point (e.g. all Pioreactor points use "pioreactor"), while the
171
+ "metric" tag is what actually distinguishes one point from another.
172
+ """
173
+ tags = item.get("tags")
174
+ if isinstance(tags, dict) and tags.get("metric"):
175
+ return tags["metric"]
176
+
177
+ if item.get("measurement"):
178
+ return item["measurement"]
131
179
 
132
- action = self._term_builder(experiment_id=experiment_id, measurement=measurement)
133
- return (action, result)
180
+ return "unknown"
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "leaf-framework"
3
- version = "0.10.1"
3
+ version = "0.10.2"
4
4
  description = "Lightweight Adapter Framework (LEAF)"
5
5
  authors = [
6
6
  "Matthew Crowther <nmc215@ncl.ac.uk>",
File without changes