leaf-framework 0.9.3__tar.gz → 0.9.5__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.9.3 → leaf_framework-0.9.5}/PKG-INFO +1 -1
  2. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/desktop_launcher.py +40 -5
  3. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/pyproject.toml +1 -1
  4. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/LICENSE +0 -0
  5. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/README.md +0 -0
  6. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/__init__.py +0 -0
  7. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/adapters/__init__.py +0 -0
  8. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/adapters/core_adapters/__init__.py +0 -0
  9. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/adapters/core_adapters/continuous_experiment_adapter.py +0 -0
  10. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/adapters/core_adapters/discrete_experiment_adapter.py +0 -0
  11. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/adapters/core_adapters/upload_adapter.py +0 -0
  12. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/adapters/equipment_adapter.py +0 -0
  13. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/config/configuration.yaml +0 -0
  14. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/data/marketplace.yaml +0 -0
  15. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/error_handler/__init__.py +0 -0
  16. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/error_handler/error_holder.py +0 -0
  17. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/error_handler/exceptions.py +0 -0
  18. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/measurement_handler/__init__.py +0 -0
  19. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/measurement_handler/handler.py +0 -0
  20. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/measurement_handler/measurements.yaml +0 -0
  21. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/measurement_handler/terms.py +0 -0
  22. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/.gitkeep +0 -0
  23. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/__init__.py +0 -0
  24. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/input_modules/__init__.py +0 -0
  25. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/input_modules/ble_watcher.py +0 -0
  26. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/input_modules/db_watcher.py +0 -0
  27. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/input_modules/event_watcher.py +0 -0
  28. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/input_modules/external_api_watcher.py +0 -0
  29. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/input_modules/external_event_watcher.py +0 -0
  30. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/input_modules/file_watcher.py +0 -0
  31. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/input_modules/http_watcher.py +0 -0
  32. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/input_modules/modbus_watcher.py +0 -0
  33. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/input_modules/mqtt_external_event_watcher.py +0 -0
  34. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/input_modules/mqtt_watcher.py +0 -0
  35. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/input_modules/opc_watcher.py +0 -0
  36. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/input_modules/polling_watcher.py +0 -0
  37. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/input_modules/simple_watcher.py +0 -0
  38. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/measurement_modules/__init__.py +0 -0
  39. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/measurement_modules/carbon_dioxide.py +0 -0
  40. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/measurement_modules/dissolved_oxygen.py +0 -0
  41. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/measurement_modules/fluorescence.py +0 -0
  42. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/measurement_modules/measurement_module.py +0 -0
  43. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/measurement_modules/optical_density.py +0 -0
  44. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/measurement_modules/ph.py +0 -0
  45. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/measurement_modules/temperature.py +0 -0
  46. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/output_modules/__init__.py +0 -0
  47. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/output_modules/file.py +0 -0
  48. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/output_modules/keydb.py +0 -0
  49. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/output_modules/mqtt.py +0 -0
  50. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/output_modules/output_module.py +0 -0
  51. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/output_modules/sql.py +0 -0
  52. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/output_modules/topic_store.py +0 -0
  53. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/phase_modules/__init__.py +0 -0
  54. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/phase_modules/control.py +0 -0
  55. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/phase_modules/error.py +0 -0
  56. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/phase_modules/external_event_phase.py +0 -0
  57. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/phase_modules/initialisation.py +0 -0
  58. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/phase_modules/measure.py +0 -0
  59. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/phase_modules/phase.py +0 -0
  60. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/phase_modules/start.py +0 -0
  61. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/phase_modules/stop.py +0 -0
  62. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/process_modules/__init__.py +0 -0
  63. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/process_modules/continous_module.py +0 -0
  64. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/process_modules/discrete_module.py +0 -0
  65. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/process_modules/external_event_process.py +0 -0
  66. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/process_modules/process_module.py +0 -0
  67. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/modules/process_modules/upload_module.py +0 -0
  68. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/register/__init__.py +0 -0
  69. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/register/abstract_leaf.py +0 -0
  70. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/register/equipment_actions.yaml +0 -0
  71. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/register/equipment_data.yaml +0 -0
  72. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/register/metadata.py +0 -0
  73. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/register/py.typed +0 -0
  74. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/register/topic_utilities.py +0 -0
  75. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/registry/discovery.py +0 -0
  76. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/registry/loader.py +0 -0
  77. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/registry/registry.py +0 -0
  78. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/registry/utils.py +0 -0
  79. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/start.py +0 -0
  80. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/__init__.py +0 -0
  81. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/adapter_ui_extension.py +0 -0
  82. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/components/__init__.py +0 -0
  83. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/components/header.py +0 -0
  84. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/constants.py +0 -0
  85. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/images/icon.icns +0 -0
  86. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/images/icon.ico +0 -0
  87. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/images/icon.svg +0 -0
  88. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/interface.py +0 -0
  89. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/markdown/configuration_help.md +0 -0
  90. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/markdown/documentation_main.md +0 -0
  91. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/markdown/documentation_protips.md +0 -0
  92. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/scripts.js +0 -0
  93. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/styles.css +0 -0
  94. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/tabs/__init__.py +0 -0
  95. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/tabs/adapters.py +0 -0
  96. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/tabs/configuration.py +0 -0
  97. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/tabs/documentation.py +0 -0
  98. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/tabs/logs.py +0 -0
  99. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/tabs/monitoring.py +0 -0
  100. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/ui/utils.py +0 -0
  101. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/utility/config_utils.py +0 -0
  102. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/utility/logger/__init__.py +0 -0
  103. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/leaf/utility/logger/logger_utils.py +0 -0
  104. {leaf_framework-0.9.3 → leaf_framework-0.9.5}/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.9.3
