oml-plot-tools 0.9.1__py3-none-any.whl

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. oml_plot_tools/__init__.py +24 -0
  2. oml_plot_tools/common.py +172 -0
  3. oml_plot_tools/consum.py +187 -0
  4. oml_plot_tools/main.py +49 -0
  5. oml_plot_tools/radio.py +184 -0
  6. oml_plot_tools/tests/__init__.py +22 -0
  7. oml_plot_tools/tests/common.py +126 -0
  8. oml_plot_tools/tests/common_test.py +133 -0
  9. oml_plot_tools/tests/consum_test.py +201 -0
  10. oml_plot_tools/tests/examples/consumption.oml +4179 -0
  11. oml_plot_tools/tests/examples/consumption_all.png +0 -0
  12. oml_plot_tools/tests/examples/consumption_clock.png +0 -0
  13. oml_plot_tools/tests/examples/consumption_current.png +0 -0
  14. oml_plot_tools/tests/examples/consumption_only_one.oml +10 -0
  15. oml_plot_tools/tests/examples/grenoble-iotlab.png +0 -0
  16. oml_plot_tools/tests/examples/radio.oml +2009 -0
  17. oml_plot_tools/tests/examples/radio_clock.png +0 -0
  18. oml_plot_tools/tests/examples/radio_separated_last.png +0 -0
  19. oml_plot_tools/tests/examples/radio_single.png +0 -0
  20. oml_plot_tools/tests/examples/robot.oml +1447 -0
  21. oml_plot_tools/tests/examples/trajectory_all.png +0 -0
  22. oml_plot_tools/tests/examples/trajectory_angle.png +0 -0
  23. oml_plot_tools/tests/examples/trajectory_circuit.png +0 -0
  24. oml_plot_tools/tests/examples/trajectory_clock.png +0 -0
  25. oml_plot_tools/tests/examples/trajectory_only.png +0 -0
  26. oml_plot_tools/tests/main_parser_test.py +51 -0
  27. oml_plot_tools/tests/radio_test.py +173 -0
  28. oml_plot_tools/tests/traj_test.py +223 -0
  29. oml_plot_tools/traj.py +352 -0
  30. oml_plot_tools-0.9.1.dist-info/METADATA +35 -0
  31. oml_plot_tools-0.9.1.dist-info/RECORD +35 -0
  32. oml_plot_tools-0.9.1.dist-info/WHEEL +4 -0
  33. oml_plot_tools-0.9.1.dist-info/entry_points.txt +5 -0
  34. oml_plot_tools-0.9.1.dist-info/licenses/AUTHORS +1 -0
  35. oml_plot_tools-0.9.1.dist-info/licenses/COPYING +518 -0
