tdl-xoa-driver 1.5.1__py3-none-any.whl → 1.6.0__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 (110) hide show
  1. {tdl_xoa_driver-1.5.1.dist-info → tdl_xoa_driver-1.6.0.dist-info}/METADATA +1 -1
  2. {tdl_xoa_driver-1.5.1.dist-info → tdl_xoa_driver-1.6.0.dist-info}/RECORD +89 -88
  3. xoa_driver/__init__.py +2 -2
  4. xoa_driver/enums.py +10 -10
  5. xoa_driver/functions/anlt.py +60 -78
  6. xoa_driver/functions/cli/testbed_config.py +1 -1
  7. xoa_driver/functions/cmis/_replies.py +4 -4
  8. xoa_driver/functions/mgmt.py +206 -250
  9. xoa_driver/functions/tools.py +11 -6
  10. xoa_driver/internals/commands/c_commands.py +59 -0
  11. xoa_driver/internals/commands/enums.py +101 -90
  12. xoa_driver/internals/commands/m4_commands.py +25 -0
  13. xoa_driver/internals/commands/m4e_commands.py +6 -0
  14. xoa_driver/internals/commands/m_commands.py +51 -1
  15. xoa_driver/internals/commands/p4_commands.py +63 -1
  16. xoa_driver/internals/commands/p4e_commands.py +9 -0
  17. xoa_driver/internals/commands/p4g_commands.py +139 -0
  18. xoa_driver/internals/commands/p_commands.py +455 -61
  19. xoa_driver/internals/commands/pc_commands.py +9 -0
  20. xoa_driver/internals/commands/pd_commands.py +11 -0
  21. xoa_driver/internals/commands/pe_commands.py +27 -0
  22. xoa_driver/internals/commands/pec_commands.py +9 -0
  23. xoa_driver/internals/commands/ped_commands.py +23 -0
  24. xoa_driver/internals/commands/pef_commands.py +43 -0
  25. xoa_driver/internals/commands/pf_commands.py +11 -0
  26. xoa_driver/internals/commands/pl1_commands.py +315 -48
  27. xoa_driver/internals/commands/pl_commands.py +8 -0
  28. xoa_driver/internals/commands/pm_commands.py +11 -0
  29. xoa_driver/internals/commands/pp_commands.py +84 -27
  30. xoa_driver/internals/commands/pr_commands.py +25 -0
  31. xoa_driver/internals/commands/ps_commands.py +47 -1
  32. xoa_driver/internals/commands/pt_commands.py +15 -0
  33. xoa_driver/internals/commands/px_commands.py +180 -136
  34. xoa_driver/internals/commands/subtypes.py +4 -3
  35. xoa_driver/internals/core/transporter/protocol/payload/base_struct.py +1 -1
  36. xoa_driver/internals/hli/indices/macsecscs/base_macsecsc.py +41 -3
  37. xoa_driver/internals/hli/modules/modules_l23/family_combi.py +0 -64
  38. xoa_driver/internals/hli/modules/modules_l23/family_edun.py +0 -2
  39. xoa_driver/internals/hli/modules/modules_l23/{family_g.py → family_loki.py} +29 -1
  40. xoa_driver/internals/hli/modules/modules_l23/family_odin.py +412 -0
  41. xoa_driver/internals/hli/modules/modules_l23/{family_l.py → family_thor.py} +44 -0
  42. xoa_driver/internals/hli/ports/port_l23/chimera/port_chimera.py +3 -3
  43. xoa_driver/internals/hli/ports/port_l23/family_edun.py +9 -44
  44. xoa_driver/internals/hli/ports/port_l23/{family_l1.py → family_freya.py} +10 -45
  45. xoa_driver/internals/hli/ports/port_l23/{family_g.py → family_loki.py} +33 -32
  46. xoa_driver/internals/hli/ports/port_l23/family_odin.py +225 -0
  47. xoa_driver/internals/hli/ports/port_l23/family_thor.py +67 -0
  48. xoa_driver/internals/hli/ports/port_l23/layer1/anlt.py +512 -0
  49. xoa_driver/internals/hli/ports/port_l23/layer1/brr.py +26 -0
  50. xoa_driver/internals/hli/ports/port_l23/layer1/eye_diagram.py +71 -0
  51. xoa_driver/internals/hli/ports/port_l23/{pcs_pma_ijkl_chimera.py → layer1/impair.py} +7 -7
  52. xoa_driver/internals/hli/ports/port_l23/layer1/laser_power.py +28 -0
  53. xoa_driver/internals/hli/ports/port_l23/{family_e.py → layer1/lower_power.py} +1 -51
  54. xoa_driver/internals/hli/ports/port_l23/{freya_l1.py → layer1/medium.py} +38 -358
  55. xoa_driver/internals/hli/ports/port_l23/layer1/pcs_fec.py +219 -0
  56. xoa_driver/internals/hli/ports/port_l23/layer1/pma.py +43 -0
  57. xoa_driver/internals/hli/ports/port_l23/layer1/prbs.py +39 -0
  58. xoa_driver/internals/hli/ports/port_l23/layer1/preamble.py +25 -0
  59. xoa_driver/internals/hli/ports/port_l23/{fault_jkl.py → layer1/rs_fault.py} +2 -2
  60. xoa_driver/internals/hli/ports/port_l23/layer1/siv.py +69 -0
  61. xoa_driver/internals/hli/ports/port_l23/layer1_edun.py +103 -0
  62. xoa_driver/internals/hli/ports/port_l23/layer1_freya.py +103 -0
  63. xoa_driver/internals/hli/ports/port_l23/layer1_loki.py +74 -0
  64. xoa_driver/internals/hli/ports/port_l23/layer1_thor.py +70 -0
  65. xoa_driver/internals/hli/ports/port_l23/port_l23ve.py +4 -4
  66. xoa_driver/internals/hli/ports/port_l23/sec/__init__.py +0 -0
  67. xoa_driver/internals/hli/ports/port_l23/sec/macsec.py +108 -0
  68. xoa_driver/internals/hli/ports/port_l23/tcvr/__init__.py +0 -0
  69. xoa_driver/internals/hli/ports/port_l23/{bases/port_transceiver.py → tcvr/cmis.py} +4 -118
  70. xoa_driver/internals/hli/ports/port_l23/tcvr/transceiver.py +124 -0
  71. xoa_driver/internals/hli/ports/port_l23/trafficgen/__init__.py +0 -0
  72. xoa_driver/internals/hli/ports/port_l23/{bases → trafficgen}/port_l23.py +1 -1
  73. xoa_driver/internals/hli/ports/port_l23/{bases → trafficgen}/port_l23_genuine.py +5 -45
  74. xoa_driver/internals/hli/ports/port_l23/{bases/port_reception_statistics.py → trafficgen/port_rx_stats.py} +0 -21
  75. xoa_driver/internals/hli/ports/port_l23/{bases/port_transmission_statistics.py → trafficgen/port_tx_stats.py} +2 -22
  76. xoa_driver/internals/hli/ports/port_l23/trafficgen/runt.py +32 -0
  77. xoa_driver/internals/hli/testers/l23_tester.py +1 -3
  78. xoa_driver/internals/utils/indices/_interfaces.py +18 -6
  79. xoa_driver/internals/utils/indices/index_manager.py +8 -2
  80. xoa_driver/internals/utils/managers/ports_manager.py +5 -2
  81. xoa_driver/misc.py +6 -6
  82. xoa_driver/modules.py +31 -47
  83. xoa_driver/ports.py +10 -29
  84. xoa_driver/internals/hli/modules/modules_l23/family_d.py +0 -75
  85. xoa_driver/internals/hli/modules/modules_l23/family_e.py +0 -85
  86. xoa_driver/internals/hli/modules/modules_l23/family_f.py +0 -145
  87. xoa_driver/internals/hli/modules/modules_l23/family_h.py +0 -40
  88. xoa_driver/internals/hli/modules/modules_l23/family_i.py +0 -25
  89. xoa_driver/internals/hli/modules/modules_l23/family_j.py +0 -25
  90. xoa_driver/internals/hli/modules/modules_l23/family_k.py +0 -39
  91. xoa_driver/internals/hli/modules/modules_l23/family_m.py +0 -25
  92. xoa_driver/internals/hli/modules/modules_l23/family_n.py +0 -40
  93. xoa_driver/internals/hli/ports/port_l23/edun_l1.py +0 -181
  94. xoa_driver/internals/hli/ports/port_l23/family_combi.py +0 -37
  95. xoa_driver/internals/hli/ports/port_l23/family_d.py +0 -51
  96. xoa_driver/internals/hli/ports/port_l23/family_f.py +0 -151
  97. xoa_driver/internals/hli/ports/port_l23/family_h.py +0 -67
  98. xoa_driver/internals/hli/ports/port_l23/family_i.py +0 -84
  99. xoa_driver/internals/hli/ports/port_l23/family_j.py +0 -68
  100. xoa_driver/internals/hli/ports/port_l23/family_k.py +0 -73
  101. xoa_driver/internals/hli/ports/port_l23/family_l.py +0 -82
  102. xoa_driver/internals/hli/ports/port_l23/family_m.py +0 -29
  103. xoa_driver/internals/hli/ports/port_l23/pcs_pma_ghijkl.py +0 -369
  104. xoa_driver/internals/hli/ports/port_l23/pcs_pma_l.py +0 -78
  105. {tdl_xoa_driver-1.5.1.dist-info → tdl_xoa_driver-1.6.0.dist-info}/WHEEL +0 -0
  106. {tdl_xoa_driver-1.5.1.dist-info → tdl_xoa_driver-1.6.0.dist-info}/licenses/LICENSE +0 -0
  107. {tdl_xoa_driver-1.5.1.dist-info → tdl_xoa_driver-1.6.0.dist-info}/top_level.txt +0 -0
  108. /xoa_driver/internals/hli/modules/modules_l23/{family_l1.py → family_freya.py} +0 -0
  109. /xoa_driver/internals/hli/ports/port_l23/{bases → layer1}/__init__.py +0 -0
  110. /xoa_driver/internals/hli/ports/port_l23/{bases → trafficgen}/port_capture.py +0 -0
