auto-trainer-core 2.0.3__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 (97) hide show
  1. auto_trainer_core-2.0.3/PKG-INFO +17 -0
  2. auto_trainer_core-2.0.3/README.md +28 -0
  3. auto_trainer_core-2.0.3/pyproject.toml +44 -0
  4. auto_trainer_core-2.0.3/setup.cfg +4 -0
  5. auto_trainer_core-2.0.3/src/auto_trainer_core.egg-info/PKG-INFO +17 -0
  6. auto_trainer_core-2.0.3/src/auto_trainer_core.egg-info/SOURCES.txt +95 -0
  7. auto_trainer_core-2.0.3/src/auto_trainer_core.egg-info/dependency_links.txt +1 -0
  8. auto_trainer_core-2.0.3/src/auto_trainer_core.egg-info/requires.txt +13 -0
  9. auto_trainer_core-2.0.3/src/auto_trainer_core.egg-info/top_level.txt +1 -0
  10. auto_trainer_core-2.0.3/src/autotrainer/core/__init__.py +319 -0
  11. auto_trainer_core-2.0.3/src/autotrainer/core/analysis/__init__.py +6 -0
  12. auto_trainer_core-2.0.3/src/autotrainer/core/analysis/alarm_monitor.py +484 -0
  13. auto_trainer_core-2.0.3/src/autotrainer/core/analysis/audio_spectrum_data.py +27 -0
  14. auto_trainer_core-2.0.3/src/autotrainer/core/analysis/audio_spectrum_monitor.py +134 -0
  15. auto_trainer_core-2.0.3/src/autotrainer/core/analysis/auto_tunnel_fan_monitor.py +92 -0
  16. auto_trainer_core-2.0.3/src/autotrainer/core/analysis/detector.py +179 -0
  17. auto_trainer_core-2.0.3/src/autotrainer/core/analysis/external_doors_monitor.py +124 -0
  18. auto_trainer_core-2.0.3/src/autotrainer/core/analysis/global_animal_presence_monitor.py +69 -0
  19. auto_trainer_core-2.0.3/src/autotrainer/core/analysis/head_fix_measurement.py +15 -0
  20. auto_trainer_core-2.0.3/src/autotrainer/core/analysis/headbar_pressure_monitor.py +158 -0
  21. auto_trainer_core-2.0.3/src/autotrainer/core/analysis/load_cell_monitor.py +377 -0
  22. auto_trainer_core-2.0.3/src/autotrainer/core/analysis/load_cell_tare_monitor.py +217 -0
  23. auto_trainer_core-2.0.3/src/autotrainer/core/analysis/measurement_data.py +80 -0
  24. auto_trainer_core-2.0.3/src/autotrainer/core/analysis/pellet_position_monitor.py +108 -0
  25. auto_trainer_core-2.0.3/src/autotrainer/core/analysis/sensor_analysis.py +390 -0
  26. auto_trainer_core-2.0.3/src/autotrainer/core/analysis/system_fault_monitor.py +81 -0
  27. auto_trainer_core-2.0.3/src/autotrainer/core/analysis/system_maintenance_monitor.py +88 -0
  28. auto_trainer_core-2.0.3/src/autotrainer/core/animal/__init__.py +1 -0
  29. auto_trainer_core-2.0.3/src/autotrainer/core/animal/animal_subject.py +208 -0
  30. auto_trainer_core-2.0.3/src/autotrainer/core/capture.py +25 -0
  31. auto_trainer_core-2.0.3/src/autotrainer/core/configuration/__init__.py +88 -0
  32. auto_trainer_core-2.0.3/src/autotrainer/core/configuration/alarm_configuration.py +55 -0
  33. auto_trainer_core-2.0.3/src/autotrainer/core/configuration/animal_presence_configuration.py +17 -0
  34. auto_trainer_core-2.0.3/src/autotrainer/core/configuration/behavior_configuration.py +323 -0
  35. auto_trainer_core-2.0.3/src/autotrainer/core/configuration/camera_configuration.py +108 -0
  36. auto_trainer_core-2.0.3/src/autotrainer/core/configuration/external_doors_monitor_configuration.py +9 -0
  37. auto_trainer_core-2.0.3/src/autotrainer/core/configuration/hardware_configuration.py +30 -0
  38. auto_trainer_core-2.0.3/src/autotrainer/core/configuration/inference_configuration.py +26 -0
  39. auto_trainer_core-2.0.3/src/autotrainer/core/configuration/load_cell_config.py +61 -0
  40. auto_trainer_core-2.0.3/src/autotrainer/core/configuration/persistence_configuration.py +29 -0
  41. auto_trainer_core-2.0.3/src/autotrainer/core/configuration/presence_detection_configuration.py +9 -0
  42. auto_trainer_core-2.0.3/src/autotrainer/core/configuration/system_configuration.py +211 -0
  43. auto_trainer_core-2.0.3/src/autotrainer/core/configuration/system_fault_config.py +9 -0
  44. auto_trainer_core-2.0.3/src/autotrainer/core/configuration/system_maintenance_config.py +17 -0
  45. auto_trainer_core-2.0.3/src/autotrainer/core/diamond_triangle_config.py +150 -0
  46. auto_trainer_core-2.0.3/src/autotrainer/core/event/__init__.py +54 -0
  47. auto_trainer_core-2.0.3/src/autotrainer/core/event/api_event_kind.py +5 -0
  48. auto_trainer_core-2.0.3/src/autotrainer/core/event/api_event_plugin.py +57 -0
  49. auto_trainer_core-2.0.3/src/autotrainer/core/event/event_info.py +53 -0
  50. auto_trainer_core-2.0.3/src/autotrainer/core/event/event_manager.py +296 -0
  51. auto_trainer_core-2.0.3/src/autotrainer/core/event/event_manager_plugin.py +45 -0
  52. auto_trainer_core-2.0.3/src/autotrainer/core/event/file_event_plugin.py +91 -0
  53. auto_trainer_core-2.0.3/src/autotrainer/core/event/logger_event_plugin.py +43 -0
  54. auto_trainer_core-2.0.3/src/autotrainer/core/fixed_array_multiqueue.py +263 -0
  55. auto_trainer_core-2.0.3/src/autotrainer/core/fixed_array_queue.py +124 -0
  56. auto_trainer_core-2.0.3/src/autotrainer/core/frame_index.py +34 -0
  57. auto_trainer_core-2.0.3/src/autotrainer/core/interfaces.py +347 -0
  58. auto_trainer_core-2.0.3/src/autotrainer/core/logging.py +714 -0
  59. auto_trainer_core-2.0.3/src/autotrainer/core/message/__init__.py +26 -0
  60. auto_trainer_core-2.0.3/src/autotrainer/core/message/audio_spectrum_message.py +21 -0
  61. auto_trainer_core-2.0.3/src/autotrainer/core/message/measurement_message.py +61 -0
  62. auto_trainer_core-2.0.3/src/autotrainer/core/message/message_handler.py +158 -0
  63. auto_trainer_core-2.0.3/src/autotrainer/core/message/motor_configuration_message.py +128 -0
  64. auto_trainer_core-2.0.3/src/autotrainer/core/message/system_command_kind.py +74 -0
  65. auto_trainer_core-2.0.3/src/autotrainer/core/message/system_message_handler.py +122 -0
  66. auto_trainer_core-2.0.3/src/autotrainer/core/message/system_status_message.py +112 -0
  67. auto_trainer_core-2.0.3/src/autotrainer/core/multiproc.py +50 -0
  68. auto_trainer_core-2.0.3/src/autotrainer/core/notification/__init__.py +2 -0
  69. auto_trainer_core-2.0.3/src/autotrainer/core/notification/notification_center.py +80 -0
  70. auto_trainer_core-2.0.3/src/autotrainer/core/notification/trigger_notification.py +27 -0
  71. auto_trainer_core-2.0.3/src/autotrainer/core/observable_object.py +105 -0
  72. auto_trainer_core-2.0.3/src/autotrainer/core/perf_monitor.py +77 -0
  73. auto_trainer_core-2.0.3/src/autotrainer/core/pose_elements.py +196 -0
  74. auto_trainer_core-2.0.3/src/autotrainer/core/project/__init__.py +19 -0
  75. auto_trainer_core-2.0.3/src/autotrainer/core/project/project_info.py +486 -0
  76. auto_trainer_core-2.0.3/src/autotrainer/core/queue_util.py +60 -0
  77. auto_trainer_core-2.0.3/src/autotrainer/core/reach_event.py +45 -0
  78. auto_trainer_core-2.0.3/src/autotrainer/core/video_detection.py +124 -0
  79. auto_trainer_core-2.0.3/tests/alarm_config_test.py +19 -0
  80. auto_trainer_core-2.0.3/tests/animal_config_test.py +37 -0
  81. auto_trainer_core-2.0.3/tests/audio_spectrum_monitor_test.py +84 -0
  82. auto_trainer_core-2.0.3/tests/event_manager_test.py +90 -0
  83. auto_trainer_core-2.0.3/tests/fixed_array_queue_test.py +179 -0
  84. auto_trainer_core-2.0.3/tests/fixtures/pressure_threshold_sample.csv +11343 -0
  85. auto_trainer_core-2.0.3/tests/fixtures/v0_config.yaml +77 -0
  86. auto_trainer_core-2.0.3/tests/fixtures/v1_config.yaml +87 -0
  87. auto_trainer_core-2.0.3/tests/frame_index_test.py +47 -0
  88. auto_trainer_core-2.0.3/tests/load_cell_monitor_test.py +148 -0
  89. auto_trainer_core-2.0.3/tests/load_cell_tare_monitor_test.py +87 -0
  90. auto_trainer_core-2.0.3/tests/mocks/__init__.py +1 -0
  91. auto_trainer_core-2.0.3/tests/mocks/mock_event_plugin.py +29 -0
  92. auto_trainer_core-2.0.3/tests/offset3d_test.py +216 -0
  93. auto_trainer_core-2.0.3/tests/pose_elements_test.py +12 -0
  94. auto_trainer_core-2.0.3/tests/pressure_threshold_test.py +57 -0
  95. auto_trainer_core-2.0.3/tests/project_info_test.py +155 -0
  96. auto_trainer_core-2.0.3/tests/system_configuration_test.py +307 -0
  97. auto_trainer_core-2.0.3/tests/system_data_args_kwargs_test.py +7 -0