@@ -0,0 +1,51 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # This file is a part of IoT-LAB oml-plot-tools
4
+ # Copyright (C) 2015 INRIA (Contact: admin@iot-lab.info)
5
+ # Contributor(s) : see AUTHORS file
6
+ #
7
+ # This software is governed by the CeCILL license under French law
8
+ # and abiding by the rules of distribution of free software. You can use,
9
+ # modify and/ or redistribute the software under the terms of the CeCILL
10
+ # license as circulated by CEA, CNRS and INRIA at the following URL
11
+ # http://www.cecill.info.
12
+ #
13
+ # As a counterpart to the access to the source code and rights to copy,
14
+ # modify and redistribute granted by the license, users are provided only
15
+ # with a limited warranty and the software's author, the holder of the
16
+ # economic rights, and the successive licensors have only limited
17
+ # liability.
18
+ #
19
+ # The fact that you are presently reading this means that you have had
20
+ # knowledge of the CeCILL license and that you accept its terms.
21
+
22
+ """Test the main parser module."""
23
+
24
+ from unittest.mock import patch
25
+
26
+ import pytest
27
+
28
+ import oml_plot_tools.main as main_parser
29
+
30
+
31
+ @pytest.mark.parametrize("entry", ["consum", "radio", "traj"])
32
+ def test_main_parser(entry):
33
+ """Test that main dispatches to the correct subcommand."""
34
+ with patch(f"oml_plot_tools.{entry}.main") as entrypoint_func:
35
+ main_parser.main([entry, "-i", "123"])
36
+ entrypoint_func.assert_called_with(["-i", "123"])
37
+
38
+
39
+ def test_main_help(capsys):
40
+ """Test that 'help' command prints usage."""
41
+ main_parser.main(["help"])
42
+ captured = capsys.readouterr()
43
+ assert "usage" in captured.out.lower()
44
+
45
+
46
+ def test_main_default_help(capsys):
47
+ """Test that no arguments defaults to help."""
48
+ with patch("sys.argv", ["iotlab-plot"]):
49
+ main_parser.main()
50
+ captured = capsys.readouterr()
51
+ assert "usage" in captured.out.lower()
@@ -0,0 +1,173 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # This file is a part of IoT-LAB oml-plot-tools
4
+ # Copyright (C) 2015 INRIA (Contact: admin@iot-lab.info)
5
+ # Contributor(s) : see AUTHORS file
6
+ #
7
+ # This software is governed by the CeCILL license under French law
8
+ # and abiding by the rules of distribution of free software. You can use,
9
+ # modify and/ or redistribute the software under the terms of the CeCILL
10
+ # license as circulated by CEA, CNRS and INRIA at the following URL
11
+ # http://www.cecill.info.
12
+ #
13
+ # As a counterpart to the access to the source code and rights to copy,
14
+ # modify and redistribute granted by the license, users are provided only
15
+ # with a limited warranty and the software's author, the holder of the
16
+ # economic rights, and the successive licensors have only limited
17
+ # liability.
18
+ #
19
+ # The fact that you are presently reading this means that you have had
20
+ # knowledge of the CeCILL license and that you accept its terms.
21
+
22
+ """Tests for radio.py."""
23
+
24
+ import unittest
25
+ from unittest import mock
26
+
27
+ from .. import radio
28
+ from .common import (
29
+ IS_PYTHON_3_10,
30
+ assert_called_with_nparray,
31
+ fixture_path,
32
+ utest_help_as_doc,
33
+ utest_plot_and_compare,
34
+ )
35
+
36
+
37
+ class TestRadioOmlPlot(unittest.TestCase):
38
+ """Tests for radio OML plot functions."""
39
+
40
+ def setUp(self):
41
+ """Set up radio OML data for plot tests."""
42
+ radio_file = fixture_path("examples", "radio.oml")
43
+ self.data = radio.oml_load(radio_file)
44
+ self.title = ""
45
+
46
+ def test_plot_all(self):
47
+ """Test plotting all radio data."""
48
+ ref_img = fixture_path("examples", "radio_single.png")
49
+ radio.oml_plot_rssi(self.data, self.title)
50
+ utest_plot_and_compare(self, ref_img, 200)
51
+
52
+ def test_plot_current(self):
53
+ """Test plotting RSSI data for each channel separately."""
54
+ # multiple images are printed but only last one is kept
55
+ ref_img = fixture_path("examples", "radio_separated_last.png")
56
+ radio.oml_plot_rssi(self.data, self.title, separated=True)
57
+ utest_plot_and_compare(self, ref_img, 200)
58
+
59
+ def test_plot_clock(self):
60
+ """Test plotting OML clock data for radio."""
61
+ ref_img = fixture_path("examples", "radio_clock.png")
62
+ radio.common.oml_plot_clock(self.data)
63
+ utest_plot_and_compare(self, ref_img, 200)
64
+
65
+
66
+ class TestRadioPlot(unittest.TestCase):
67
+ """Tests for radio_plot function with different plot selections."""
68
+
69
+ def setUp(self):
70
+ """Set up test OML data and arguments for radio_plot tests."""
71
+ meas_file = fixture_path("examples", "radio.oml")
72
+ self.data = radio.oml_load(meas_file)[0:1]
73
+
74
+ self.title = "TITLE_TESTS"
75
+ self.args = [
76
+ "plot_oml_radio",
77
+ "-i",
78
+ meas_file,
79
+ "--begin",
80
+ "0",
81
+ "--end",
82
+ "1",
83
+ "-l",
84
+ self.title,
85
+ ]
86
+
87
+ self.oml_plot_rssi = mock.patch("oml_plot_tools.radio.oml_plot_rssi").start()
88
+ self.oml_plot_clock = mock.patch(
89
+ "oml_plot_tools.radio.common.oml_plot_clock"
90
+ ).start()
91
+
92
+ def tearDown(self):
93
+ """Stop all mocks after each test."""
94
+ mock.patch.stopall()
95
+
96
+ def radio_main(self, *args):
97
+ """Call radio main with given additional args."""
98
+ with mock.patch("sys.argv", list(self.args) + list(args)):
99
+ radio.main()
100
+
101
+ def test_plot_joined(self):
102
+ """Test radio_plot with joined channels selection."""
103
+ self.radio_main("--all")
104
+ assert_called_with_nparray(self.oml_plot_rssi, self.data, self.title)
105
+
106
+ def test_plot_separated(self):
107
+ """Test radio_plot with separated channels selection."""
108
+ self.radio_main("--plot")
109
+ assert_called_with_nparray(
110
+ self.oml_plot_rssi, self.data, self.title, separated=True
111
+ )
112
+
113
+ def test_plot_time(self):
114
+ """Test radio_plot with time verification selection."""
115
+ self.radio_main("--time")
116
+ assert_called_with_nparray(self.oml_plot_clock, self.data)
117
+
118
+ def test_plot_default_joined(self):
119
+ """Test radio_plot default selection is joined channels."""
120
+ self.radio_main()
121
+ assert_called_with_nparray(self.oml_plot_rssi, self.data, self.title)
122
+
123
+
124
+ class TestRadioHelpers(unittest.TestCase):
125
+ """Tests for radio helper functions like list_channels and with_channel."""
126
+
127
+ def setUp(self):
128
+ """Set up test OML data for radio helper function tests."""
129
+ radio_file = fixture_path("examples", "radio.oml")
130
+ self.data = radio.oml_load(radio_file)
131
+
132
+ def test_list_channels(self):
133
+ """Test listing channels from radio OML data."""
134
+ channels = radio.list_channels(self.data)
135
+ self.assertIsInstance(channels, list)
136
+ self.assertEqual(channels, sorted(channels))
137
+
138
+ def test_with_channel(self):
139
+ """Test filtering radio OML data by specific channel."""
140
+ channels = radio.list_channels(self.data)
141
+ if channels:
142
+ subset = radio.with_channel(self.data, channels[0])
143
+ self.assertTrue(all(subset["channel"] == channels[0]))
144
+
145
+ def test_radio_plot_joined(self):
146
+ """Test with joined channels selection calls correct plotting function."""
147
+ with mock.patch("oml_plot_tools.radio.oml_plot_rssi") as mock_rssi:
148
+ with mock.patch("oml_plot_tools.radio.common.plot_show"):
149
+ radio.radio_plot(self.data, "Title", ["joined"])
150
+ mock_rssi.assert_called_once_with(self.data, "Title")
151
+
152
+ def test_radio_plot_separated(self):
153
+ """Test with separated channels selection calls correct plotting function."""
154
+ with mock.patch("oml_plot_tools.radio.oml_plot_rssi") as mock_rssi:
155
+ with mock.patch("oml_plot_tools.radio.common.plot_show"):
156
+ radio.radio_plot(self.data, "Title", ["separated"])
157
+ mock_rssi.assert_called_once_with(self.data, "Title", separated=True)
158
+
159
+ def test_radio_plot_time(self):
160
+ """Test with time verification selection calls correct plotting function."""
161
+ with mock.patch("oml_plot_tools.radio.common.oml_plot_clock") as mock_clock:
162
+ with mock.patch("oml_plot_tools.radio.common.plot_show"):
163
+ radio.radio_plot(self.data, "Title", ["time"])
164
+ self.assertTrue(mock_clock.called)
165
+
166
+
167
+ class TestDoc(unittest.TestCase):
168
+ """Tests that module help matches its docstring."""
169
+
170
+ @unittest.skipIf(IS_PYTHON_3_10, "Python 3.10 not supported")
171
+ def test_doc(self):
172
+ """Test that the module help output matches its docstring."""
173
+ utest_help_as_doc(self, radio)
@@ -0,0 +1,223 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # This file is a part of IoT-LAB oml-plot-tools
4
+ # Copyright (C) 2015 INRIA (Contact: admin@iot-lab.info)
5
+ # Contributor(s) : see AUTHORS file
6
+ #
7
+ # This software is governed by the CeCILL license under French law
8
+ # and abiding by the rules of distribution of free software. You can use,
9
+ # modify and/ or redistribute the software under the terms of the CeCILL
10
+ # license as circulated by CEA, CNRS and INRIA at the following URL
11
+ # http://www.cecill.info.
12
+ #
13
+ # As a counterpart to the access to the source code and rights to copy,
14
+ # modify and redistribute granted by the license, users are provided only
15
+ # with a limited warranty and the software's author, the holder of the
16
+ # economic rights, and the successive licensors have only limited
17
+ # liability.
18
+ #
19
+ # The fact that you are presently reading this means that you have had
20
+ # knowledge of the CeCILL license and that you accept its terms.
21
+
22
+ """Tests for traj.py."""
23
+
24
+ import json
25
+ import unittest
26
+ from unittest import mock
27
+
28
+ from .. import common, traj
29
+ from .common import (
30
+ IS_PYTHON_3_10,
31
+ assert_called_with_nparray,
32
+ fixture_path,
33
+ utest_help_as_doc,
34
+ utest_plot_and_compare,
35
+ )
36
+
37
+
38
+ def robot_get_map(site):
39
+ """Simulate robot_get_map using examples files."""
40
+ map_cfg = {}
41
+
42
+ with open(fixture_path("examples", f"{site}-iotlab.png"), "rb") as _fd:
43
+ map_cfg["image"] = _fd.read()
44
+
45
+ with open(fixture_path("examples", f"{site}-mapconfig.json")) as _fd:
46
+ map_cfg["config"] = json.load(_fd)
47
+
48
+ with open(fixture_path("examples", f"{site}-dockconfig.json")) as _fd:
49
+ map_cfg["dock"] = json.load(_fd)
50
+
51
+ return map_cfg
52
+
53
+
54
+ def maps_load(site):
55
+ """Load given site map and return mapinfo."""
56
+ map_cfg = robot_get_map(site)
57
+ return traj._mapinfo_from_cfg(map_cfg) # noqa: SLF001, #pylint: disable=protected-access
58
+
59
+
60
+ class TestTrajectoryOmlPlot(unittest.TestCase):
61
+ """Tests for trajectory OML plot functions."""
62
+
63
+ def setUp(self):
64
+ """Set up trajectory OML data for plot tests."""
65
+ robot_file = fixture_path("examples", "robot.oml")
66
+ circuit_file = fixture_path("examples", "Jhall_w.json")
67
+
68
+ self.data = traj.oml_load(robot_file)
69
+ self.mapinfo = maps_load("grenoble")
70
+ self.circuit = traj.circuit_load(circuit_file)
71
+ self.title = "Robot"
72
+
73
+ def test_plot_all(self):
74
+ """Test plotting all trajectory data with map and circuit."""
75
+ ref_img = fixture_path("examples", "trajectory_all.png")
76
+ traj.oml_plot_map(self.data, self.title, self.mapinfo, self.circuit)
77
+ utest_plot_and_compare(self, ref_img, 20000)
78
+
79
+ def test_plot_traj_only(self):
80
+ """Test plotting trajectory data without map and circuit."""
81
+ ref_img = fixture_path("examples", "trajectory_only.png")
82
+ traj.oml_plot_map(self.data, self.title, None, None)
83
+ utest_plot_and_compare(self, ref_img, 3000)
84
+
85
+ def test_plot_traj_circuit(self):
86
+ """Test plotting trajectory data with circuit but no map."""
87
+ ref_img = fixture_path("examples", "trajectory_circuit.png")
88
+ traj.oml_plot_map(None, self.title, None, self.circuit)
89
+ utest_plot_and_compare(self, ref_img, 3000)
90
+
91
+ def test_plot_traj_nothing(self):
92
+ """Test plotting with no data, map, or circuit should print message."""
93
+ ret = traj.oml_plot_map(None, None, None, None)
94
+ self.assertFalse(ret)
95
+
96
+ def test_plot_angle(self):
97
+ """Test plotting trajectory angle data."""
98
+ ref_img = fixture_path("examples", "trajectory_angle.png")
99
+ traj.oml_plot_angle(self.data, self.title)
100
+ utest_plot_and_compare(self, ref_img, 50)
101
+
102
+ def test_plot_clock(self):
103
+ """Test plotting trajectory clock data."""
104
+ ref_img = fixture_path("examples", "trajectory_clock.png")
105
+ common.oml_plot_clock(self.data)
106
+ utest_plot_and_compare(self, ref_img, 100)
107
+
108
+
109
+ class TestTrajectory(unittest.TestCase):
110
+ """Tests for trajectory main CLI entry point."""
111
+
112
+ def setUp(self):
113
+ """Set up mocks and test arguments for trajectory main tests."""
114
+ meas_file = fixture_path("examples", "robot.oml")
115
+ self.data = traj.oml_load(meas_file)[0:1]
116
+
117
+ self.title = "TITLE_TESTS"
118
+ self.args = [
119
+ "plot_oml_consum",
120
+ "-i",
121
+ meas_file,
122
+ "--begin",
123
+ "0",
124
+ "--end",
125
+ "1",
126
+ "-l",
127
+ self.title,
128
+ ]
129
+
130
+ self.oml_plot_map = mock.patch("oml_plot_tools.traj.oml_plot_map").start()
131
+ self.oml_plot_map.return_value = False
132
+ self.oml_plot_angle = mock.patch("oml_plot_tools.traj.oml_plot_angle").start()
133
+ self.oml_plot_angle.return_value = False
134
+ self.oml_plot_clock = mock.patch(
135
+ "oml_plot_tools.traj.common.oml_plot_clock"
136
+ ).start()
137
+ self.oml_plot_clock.return_value = False
138
+
139
+ self.plot_show = mock.patch("oml_plot_tools.traj.common.plot_show").start()
140
+
141
+ def tearDown(self):
142
+ """Stop all mocks after each test."""
143
+ mock.patch.stopall()
144
+
145
+ def traj_main(self, *args):
146
+ """Call traj main with given additional args."""
147
+ with mock.patch("sys.argv", list(self.args) + list(args)):
148
+ traj.main()
149
+
150
+ def test_plot_traj(self):
151
+ """Test with trajectory selection calls correct plotting function."""
152
+ self.oml_plot_map.return_value = True
153
+ self.traj_main("--traj")
154
+ assert_called_with_nparray(self.oml_plot_map, self.data, self.title, None, None)
155
+ self.assertFalse(self.oml_plot_angle.called)
156
+ self.assertFalse(self.oml_plot_clock.called)
157
+ self.assertTrue(self.plot_show.called)
158
+
159
+ def test_plot_angle(self):
160
+ """Test with angle selection calls correct plotting function."""
161
+ self.oml_plot_angle.return_value = True
162
+ self.traj_main("--angle")
163
+ self.assertFalse(self.oml_plot_map.called)
164
+ assert_called_with_nparray(self.oml_plot_angle, self.data, self.title)
165
+ self.assertFalse(self.oml_plot_clock.called)
166
+ self.assertTrue(self.plot_show.called)
167
+
168
+ def test_plot_clock(self):
169
+ """Test with time selection calls correct plotting function."""
170
+ self.oml_plot_clock.return_value = True
171
+ self.traj_main("--time")
172
+ self.assertFalse(self.oml_plot_map.called)
173
+ self.assertFalse(self.oml_plot_angle.called)
174
+ assert_called_with_nparray(self.oml_plot_clock, self.data)
175
+ self.assertTrue(self.plot_show.called)
176
+
177
+ def test_plot_nothing(self):
178
+ """Test no selections should print message and not call plotting functions."""
179
+ self.oml_plot_map.return_value = False
180
+ self.args = ["plot_oml_consum"]
181
+ self.traj_main("--traj")
182
+
183
+ assert_called_with_nparray(self.oml_plot_map, None, "Robot", None, None)
184
+ self.assertFalse(self.oml_plot_angle.called)
185
+ self.assertFalse(self.oml_plot_clock.called)
186
+
187
+ @mock.patch("iotlabcli.robot.robot_get_map", robot_get_map)
188
+ def test_plot_mapinfo(self):
189
+ """Test with mapinfo selection calls correct plotting function."""
190
+ self.args = ["plot_oml_consum"]
191
+ self.traj_main("--site-map", "grenoble")
192
+ self.assertTrue(self.oml_plot_map.called)
193
+
194
+ def test_trajectory_plot_nothing_to_show(self):
195
+ """Test with selections that do not produce any plot should print message."""
196
+ self.oml_plot_map.return_value = False
197
+ self.oml_plot_angle.return_value = False
198
+ self.oml_plot_clock.return_value = False
199
+ with mock.patch("builtins.print") as mock_print:
200
+ traj.trajectory_plot(None, "T", None, None, ["traj"])
201
+ mock_print.assert_called_with("Nothing to plot")
202
+
203
+ def test_trajectory_plot_all_selections(self):
204
+ """Test trajectory_plot with all selections calls all plotting functions."""
205
+ self.oml_plot_map.return_value = True
206
+ self.oml_plot_angle.return_value = True
207
+ self.oml_plot_clock.return_value = True
208
+ traj.trajectory_plot(
209
+ self.data, self.title, None, None, ["traj", "angle", "time"]
210
+ )
211
+ self.assertTrue(self.oml_plot_map.called)
212
+ self.assertTrue(self.oml_plot_angle.called)
213
+ self.assertTrue(self.oml_plot_clock.called)
214
+ self.assertTrue(self.plot_show.called)
215
+
216
+
217
+ class TestDoc(unittest.TestCase):
218
+ """Tests that module help matches its docstring."""
219
+
220
+ @unittest.skipIf(IS_PYTHON_3_10, "Python 3.10 not supported")
221
+ def test_doc(self):
222
+ """Test that the module help output matches its docstring."""
223
+ utest_help_as_doc(self, traj)