@@ -9,15 +9,18 @@ from typing import (
9
9
  TYPE_CHECKING,
10
10
  Any,
11
11
  Union,
12
+ List,
13
+ Tuple,
12
14
  )
13
- from xoa_driver import enums, testers
15
+ from xoa_driver import enums, ports
14
16
  from xoa_driver.utils import apply
15
17
  if TYPE_CHECKING:
16
- from xoa_driver.internals.hli.ports.port_l23.family_l import FamilyL
17
- from xoa_driver.internals.hli.ports.port_l23.family_l1 import FamilyFreya
18
- from xoa_driver.ports import GenericAnyPort, GenericL23Port
18
+ from xoa_driver.ports import GenericL23Port, Z800FreyaPort, Z1600EdunPort, GenericAnyPort
19
19
  from xoa_driver.modules import GenericAnyModule, GenericL23Module, ModuleChimera, Z800FreyaModule, Z1600EdunModule
20
- from xoa_driver.testers import GenericAnyTester, L23Tester
20
+ from xoa_driver.testers import L23Tester
21
+ type FreyaEdunModule = Union[Z800FreyaModule, Z1600EdunModule]
22
+ type FreyaEdunPort = Union[Z800FreyaPort, Z1600EdunPort]
23
+ from xoa_driver.internals.commands.enums import MediaConfigurationType
21
24
  from .exceptions import (
22
25
  NotSupportMedia,
23
26
  NotSupportPortSpeed,
@@ -30,30 +33,31 @@ import json
30
33
 
31
34
 
32
35
  # region Testers
33
- async def reserve_tester(tester: GenericAnyTester, force: bool = True) -> None:
36
+ async def reserve_tester(tester: L23Tester, force: bool = True) -> None:
34
37
  """
35
38
  Reserve a tester regardless whether it is owned by others or not.
36
39
 
37
40
  :param tester: The tester to reserve
38
- :type tester: :class:`~xoa_driver.testers.GenericAnyTester`
41
+ :type tester: :class:`~xoa_driver.testers.L23Tester`
39
42
  :param force: Should force reserve the tester
40
43
  :type force: boolean
41
44
  :return:
42
45
  :rtype: None
43
46
  """
47
+
44
48
  await release_tester(tester, force)
45
49
  await tester.reservation.set_reserve()
46
50
 
47
51
 
48
52
  async def release_tester(
49
- tester: GenericAnyTester,
53
+ tester: L23Tester,
50
54
  should_release_modules_ports: bool = False,
51
55
  ) -> None:
52
56
  """
53
57
  Free a tester. If the tester is reserved by you, release the tester. If the tester is reserved by others, relinquish the tester. The tester should have no owner afterwards.
54
58
 
55
59
  :param tester: The tester to free
56
- :type tester: :class:`~xoa_driver.testers.GenericAnyTester`
60
+ :type tester: :class:`~xoa_driver.testers.L23Tester`
57
61
  :param should_release_modules_ports: should modules and ports also be freed, defaults to False
58
62
  :type should_release_modules_ports: bool, optional
59
63
  :return:
@@ -65,10 +69,10 @@ async def release_tester(
65
69
  elif r.operation == enums.ReservedStatus.RESERVED_BY_YOU:
66
70
  await tester.reservation.set_release()
67
71
  if should_release_modules_ports:
68
- await asyncio.gather(*(release_module(m, True) for m in tester.modules))
72
+ await asyncio.gather(*(release_modules(list(tester.modules), True)))
69
73
 
70
74
 
71
- async def get_chassis_sys_uptime_sec(tester: L23Tester) -> int:
75
+ async def get_chassis_sys_uptime(tester: L23Tester) -> int:
72
76
  """
73
77
  Get chassis system uptime in seconds
74
78
 
@@ -90,54 +94,53 @@ async def get_chassis_sys_uptime_sec(tester: L23Tester) -> int:
90
94
  # region Modules
91
95
 
92
96
 
93
- def get_module(tester: GenericAnyTester, module_id: int) -> GenericAnyModule:
97
+ def obtain_modules_by_ids(tester: L23Tester, module_ids: List[str]) -> Tuple[GenericAnyModule, ...]:
94
98
  """
95
- Get a module object of the tester.
99
+ Get the module objects of the tester specified by module index ids
96
100
 
97
101
  :param tester: The tester object
98
- :type tester: :class:`~xoa_driver.testers.GenericAnyTester`
99
- :param module_id: the index id of the module
100
- :type module_id: int
101
- :raises NoSuchModuleError: No such a module index on the tester
102
- :return: module object
103
- :rtype: :class:`~xoa_driver.modules.GenericAnyModule`
104
- """
105
- return tester.modules.obtain(module_id)
102
+ :type tester: :class:`~xoa_driver.testers.L23Tester`
103
+ :param module_ids: the index ids of the modules.
106
104
 
105
+ Use "*" to get all modules.
106
+
107
+ If the list is empty, return all modules of the tester
107
108
 
108
- def get_modules(tester: GenericAnyTester) -> tuple[GenericAnyModule, ...]:
109
+ :type module_ids: List[str]
110
+ :raises NoSuchModuleError: No such a module index on the tester
111
+ :return: module objects
112
+ :rtype: List[:class:`~xoa_driver.modules.GenericAnyModule`]
109
113
  """
110
- Get all modules of the tester
111
114
 
112
- :param tester: The tester object
113
- :type tester: :class:`~xoa_driver.testers.GenericAnyTester`
114
- :return: List of module objects
115
- :rtype: tuple[GenericAnyModule]
116
- """
117
- return tuple(tester.modules)
115
+ if len(module_ids) == 0:
116
+ return tuple(tester.modules)
117
+ elif "*" in module_ids:
118
+ return tuple(tester.modules)
119
+ else:
120
+ return tuple(tester.modules.obtain(int(module_id)) for module_id in module_ids)
118
121
 
119
122
 
120
- async def reserve_module(module: GenericAnyModule, force: bool = True) -> None:
123
+ async def reserve_modules(modules: List[GenericAnyModule], force: bool = True) -> None:
121
124
  """
122
- Reserve a module regardless whether it is owned by others or not.
125
+ Reserve modules regardless whether they are owned by others or not.
123
126
 
124
- :param module: The module to reserve
125
- :type module: :class:`~xoa_driver.modules.GenericAnyModule`
127
+ :param modules: The modules to reserve
128
+ :type modules: List[:class:`~xoa_driver.modules.GenericAnyModule`]
126
129
  :param force: Should force reserve the module, defaults to True
127
130
  :type force: boolean
128
131
  :return:
129
132
  :rtype: None
130
133
  """
131
- await release_module(module, force)
132
- await module.reservation.set_reserve()
133
134
 
135
+ await release_modules(modules, force)
136
+ await asyncio.gather(*(module.reservation.set_reserve() for module in modules))
134
137
 
135
- async def release_module(
136
- module: GenericAnyModule, should_release_ports: bool = False
138
+
139
+ async def release_modules(
140
+ modules: List[GenericAnyModule], should_release_ports: bool = False
137
141
  ) -> None:
138
142
  """
139
- Free a module. If the module is reserved by you, release the module. If the module is reserved by others, relinquish the module. The module should have no owner afterwards.
140
-
143
+ Free modules. If a module is reserved by you, release the module. If a module is reserved by others, relinquish the module. The modules should have no owner afterwards.
141
144
  :param module: The module to free
142
145
  :type module: :class:`~xoa_driver.modules.GenericAnyModule`
143
146
  :param should_release_ports: should ports also be freed, defaults to False
@@ -145,122 +148,34 @@ async def release_module(
145
148
  :return:
146
149
  :rtype: None
147
150
  """
148
- r = await module.reservation.get()
149
- if r.operation == enums.ReservedStatus.RESERVED_BY_OTHER:
150
- await module.reservation.set_relinquish()
151
- elif r.operation == enums.ReservedStatus.RESERVED_BY_YOU:
152
- await module.reservation.set_release()
153
- if should_release_ports:
154
- await release_ports(*module.ports)
155
-
156
-
157
- def get_module_supported_media(
158
- module: GenericL23Module | ModuleChimera,
159
- ) -> list[dict[str, Any]]:
160
- """
161
- Get a list of supported media, port speed and count of the module.
162
-
163
- :param module: The module object
164
- :type module: GenericAnyModule
165
- :return: List of supported media, port speed and count
166
- :rtype: list[dict[str, Any]]
167
- """
168
- supported_media_list = []
169
- item = {}
170
-
171
- for media_item in module.info.media_info_list: # type: ignore
172
- for sub_item in media_item.supported_configs:
173
- item = dict()
174
- item["media"] = media_item.cage_type
175
- item["port_count"] = sub_item.port_count
176
- item["port_speed"] = sub_item.port_speed
177
- supported_media_list.append(item)
178
151
 
179
- return supported_media_list
152
+ for module in modules:
153
+ r = await module.reservation.get()
154
+ if r.operation == enums.ReservedStatus.RESERVED_BY_OTHER:
155
+ await module.reservation.set_relinquish()
156
+ elif r.operation == enums.ReservedStatus.RESERVED_BY_YOU:
157
+ await module.reservation.set_release()
158
+ if should_release_ports:
159
+ await release_ports(list(module.ports))
180
160
 
181
161
 
182
- async def set_module_media_config(
162
+ def get_module_supported_configs(
183
163
  module: Union[GenericL23Module, ModuleChimera],
184
- media: enums.MediaConfigurationType,
185
- force: bool = True,
186
- ) -> None:
164
+ ) -> List[Tuple[MediaConfigurationType, int, int]]:
187
165
  """
188
- Set module's media configuration.
189
-
190
- :param module: The module object
191
- :type module: GenericAnyModule
192
- :param media: Target media for the module
193
- :type media: enums.MediaConfigurationType
194
- :param force: Should reserve the module by force, defaults to True
195
- :type force: bool, optional
196
- :raises NotSupportMedia: The module does not support this media type
197
- :return:
198
- :rtype:
199
- """
200
-
201
- # reserve the module first
202
- await reserve_module(module, force)
203
-
204
- # get the supported media
205
- supported_media_list = get_module_supported_media(module)
206
-
207
- # set the module media if the target media is found in supported media
208
- for item in supported_media_list:
209
- if item["media"] == media:
210
- await module.config.media.set(media_config=media)
211
- await release_module(module, False)
212
- return None
213
-
214
- # raise exception is the target media is not found in the supported media
215
- raise NotSupportMedia(module)
216
-
217
-
218
- async def set_module_port_config(
219
- module: Union[GenericL23Module, ModuleChimera],
220
- port_count: int,
221
- port_speed: int,
222
- force: bool = True,
223
- ) -> None:
224
- """
225
- Set module's port-speed configuration
166
+ Get the module's supported configurations in a list.
226
167
 
227
168
  :param module: The module object
228
169
  :type module: Union[GenericL23Module, ModuleChimera]
229
- :param port_count: The port count
230
- :type port_count: int
231
- :param port_speed: The port speed in Mbps, e.g. 40000 for 40G
232
- :type port_speed: int
233
- :param force: Should reserve the module by force, defaults to True
234
- :type force: bool, optional
235
- :raises NotSupportPortSpeed: The module does not support the port-speed configuration under its current media configuration
236
- :return:
237
- :rtype:
170
+ :return: List of tuple(supported media, port count, port speed) (The port speed in Mbps, e.g. 40000 for 40G)
171
+ :rtype: List[Tuple[MediaConfigurationType, int, int]]
238
172
  """
173
+ supported_media_list = []
174
+ for media_item in module.info.media_info_list: # type: ignore
175
+ for port_speed_config in media_item.supported_configs:
176
+ supported_media_list.append((media_item.cage_type, port_speed_config.port_count, port_speed_config.port_speed))
239
177
 
240
- # reserve the module first
241
- await reserve_module(module, force)
242
-
243
- # get the supported media by the module
244
- supported_media_list = get_module_supported_media(module)
245
-
246
- # get the current media of the module
247
- reply = await module.config.media.get()
248
- current_media = reply.media_config
249
-
250
- # set the module port speed if we can find the port-speed in the corresponding media
251
- for item in supported_media_list:
252
- if all(
253
- (
254
- item["media"] == enums.MediaConfigurationType(current_media),
255
- item["port_count"] == port_count,
256
- item["port_speed"] == port_speed,
257
- )
258
- ):
259
- portspeed_list = [port_count] + port_count * [port_speed]
260
- await module.config.port_speed.set(portspeed_list=portspeed_list)
261
- await release_module(module, False)
262
- return None
263
- raise NotSupportPortSpeed(module)
178
+ return supported_media_list
264
179
 
265
180
 
266
181
  async def set_module_config(
@@ -285,28 +200,51 @@ async def set_module_config(
285
200
  :raises NotSupportMediaPortSpeed: the provided media, port count and port speed configuration is not supported by the module
286
201
  """
287
202
 
288
- # reserve the module first
289
- await reserve_module(module, force)
203
+ await set_module_configs([(module, media, port_count, port_speed)], force)
290
204
 
291
- # get the supported media
292
- supported_media_list = get_module_supported_media(module)
293
205
 
294
- # set the module media if the target media is found in supported media
295
- for item in supported_media_list:
296
- if all(
297
- (
298
- item["media"] == media,
299
- item["port_count"] == port_count,
300
- item["port_speed"] == port_speed,
301
- )
302
- ):
303
- portspeed_list = [port_count] + port_count * [port_speed]
304
- await module.config.media.set(media_config=media)
305
- await module.config.port_speed.set(portspeed_list=portspeed_list)
306
- await release_module(module, False)
307
- return None
308
- raise NotSupportMediaPortSpeed(module)
206
+ async def set_module_configs(module_configs: List[Tuple[Union[GenericL23Module, ModuleChimera], enums.MediaConfigurationType, int, int]], force: bool = True) -> None:
309
207
 
208
+ """Configure multiple modules with specified media, port count and port speed.
209
+
210
+ :param module_configs: List of module configuration tuples.
211
+
212
+ Each tuple contains (module object, target media, target port count, target port speed in Mbps, should forcibly reserve the module)
213
+
214
+ :type module_configs: List[Tuple[Union[GenericL23Module, ModuleChimera], enums.MediaConfigurationType, int, int, bool]]
215
+
216
+ :param force: should forcibly reserve the modules, defaults to True
217
+ :type force: bool, optional
218
+
219
+ :raises NotSupportMediaPortSpeed: one of the provided media, port count and port speed configuration is not supported by the corresponding module.
220
+ """
221
+ # reserve the modules
222
+ await reserve_modules([module for (module, _, _, _) in module_configs], force)
223
+
224
+ for module_config in module_configs:
225
+ module, media, port_count, port_speed = module_config
226
+
227
+ # get the supported media
228
+ supported_media_list = get_module_supported_configs(module)
229
+
230
+ # set the module media if the target media is found in supported media
231
+ for item in supported_media_list:
232
+ if all(
233
+ (
234
+ item[0] == media,
235
+ item[1] == port_count,
236
+ item[2] == port_speed,
237
+ )
238
+ ):
239
+ portspeed_list = [port_count] + port_count * [port_speed]
240
+ await module.config.media.set(media_config=media)
241
+ await module.config.port_speed.set(portspeed_list=portspeed_list)
242
+ return None
243
+ raise NotSupportMediaPortSpeed(module)
244
+
245
+ # release the modules
246
+ await release_modules([module for (module, _, _, _) in module_configs], False)
247
+
310
248
 
311
249
  async def get_module_eol_date(module: GenericAnyModule) -> str:
312
250
  """
@@ -338,35 +276,27 @@ async def get_module_eol_days(module: GenericAnyModule) -> int:
338
276
  return timedelta.days
339
277
 
340
278
 
341
- from xoa_driver.modules import GenericAnyModule, GenericL23Module, ModuleChimera, Z800FreyaModule, Z1600EdunModule
342
- async def get_module_cage_insertion_count(module: Union[Z800FreyaModule, Z1600EdunModule], cage_index: int) -> int:
279
+ async def get_cage_insertions(module: Union[Z800FreyaModule, Z1600EdunModule]) -> Tuple[int, ...]:
343
280
  """
344
- Get module cage insertion count
281
+ Get module cage insertion count of each cage
345
282
 
346
- :param module: The Z800 Freya module object
283
+ :param module: The Z800 Freya/Z1600 Edun module object
347
284
  :type module: Union[Z800FreyaModule, Z1600EdunModule]
348
- :param cage_index: The cage index
349
- :type module: int
350
- :return: Insertion count of the cage
351
- :rtype: int
285
+ :return: Insertion count of each cage
286
+ :rtype: Tuple[int, ...]
352
287
  """
353
288
  resp = await module.health.cage_insertion.get()
354
289
  info_js = resp.info
355
290
  info_dict = json.loads(info_js)
356
- if 0 <= cage_index < len(info_dict['1']['data']):
357
- result = info_dict['1']['data'][cage_index]['insert_count']
358
- elif cage_index < 0:
359
- result = -1
360
- else:
361
- result = -1
291
+ result = tuple(cage['insert_count'] for cage in info_dict['1']['data'])
362
292
  return result
363
293
 
364
294
 
365
- async def get_module_cage_count(module: Union[Z800FreyaModule, Z1600EdunModule]) -> int:
295
+ async def get_cage_count(module: Union[Z800FreyaModule, Z1600EdunModule]) -> int:
366
296
  """
367
297
  Get module cage count
368
298
 
369
- :param module: The Z800 Freya module object
299
+ :param module: The Z800 Freya/Z1600 Edun module object
370
300
  :type module: Union[Z800FreyaModule, Z1600EdunModule]
371
301
  :return: The number of cages in the module
372
302
  :rtype: int
@@ -384,76 +314,102 @@ async def get_module_cage_count(module: Union[Z800FreyaModule, Z1600EdunModule])
384
314
  # region Ports
385
315
 
386
316
 
387
- def get_all_ports(tester: GenericAnyTester) -> tuple[GenericAnyPort, ...]:
317
+ def obtain_ports_by_ids(tester: L23Tester, port_ids: List[str], separator: str = "/") -> tuple[GenericAnyPort, ...]:
388
318
  """
389
- Get all ports of the tester
319
+ Get ports of the tester specified by port ids
390
320
 
391
321
  :param tester: The tester object
392
- :type tester: :class:`~xoa_driver.testers.GenericAnyTester`
393
- :return: List of port objects
394
- :rtype: tuple[GenericAnyPort]
395
- """
396
- all_ports_ = (m.ports for m in get_modules(tester))
397
- return tuple(chain.from_iterable(all_ports_))
322
+ :type tester: :class:`~xoa_driver.testers.L23Tester`
323
+ :param port_ids: The port ids.
324
+
325
+ The port index with format ``m/p``, m is module index, p is port index, e.g. ["1/3", "2/4"].
398
326
 
327
+ Use ``1/*`` to get all ports of module 1.
399
328
 
400
- def get_ports(tester: GenericAnyTester, module_id: int) -> tuple[GenericAnyPort, ...]:
401
- """
402
- Get all ports of the module
329
+ Use ``*/1`` to get port 1 of all modules.
403
330
 
404
- :param tester: The tester object
405
- :type tester: :class:`~xoa_driver.testers.GenericAnyTester`
406
- :param module_id: The module index
407
- :type module_id: int
331
+ Use ``*``, or ``*/*`` to get all ports of all modules.
332
+
333
+ Use an empty list to get all ports of all modules.
334
+
335
+ :type port_ids: List[str]
336
+ :param separator: The separator between module index and port index in port id, defaults to `/`
337
+ :type separator: str, optional
408
338
  :return: List of port objects
409
339
  :rtype: tuple[GenericAnyPort]
410
340
  """
411
- module = get_module(tester, module_id)
412
- return tuple(module.ports)
413
-
414
341
 
415
- def get_port(tester: GenericAnyTester, module_id: int, port_id: int) -> GenericAnyPort:
342
+ returned_ports = []
343
+ if len(port_ids) == 0 or f"*{separator}*" in port_ids or f"*" in port_ids: # [] or ["*/*"] or ["*"]
344
+ all_ports_ = (m.ports for m in tester.modules)
345
+ return tuple(chain.from_iterable(all_ports_))
346
+ else:
347
+ for port_id in port_ids:
348
+ if separator not in port_id:
349
+ continue
350
+ mid = port_id.split(separator)[0]
351
+ if mid != "*":
352
+ module = tester.modules.obtain(int(mid))
353
+ pid = port_id.split(separator)[1]
354
+ if pid == "*": # ["1/*"]
355
+ returned_ports.extend(list(module.ports))
356
+ else: # ["1/3"]
357
+ returned_ports.append(module.ports.obtain(int(pid)))
358
+ else: # ["*/1"]
359
+ pid = port_id.split(separator)[1]
360
+ for module in tester.modules:
361
+ returned_ports.append(module.ports.obtain(int(pid)))
362
+ return tuple(returned_ports)
363
+
364
+
365
+ def obtain_port_by_id(tester: L23Tester, port_id: str, separator: str = "/") -> GenericAnyPort:
416
366
  """
417
367
  Get a port of the module
418
368
 
419
369
  :param tester: The tester object
420
- :type tester: :class:`~xoa_driver.testers.GenericAnyTester`
421
- :param module_id: The module index
422
- :type module_id: int
423
- :param port_id: The port index
424
- :type port_id: int
370
+ :type tester: :class:`~xoa_driver.testers.L23Tester`
371
+ :param port_id: The port index with format "m/p", m is module index, p is port index, e.g. "1/3". Wildcard "*" is not allowed.
372
+ :type port_id: str
373
+ :param separator: The separator between module index and port index in port id, defaults to "/"
374
+ :type separator: str, optional
425
375
  :raises NoSuchPortError: No port found with the index
426
376
  :return: The port object
427
377
  :rtype: GenericAnyPort
428
378
  """
429
- module = get_module(tester, module_id)
430
- return module.ports.obtain(port_id)
379
+ if "*" in port_id:
380
+ raise ValueError("Wildcard '*' is not allowed in port_id for obtain_port_by_id function.")
381
+ if separator not in port_id:
382
+ raise ValueError(f"Invalid port_id format: {port_id}. Expected format 'm{separator}p'.")
383
+ return obtain_ports_by_ids(tester, [port_id], separator=separator)[0]
431
384
 
432
385
 
433
- async def reserve_port(port: GenericAnyPort, force: bool = True, reset: bool = False) -> None:
386
+ async def reserve_ports(ports: list[GenericAnyPort], force: bool = True, reset: bool = False) -> None:
434
387
  """
435
388
  Reserve a port regardless whether it is owned by others or not.
436
389
 
437
- :param port: The port to reserve
438
- :type port: GenericAnyPort
439
- :param force: Should force reserve the port
440
- :type force: boolean
390
+ :param ports: The ports to reserve
391
+ :type ports: list[GenericAnyPort]
392
+ :param force: Should force reserve the ports, defaults to True
393
+ :type force: boolean, optional
394
+ :param reset: Should reset the ports after reserving, defaults to False
395
+ :type reset: boolean, optional
441
396
  :return:
442
397
  :rtype: None
443
398
  """
444
- r = await port.reservation.get()
445
- if force and r.status == enums.ReservedStatus.RESERVED_BY_OTHER:
446
- await apply(
447
- port.reservation.set_relinquish(),
448
- port.reservation.set_reserve(),
449
- )
450
- elif r.status == enums.ReservedStatus.RELEASED:
451
- await port.reservation.set_reserve()
452
- if reset:
453
- await port.reset.set()
399
+ for port in ports:
400
+ r = await port.reservation.get()
401
+ if force and r.status == enums.ReservedStatus.RESERVED_BY_OTHER:
402
+ await apply(
403
+ port.reservation.set_relinquish(),
404
+ port.reservation.set_reserve(),
405
+ )
406
+ elif r.status == enums.ReservedStatus.RELEASED:
407
+ await port.reservation.set_reserve()
408
+ if reset:
409
+ await port.reset.set()
454
410
 
455
411
 
456
- async def release_port(port: GenericAnyPort) -> None:
412
+ async def release_ports(ports: List[GenericAnyPort]) -> None:
457
413
  """
458
414
  Free a port. If the port is reserved by you, release the port. If the port is reserved by others, relinquish the port. The port should have no owner afterwards.
459
415
 
@@ -462,23 +418,24 @@ async def release_port(port: GenericAnyPort) -> None:
462
418
  :return:
463
419
  :rtype: None
464
420
  """
465
- r = await port.reservation.get()
466
- if r.status == enums.ReservedStatus.RESERVED_BY_OTHER:
467
- await port.reservation.set_relinquish()
468
- elif r.status == enums.ReservedStatus.RESERVED_BY_YOU:
469
- await port.reservation.set_release()
421
+ for port in ports:
422
+ r = await port.reservation.get()
423
+ if r.status == enums.ReservedStatus.RESERVED_BY_OTHER:
424
+ await port.reservation.set_relinquish()
425
+ elif r.status == enums.ReservedStatus.RESERVED_BY_YOU:
426
+ await port.reservation.set_release()
470
427
 
471
428
 
472
- async def release_ports(*ports: GenericAnyPort) -> None:
429
+ async def reset_ports(ports: List[GenericAnyPort]) -> None:
473
430
  """
474
- Free a list of ports. If the port is reserved by you, release the port. If the port is reserved by others, relinquish the port. The port should have no owner afterwards.
431
+ Reset a list of ports.
475
432
 
476
- :param ports: The ports to free
477
- :type ports: GenericAnyPort
433
+ :param ports: The ports to reset
434
+ :type ports: List[GenericAnyPort]
435
+ :return:
436
+ :rtype: None
478
437
  """
479
- await asyncio.gather(*(release_port(port=p) for p in ports))
480
-
481
-
438
+ await asyncio.gather(*(port.reset.set() for port in ports))
482
439
 
483
440
  # endregion
484
441
 
@@ -498,24 +455,23 @@ async def remove_streams(port: GenericL23Port) -> None:
498
455
  # endregion
499
456
 
500
457
  __all__ = (
501
- "release_module",
502
- "release_port",
503
- "release_ports",
458
+ "reserve_tester",
504
459
  "release_tester",
505
- "get_all_ports",
506
- "get_module",
460
+ "get_chassis_sys_uptime",
461
+ "obtain_modules_by_ids",
462
+ "reserve_modules",
463
+ "release_modules",
464
+ "get_module_supported_configs",
465
+ "set_module_configs",
466
+ "set_module_config",
507
467
  "get_module_eol_date",
508
468
  "get_module_eol_days",
509
- "get_module_supported_media",
510
- "get_modules",
511
- "get_port",
512
- "get_ports",
513
- "reserve_module",
514
- "reserve_port",
515
- "reserve_tester",
516
- "set_module_media_config",
517
- "set_module_port_config",
469
+ "get_cage_insertions",
470
+ "get_cage_count",
471
+ "obtain_ports_by_ids",
472
+ "obtain_port_by_id",
473
+ "reserve_ports",
474
+ "release_ports",
475
+ "reset_ports",
518
476
  "remove_streams",
519
- "get_module_cage_insertion_count",
520
- "get_chassis_sys_uptime_sec",
521
477
  )
@@ -24,7 +24,7 @@ def dictionize_autoneg_status(
24
24
  ) -> dict[str, Any]:
25
25
  _is_enabled = True if status.mode == enums.AutoNegMode.ANEG_ON else False
26
26
  _ta_hcd_status = status.tech_ability_hcd_status
27
- if _ta_hcd_status == enums.FreyaTechAbilityHCDStatus.FAILED:
27
+ if _ta_hcd_status == enums.AutoNegTechAbilityHCDStatus.FAILED:
28
28
  _ta_hcd_value = "N/A"
29
29
  _fec_result_value = "N/A"
30
30
  else:
@@ -138,12 +138,17 @@ def dictionize_lt_status(
138
138
 
139
139
 
140
140
  def dictionize_txtap_get(r: commands.PP_PHYTXEQ.GetDataAttr) -> dict[str, int]:
141
+ _pre = r.tap_values[0]
142
+ _main = r.tap_values[1]
143
+ _post = r.tap_values[2]
144
+ _pre2 = r.tap_values[3]
145
+ _pre3 = r.tap_values[4]
141
146
  return {
142
- "c(-3)": r.pre3_post2,
143
- "c(-2)": r.pre2,
144
- "c(-1)": r.pre,
145
- "c(0)": r.main,
146
- "c(1)": r.post,
147
+ "c(-3)": _pre3,
148
+ "c(-2)": _pre2,
149
+ "c(-1)": _pre,
150
+ "c(0)": _main,
151
+ "c(1)": _post,
147
152
  }
148
153
 
149
154