3
+ Version: 0.9.5
4
4
  Summary: Lightweight Adapter Framework (LEAF)
5
5
  License: Apache-2.0
6
6
  License-File: LICENSE
@@ -23,6 +23,28 @@ except ImportError:
23
23
  logger.warning("tkinter not available - desktop GUI will not be available")
24
24
 
25
25
 
26
+ def _init_x11_threads() -> None:
27
+ """Tell Xlib this process is multi-threaded, before it ever touches X11.
28
+
29
+ LEAF always has other threads running by the time this GUI starts (the
30
+ NiceGUI web server thread, adapter/simulation threads -- see start.py),
31
+ even though none of them are meant to touch Tk/X11 directly. Xlib is
32
+ documented as requiring XInitThreads() to be called before its first
33
+ use in any process that is multi-threaded at all, regardless of which
34
+ thread actually issues X calls; skipping it is exactly what produces
35
+ "Unknown sequence number ... XInitThreads has not been called" xcb
36
+ aborts on Linux. No equivalent exists on macOS (Cocoa) or Windows.
37
+ """
38
+ if not sys.platform.startswith("linux"):
39
+ return
40
+ try:
41
+ import ctypes
42
+
43
+ ctypes.CDLL("libX11.so.6").XInitThreads()
44
+ except Exception as e:
45
+ logger.debug(f"Could not call XInitThreads: {e}")
46
+
47
+
26
48
  def is_desktop_environment() -> bool:
27
49
  """
28
50
  Detect if we're running in a desktop environment.
@@ -82,6 +104,7 @@ class LeafDesktopLauncher:
82
104
  self.is_running = True
83
105
 
84
106
  # Create main window
107
+ _init_x11_threads()
85
108
  self.root = tk.Tk()
86
109
  self.root.title("LEAF - Lightweight Equipment Adapter Framework")
87
110
  self.root.geometry("500x350")
@@ -281,6 +304,7 @@ class LeafDesktopLauncher:
281
304
 
282
305
  # Call the stop callback in a separate thread
283
306
  if self.on_stop_callback:
307
+ stop_finished = threading.Event()
284
308
 
285
309
  def stop_thread():
286
310
  try:
@@ -288,13 +312,24 @@ class LeafDesktopLauncher:
288
312
  except Exception as e:
289
313
  logger.error(f"Error in stop callback: {e}")
290
314
  finally:
291
- # Close the window after stopping
292
- try:
293
- self.root.after(1000, self.root.destroy)
294
- except Exception:
295
- pass
315
+ stop_finished.set()
296
316
 
297
317
  threading.Thread(target=stop_thread, daemon=True).start()
318
+
319
+ # Tk/Tcl calls (root.after, root.destroy) must only ever happen
320
+ # on the main thread that's running mainloop() -- on Linux,
321
+ # Xlib can abort the whole process ("XInitThreads has not been
322
+ # called") if a background thread issues X11 calls concurrently
323
+ # with it. Polling here (itself scheduled via root.after, so it
324
+ # always runs on the main thread) instead of destroying directly
325
+ # from stop_thread keeps every Tk call on that one thread.
326
+ def wait_and_destroy():
327
+ if stop_finished.is_set():
328
+ self.root.destroy()
329
+ else:
330
+ self.root.after(100, wait_and_destroy)
331
+
332
+ self.root.after(1000, wait_and_destroy)
298
333
  else:
299
334
  # If no callback, just close
300
335
  self.root.after(500, self.root.destroy)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "leaf-framework"
3
- version = "0.9.3"
3
+ version = "0.9.5"
4
4
  description = "Lightweight Adapter Framework (LEAF)"
5
5
  authors = [
6
6
  "Matthew Crowther <nmc215@ncl.ac.uk>",
File without changes
File without changes