@@ -0,0 +1,17 @@
1
+ Metadata-Version: 2.1
2
+ Name: auto-trainer-core
3
+ Version: 2.0.3
4
+ Summary: Core objects and implementations for autotrainer
5
+ License: MIT
6
+ Requires-Python: >=3.8
7
+ Requires-Dist: auto-trainer-api==0.9.17
8
+ Requires-Dist: verboselogs<2,>=1.7
9
+ Requires-Dist: coloredlogs<16,>=15
10
+ Requires-Dist: events<1,>=0.5
11
+ Requires-Dist: transitions<1,>=0.9.2
12
+ Requires-Dist: psutil<8,>=7
13
+ Requires-Dist: numpy<2,>=1.23.5
14
+ Requires-Dist: pyhumps<4,>=3.8
15
+ Requires-Dist: pyyaml<7,>=6.0.2
16
+ Requires-Dist: importlib-resources; python_version < "3.10"
17
+ Requires-Dist: importlib-metadata; python_version < "3.10"
@@ -0,0 +1,28 @@
1
+ # Autotrainer - Core
2
+
3
+ This is the base module for functions and objects that used across most or all modules and applications.
4
+
5
+ Major Elements
6
+ * Observable object implementation
7
+ * Common Protocols used to bridge different modules
8
+ * General pub-sub notification hub implementation
9
+ * Event manager for structured application event recording
10
+ * Enhanced multiprocessing shared array behavior
11
+ * General "project" and animal subject data and management
12
+ * Fundamental data analysis operations that may be used ro replay/reprocess data, not just in live capture
13
+ * System configuration reading and persistence
14
+ * Misc utilities
15
+ * Performance monitoring wrappers
16
+ * Queue extensions
17
+
18
+ ### Future Work
19
+ The Project class and functionality is largely geared towards the creation of projects, knowing where to save
20
+ data and created those folders and files where necessary. It should be improved to make it easier to use as
21
+ a reader for tools that need to be aware of those folders and files, but never create them. This will be used
22
+ by the management console to read information without needed to burden the acquisition application directly.
23
+
24
+ System configuration files have been updated to use YAML tags for typing and with a new structure that better
25
+ aligns to the subsystems and their properties. There is a still a step to separate a) device values that
26
+ are unlikely to change over time (e.g., hardware ports), b) values related to application that can change
27
+ between sessions, but would not be considered "training" variables and c) training variables that users
28
+ are likely to change regularly and in some cases may be changed by hand.
@@ -0,0 +1,44 @@
1
+ [build-system]
2
+ requires = [
3
+ "setuptools >= 61",
4
+ 'setuptools-scm >= 9.2.2, < 10',
5
+ ]
6
+ build-backend = "setuptools.build_meta"
7
+
8
+ [tool.setuptools.packages.find]
9
+ where = ["src"]
10
+ include = ["autotrainer"]
11
+ namespaces = true
12
+
13
+ [project]
14
+ name = "auto-trainer-core"
15
+ description = "Core objects and implementations for autotrainer"
16
+ license = { text = "MIT" }
17
+ requires-python = ">=3.8"
18
+ dynamic = ["version"]
19
+
20
+ dependencies = [
21
+
22
+ 'auto-trainer-api == 0.9.17',
23
+
24
+ "verboselogs >= 1.7, < 2",
25
+ "coloredlogs >= 15, < 16",
26
+
27
+ 'events >= 0.5, < 1', # dynamic events callback handling
28
+ 'transitions >= 0.9.2, < 1', # machine state transition handling
29
+ 'psutil >= 7, < 8', # for free disk space, notably
30
+
31
+ 'numpy >= 1.23.5, < 2',
32
+
33
+ 'pyhumps >= 3.8, < 4', # snake/camel case converter
34
+ 'pyyaml >= 6.0.2, < 7',
35
+
36
+ 'importlib-resources; python_version < "3.10"',
37
+ 'importlib-metadata; python_version < "3.10"'
38
+ ]
39
+
40
+ [tool.setuptools_scm]
41
+ root = ".." # temporary while embedded in autotrainer main repo
42
+ # also strip auto-trainer-core when moved as independent repo
43
+ write_to = "auto-trainer-core/src/autotrainer/core/version.txt"
44
+ git_describe_command = "git describe --tags --dirty --match 'core-v*' --abbrev=8"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,17 @@
1
+ Metadata-Version: 2.1
2
+ Name: auto-trainer-core
3
+ Version: 2.0.3
4
+ Summary: Core objects and implementations for autotrainer
5
+ License: MIT
6
+ Requires-Python: >=3.8
7
+ Requires-Dist: auto-trainer-api==0.9.17
8
+ Requires-Dist: verboselogs<2,>=1.7
9
+ Requires-Dist: coloredlogs<16,>=15
10
+ Requires-Dist: events<1,>=0.5
11
+ Requires-Dist: transitions<1,>=0.9.2
12
+ Requires-Dist: psutil<8,>=7
13
+ Requires-Dist: numpy<2,>=1.23.5
14
+ Requires-Dist: pyhumps<4,>=3.8
15
+ Requires-Dist: pyyaml<7,>=6.0.2
16
+ Requires-Dist: importlib-resources; python_version < "3.10"
17
+ Requires-Dist: importlib-metadata; python_version < "3.10"
@@ -0,0 +1,95 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/auto_trainer_core.egg-info/PKG-INFO
4
+ src/auto_trainer_core.egg-info/SOURCES.txt
5
+ src/auto_trainer_core.egg-info/dependency_links.txt
6
+ src/auto_trainer_core.egg-info/requires.txt
7
+ src/auto_trainer_core.egg-info/top_level.txt
8
+ src/autotrainer/core/__init__.py
9
+ src/autotrainer/core/capture.py
10
+ src/autotrainer/core/diamond_triangle_config.py
11
+ src/autotrainer/core/fixed_array_multiqueue.py
12
+ src/autotrainer/core/fixed_array_queue.py
13
+ src/autotrainer/core/frame_index.py
14
+ src/autotrainer/core/interfaces.py
15
+ src/autotrainer/core/logging.py
16
+ src/autotrainer/core/multiproc.py
17
+ src/autotrainer/core/observable_object.py
18
+ src/autotrainer/core/perf_monitor.py
19
+ src/autotrainer/core/pose_elements.py
20
+ src/autotrainer/core/queue_util.py
21
+ src/autotrainer/core/reach_event.py
22
+ src/autotrainer/core/video_detection.py
23
+ src/autotrainer/core/analysis/__init__.py
24
+ src/autotrainer/core/analysis/alarm_monitor.py
25
+ src/autotrainer/core/analysis/audio_spectrum_data.py
26
+ src/autotrainer/core/analysis/audio_spectrum_monitor.py
27
+ src/autotrainer/core/analysis/auto_tunnel_fan_monitor.py
28
+ src/autotrainer/core/analysis/detector.py
29
+ src/autotrainer/core/analysis/external_doors_monitor.py
30
+ src/autotrainer/core/analysis/global_animal_presence_monitor.py
31
+ src/autotrainer/core/analysis/head_fix_measurement.py
32
+ src/autotrainer/core/analysis/headbar_pressure_monitor.py
33
+ src/autotrainer/core/analysis/load_cell_monitor.py
34
+ src/autotrainer/core/analysis/load_cell_tare_monitor.py
35
+ src/autotrainer/core/analysis/measurement_data.py
36
+ src/autotrainer/core/analysis/pellet_position_monitor.py
37
+ src/autotrainer/core/analysis/sensor_analysis.py
38
+ src/autotrainer/core/analysis/system_fault_monitor.py
39
+ src/autotrainer/core/analysis/system_maintenance_monitor.py
40
+ src/autotrainer/core/animal/__init__.py
41
+ src/autotrainer/core/animal/animal_subject.py
42
+ src/autotrainer/core/configuration/__init__.py
43
+ src/autotrainer/core/configuration/alarm_configuration.py
44
+ src/autotrainer/core/configuration/animal_presence_configuration.py
45
+ src/autotrainer/core/configuration/behavior_configuration.py
46
+ src/autotrainer/core/configuration/camera_configuration.py
47
+ src/autotrainer/core/configuration/external_doors_monitor_configuration.py
48
+ src/autotrainer/core/configuration/hardware_configuration.py
49
+ src/autotrainer/core/configuration/inference_configuration.py
50
+ src/autotrainer/core/configuration/load_cell_config.py
51
+ src/autotrainer/core/configuration/persistence_configuration.py
52
+ src/autotrainer/core/configuration/presence_detection_configuration.py
53
+ src/autotrainer/core/configuration/system_configuration.py
54
+ src/autotrainer/core/configuration/system_fault_config.py
55
+ src/autotrainer/core/configuration/system_maintenance_config.py
56
+ src/autotrainer/core/event/__init__.py
57
+ src/autotrainer/core/event/api_event_kind.py
58
+ src/autotrainer/core/event/api_event_plugin.py
59
+ src/autotrainer/core/event/event_info.py
60
+ src/autotrainer/core/event/event_manager.py
61
+ src/autotrainer/core/event/event_manager_plugin.py
62
+ src/autotrainer/core/event/file_event_plugin.py
63
+ src/autotrainer/core/event/logger_event_plugin.py
64
+ src/autotrainer/core/message/__init__.py
65
+ src/autotrainer/core/message/audio_spectrum_message.py
66
+ src/autotrainer/core/message/measurement_message.py
67
+ src/autotrainer/core/message/message_handler.py
68
+ src/autotrainer/core/message/motor_configuration_message.py
69
+ src/autotrainer/core/message/system_command_kind.py
70
+ src/autotrainer/core/message/system_message_handler.py
71
+ src/autotrainer/core/message/system_status_message.py
72
+ src/autotrainer/core/notification/__init__.py
73
+ src/autotrainer/core/notification/notification_center.py
74
+ src/autotrainer/core/notification/trigger_notification.py
75
+ src/autotrainer/core/project/__init__.py
76
+ src/autotrainer/core/project/project_info.py
77
+ tests/alarm_config_test.py
78
+ tests/animal_config_test.py
79
+ tests/audio_spectrum_monitor_test.py
80
+ tests/event_manager_test.py
81
+ tests/fixed_array_queue_test.py
82
+ tests/frame_index_test.py
83
+ tests/load_cell_monitor_test.py
84
+ tests/load_cell_tare_monitor_test.py
85
+ tests/offset3d_test.py
86
+ tests/pose_elements_test.py
87
+ tests/pressure_threshold_test.py
88
+ tests/project_info_test.py
89
+ tests/system_configuration_test.py
90
+ tests/system_data_args_kwargs_test.py
91
+ tests/fixtures/pressure_threshold_sample.csv
92
+ tests/fixtures/v0_config.yaml
93
+ tests/fixtures/v1_config.yaml
94
+ tests/mocks/__init__.py
95
+ tests/mocks/mock_event_plugin.py
@@ -0,0 +1,13 @@
1
+ auto-trainer-api==0.9.17
2
+ verboselogs<2,>=1.7
3
+ coloredlogs<16,>=15
4
+ events<1,>=0.5
5
+ transitions<1,>=0.9.2
6
+ psutil<8,>=7
7
+ numpy<2,>=1.23.5
8
+ pyhumps<4,>=3.8
9
+ pyyaml<7,>=6.0.2
10
+
11
+ [:python_version < "3.10"]
12
+ importlib-resources
13
+ importlib-metadata
@@ -0,0 +1,319 @@
1
+ import dataclasses
2
+ import math
3
+ import time
4
+ from collections import namedtuple
5
+ from typing import Union, List, Tuple, Dict, Any, Iterable, TypeVar, Type, Optional, Callable
6
+ from typing_extensions import Self
7
+
8
+ import humps
9
+ import yaml
10
+ from typing_extensions import Self
11
+
12
+ # NB: import order is very important, put the less specific/most general first, then go in order of dependency.
13
+
14
+ from .logging import get_verbose_logger
15
+
16
+ #
17
+
18
+ logger = get_verbose_logger(__name__)
19
+
20
+ #
21
+
22
+ def mean_method(data):
23
+ return sum(data) / len(data)
24
+
25
+
26
+ def calculate_std_dev_manual(data, reduce_method=mean_method):
27
+ n = len(data)
28
+ if n < 2:
29
+ raise ValueError("Data must contain at least two values to calculate standard deviation.")
30
+ res = reduce_method(data)
31
+ squared_diffs = [(x - res) ** 2 for x in data]
32
+ variance = sum(squared_diffs) / (n - 1) # Sample standard deviation
33
+ std_dev = variance ** 0.5
34
+ return res, std_dev
35
+
36
+ #
37
+
38
+ @dataclasses.dataclass
39
+ class RawValueHolder:
40
+ value: Any
41
+
42
+
43
+ def _no_convert(v):
44
+ return v
45
+
46
+
47
+ class ValueHolderDescriptor:
48
+
49
+ def __init__(
50
+ self,
51
+ *,
52
+ convert_to: Callable[[Any], Any] = _no_convert,
53
+ convert_from: Callable[[Any], Any] = _no_convert,
54
+ ):
55
+ self._convert_to = convert_to
56
+ self._convert_from = convert_from
57
+
58
+ def __set_name__(self, owner, name):
59
+ self.name = name
60
+ self._priv_name = f"_{name}"
61
+
62
+ def __get__(self, instance, owner):
63
+ if instance is None:
64
+ return self
65
+ return self._convert_from(getattr(instance, self._priv_name).value)
66
+
67
+ def __set__(self, instance, value):
68
+ getattr(instance, self._priv_name).value = self._convert_to(value)
69
+
70
+ #
71
+
72
+ def transitions_allow_functions(transitions: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
73
+ """Update the dicts to the functions name"""
74
+ for trans in transitions:
75
+ for k in ('trigger', 'before', 'after', 'conditions'):
76
+ v = trans.get(k)
77
+ if isinstance(v, (list, tuple)):
78
+ trans[k] = tuple(
79
+ sub.__name__ if callable(sub) else sub
80
+ for sub in v
81
+ )
82
+ elif callable(v):
83
+ trans[k] = v.__name__
84
+ return transitions
85
+ #
86
+
87
+ Pairs3dOffsetT = Union[List[Tuple[str, str]], Tuple[Tuple[str, str], ...]]
88
+
89
+ _Offset3DTuple = namedtuple("Offset3DTuple", ('x', 'y', 'z'))
90
+
91
+
92
+ def _get_perf_now():
93
+ # allowed to be patched from test
94
+ return time.perf_counter()
95
+
96
+
97
+ def get_perf_now():
98
+ return _get_perf_now()
99
+
100
+
101
+ class Offset3DTuple(_Offset3DTuple):
102
+ """Named tuple (x, y, z),
103
+ allowing construction with "packed" Offset3DTuple((x, y, z)) or "unpacked" Offset3DTuple(x, y, z) coordinates.
104
+ When "packed": any object having a len() == 3 will be unpacked using python regular:
105
+ x, y, z = args[0]
106
+ Otherwise the construction fails (with anything else in args[0] when len(args) == 1)
107
+ """
108
+ x: float
109
+ y: float
110
+ z: float
111
+
112
+ def __new__(cls, *args, **kwargs):
113
+ if len(args) == 1:
114
+ arg0 = args[0]
115
+ if hasattr(arg0, "__len__") and len(arg0) == 3:
116
+ x, y, z = arg0
117
+ return super().__new__(cls, x, y, z, **kwargs) # noqa
118
+ return super().__new__(cls, *args, **kwargs) # noqa
119
+
120
+ def __repr__(self):
121
+ # to not get "Offset3DTuple(x, y, z)" but instead only "(x, y, z)"
122
+ return str(tuple(self))
123
+
124
+ __str__ = __repr__
125
+
126
+ @staticmethod
127
+ def get_nan() -> Self:
128
+ return _nan_offset3d_tuple
129
+
130
+ @staticmethod
131
+ def get_zero() -> Self:
132
+ return _zero_offset3d_tuple
133
+
134
+ def replace(self, x: Optional[float] = None, y: Optional[float] = None, z: Optional[float] = None) -> Self:
135
+ return self.__class__(
136
+ self.x if x is None else x,
137
+ self.y if y is None else y,
138
+ self.z if z is None else z,
139
+ )
140
+
141
+ def humanize(self, n_digits: int = 2) -> str:
142
+ x, y, z = self
143
+ return f"({x:.0{n_digits}f}, {y:.0{n_digits}f}, {z:.0{n_digits}f})"
144
+
145
+ def round(self, n: int=2) -> Self:
146
+ return self.__class__(*(round(v, n) for v in self))
147
+
148
+ # tried to use with statistics.mean, but at some point with it there is a sorting applied on the list (of offsets),
149
+ # and a smaller-than (<) operator check against a start value of 0 .. and we don't handle that with Offset3DTuple.
150
+ # def as_integer_ratio(self) -> Tuple[Self, Self]:
151
+ # # use float(v) to ensure float, and allow use of as_integer_ration, if integer is in any of x/y/z.
152
+ # xo, yo, zo = map(lambda v: float(v).as_integer_ratio(), self)
153
+ # return self.__class__(xo[0], yo[0], zo[0]), self.__class__(xo[1], yo[1], zo[1])
154
+
155
+ def __pow__(self, other, modulo=None) -> Self:
156
+ if modulo is None:
157
+ return self.__class__(*(v ** other for v in self))
158
+ return self.__class__(
159
+ *(pow(v, other, modulo) for v in self)
160
+ )
161
+
162
+ def __rpow__(self, other, modulo=None) -> Self:
163
+ if modulo is None:
164
+ return self.__class__(*(other ** v for v in self))
165
+ return self.__class__(
166
+ *(pow(other, v, modulo) for v in self)
167
+ )
168
+
169
+
170
+ def __add__(self, other) -> Self:
171
+ if hasattr(other, "__len__") and len(other) == 3:
172
+ return self.__class__(*(v1 + v2 for v1, v2 in zip(self, other)))
173
+ return self.__class__(*(v + other for v in self))
174
+
175
+ __radd__ = __add__
176
+
177
+ def __sub__(self, other) -> Self:
178
+ if hasattr(other, "__len__") and len(other) == 3:
179
+ return self.__class__(*(v1 - v2 for v1, v2 in zip(self, other)))
180
+ return self.__class__(*(v - other for v in self))
181
+
182
+ def __rsub__(self, other) -> Self:
183
+ if hasattr(other, "__len__") and len(other) == 3:
184
+ return self.__class__(*(v2 - v1 for v1, v2 in zip(self, other)))
185
+ return self.__class__(*(other - v for v in self))
186
+
187
+ def __neg__(self) -> Self:
188
+ return self.__class__(-self.x, -self.y, -self.z)
189
+
190
+ def __mul__(self, other) -> Self:
191
+ if hasattr(other, "__len__") and len(other) == 3:
192
+ return self.__class__(*(v1 * v2 for v1, v2 in zip(self, other)))
193
+ return self.__class__(*(v * other for v in self))
194
+
195
+ __rmul__ = __mul__
196
+
197
+ def __truediv__(self, other) -> Self:
198
+ if hasattr(other, "__len__") and len(other) == 3:
199
+ return self.__class__(*(v1 / v2 for v1, v2 in zip(self, other)))
200
+ return self.__class__(*(v / other for v in self))
201
+
202
+ def __abs__(self) -> Self:
203
+ return self.__class__(*(abs(v) for v in self))
204
+
205
+ @property
206
+ def distance(self) -> float:
207
+ return math.sqrt(sum(c**2 for c in self))
208
+
209
+
210
+ _nan_offset3d_tuple = Offset3DTuple(math.nan, math.nan, math.nan)
211
+ _zero_offset3d_tuple = Offset3DTuple(0, 0, 0)
212
+
213
+ #
214
+
215
+
216
+ def build_kwargs_apply_mapping(
217
+ content: Dict[str, Any],
218
+ mapping: Iterable[Union[str, Tuple[str, str]]],
219
+ *,
220
+ skip_remaining: bool = False,
221
+ ) -> Dict[str, Any]:
222
+ kwargs = {}
223
+ content = dict(content) # make copy of 1 level given we'll remove/pop from it
224
+ for cur_map in mapping:
225
+ if isinstance(cur_map, str):
226
+ dest = key = cur_map
227
+ else:
228
+ assert len(cur_map) == 2
229
+ dest, key = cur_map
230
+ if key in content:
231
+ value = content.pop(key)
232
+ if dest not in kwargs: # first one wins
233
+ kwargs[dest] = value
234
+ # insert whatever remains in content, unless skipped:
235
+ if not skip_remaining:
236
+ kwargs.update(content)
237
+ return kwargs
238
+
239
+ #
240
+
241
+
242
+ ConfigItemCls = TypeVar("ConfigItemCls")
243
+
244
+
245
+ def make_camelize_representer(section_name: str):
246
+
247
+ def representer(dumper: yaml.SafeDumper, obj):
248
+ return dumper.represent_mapping(section_name, {
249
+ humps.camelize(field.name): getattr(obj, field.name)
250
+ for field in dataclasses.fields(obj)
251
+ })
252
+
253
+ return representer
254
+
255
+
256
+ def make_decamelize_constructor(cls: Type[ConfigItemCls]):
257
+
258
+ # required delayed import for now,
259
+ # not big deal given this function is to be called once only (per config class).
260
+ from .configuration import SystemConfigurationLoader
261
+
262
+ def constructor(loader: SystemConfigurationLoader, node: yaml.nodes.MappingNode) -> ConfigItemCls:
263
+ content = loader.construct_mapping(node, deep=True)
264
+ content = humps.decamelize(content) # decamelize first,
265
+ # "decamelized" names are here after checked against field names
266
+ if loader.safe_load:
267
+ names = [f.name for f in dataclasses.fields(cls)]
268
+ before_count = len(content)
269
+ before_s = set(content)
270
+ content = {
271
+ k: v
272
+ for k, v in content.items()
273
+ if k in names
274
+ }
275
+ filtered_count = before_count - len(content)
276
+ after_s = set(content)
277
+ if filtered_count != 0:
278
+ logger.verbose("%s: safe load filtered %s unknown properties/attributes: %s",
279
+ cls.__qualname__, filtered_count, sorted(list(before_s - after_s)))
280
+ return cls(**content)
281
+
282
+ return constructor
283
+
284
+
285
+
286
+ # MUST come first (but after above definitions):
287
+ import autotrainer.core.logging
288
+ import autotrainer.core.diamond_triangle_config
289
+ # ..
290
+
291
+
292
+ from .observable_object import ObservableObject, ObservableObjectProtocol
293
+
294
+ from .frame_index import FrameIndexCategory
295
+
296
+ from .fixed_array_multiqueue import FixedArrayMultiQueue
297
+ from .fixed_array_queue import FixedArrayQueue
298
+
299
+ from .project import ProjectInfo, ProjectInterval, video_write_ext
300
+ from .animal import AnimalSubject
301
+
302
+ from .perf_monitor import PerfMonitor
303
+ from .queue_util import clear_queue
304
+ from .notification import NotificationCenter, Notification, TriggerNotification, post_trigger_enable
305
+ from .configuration import HardwareConfiguration, InferenceConfiguration, PersistenceConfiguration
306
+
307
+ from .message import MotorConfigurations, Motor
308
+ from .message import SystemStatusMessageKind, SystemCommandKind, MeasurementMessageProtocol, AudioSpectrumMessage
309
+ from .configuration import SystemConfiguration, BehaviorConfiguration, CameraConfiguration, CameraId, \
310
+ SystemConfigurationLoader
311
+
312
+ from .message import MessageHandler, SystemMessageHandler
313
+ from .analysis import SensorAnalysis, MeasurementData, AudioSpectrumData
314
+ from .analysis import LoadCellMonitor, HeadbarPressureMonitor
315
+
316
+ from .event.api_event_kind import ApiEventKind
317
+ from .event.event_info import EventInfo
318
+ from .event.api_event_plugin import EventManagerPlugin
319
+ from .event.event_manager import EventManager
@@ -0,0 +1,6 @@
1
+ from .audio_spectrum_data import AudioSpectrumData
2
+ from .headbar_pressure_monitor import (HeadbarPressureMonitor, HeadbarPressureConfiguration)
3
+ from .load_cell_monitor import LoadCellMonitor
4
+ from .measurement_data import MeasurementData
5
+ from .alarm_monitor import EmergencyAlarmMonitor
6
+ from .sensor_analysis import SensorAnalysis