PyPlumIO 0.5.20__py3-none-any.whl → 0.5.21__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.
- {PyPlumIO-0.5.20.dist-info → PyPlumIO-0.5.21.dist-info}/METADATA +5 -5
- {PyPlumIO-0.5.20.dist-info → PyPlumIO-0.5.21.dist-info}/RECORD +14 -14
- pyplumio/_version.py +2 -2
- pyplumio/devices/ecomax.py +33 -23
- pyplumio/devices/mixer.py +3 -2
- pyplumio/devices/thermostat.py +3 -2
- pyplumio/helpers/event_manager.py +9 -9
- pyplumio/helpers/task_manager.py +3 -4
- pyplumio/protocol.py +6 -11
- pyplumio/structures/ecomax_parameters.py +0 -2
- pyplumio/structures/network_info.py +3 -3
- {PyPlumIO-0.5.20.dist-info → PyPlumIO-0.5.21.dist-info}/LICENSE +0 -0
- {PyPlumIO-0.5.20.dist-info → PyPlumIO-0.5.21.dist-info}/WHEEL +0 -0
- {PyPlumIO-0.5.20.dist-info → PyPlumIO-0.5.21.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: PyPlumIO
|
3
|
-
Version: 0.5.
|
3
|
+
Version: 0.5.21
|
4
4
|
Summary: PyPlumIO is a native ecoNET library for Plum ecoMAX controllers.
|
5
5
|
Author-email: Denis Paavilainen <denpa@denpa.pro>
|
6
6
|
License: MIT License
|
@@ -35,11 +35,11 @@ Provides-Extra: test
|
|
35
35
|
Requires-Dist: codespell ==2.3.0 ; extra == 'test'
|
36
36
|
Requires-Dist: coverage ==7.5.3 ; extra == 'test'
|
37
37
|
Requires-Dist: mypy ==1.10.0 ; extra == 'test'
|
38
|
-
Requires-Dist: pyserial-asyncio-fast ==0.
|
39
|
-
Requires-Dist: pytest ==8.2.
|
38
|
+
Requires-Dist: pyserial-asyncio-fast ==0.12 ; extra == 'test'
|
39
|
+
Requires-Dist: pytest ==8.2.2 ; extra == 'test'
|
40
40
|
Requires-Dist: pytest-asyncio ==0.23.7 ; extra == 'test'
|
41
|
-
Requires-Dist: ruff ==0.4.
|
42
|
-
Requires-Dist: tox ==4.15.
|
41
|
+
Requires-Dist: ruff ==0.4.9 ; extra == 'test'
|
42
|
+
Requires-Dist: tox ==4.15.1 ; extra == 'test'
|
43
43
|
Requires-Dist: types-pyserial ==3.5.0.20240527 ; extra == 'test'
|
44
44
|
|
45
45
|
# PyPlumIO is a native ecoNET library for Plum ecoMAX controllers.
|
@@ -1,30 +1,30 @@
|
|
1
1
|
pyplumio/__init__.py,sha256=cclyAwy7OsW673iHcwkVrJSNnf32oF51Y_0uEEF5cdI,3293
|
2
2
|
pyplumio/__main__.py,sha256=3IwHHSq-iay5FaeMc95klobe-xv82yydSKcBE7BFZ6M,500
|
3
|
-
pyplumio/_version.py,sha256=
|
3
|
+
pyplumio/_version.py,sha256=qwvYpiZ4pV_W2HOchGsudGTbl7hCvV-xhS0ii39Ac0I,413
|
4
4
|
pyplumio/connection.py,sha256=ZZHXHFpbOBVd9DGZV_H8lpdYtYoc3nP9fRolKATKDnQ,6096
|
5
5
|
pyplumio/const.py,sha256=8rpiVbVb5R_6Rm6J2sgCnaVrkD-2Fzhd1RYMz0MBgwo,3915
|
6
6
|
pyplumio/exceptions.py,sha256=193z3zfnswYhIYPzCIpxCiWat4qI3cV85sqT4YOSo-4,699
|
7
7
|
pyplumio/filters.py,sha256=bIonYc_QbGMsL8aWweSLUmP7gKqDD646zELf_PqqQBg,11161
|
8
|
-
pyplumio/protocol.py,sha256=
|
8
|
+
pyplumio/protocol.py,sha256=Ci4p4bqADfWeGk9fzcGMudRbe-dFFa1UNot9no5Lj3M,7845
|
9
9
|
pyplumio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
10
|
pyplumio/stream.py,sha256=DqMqdi3HG9hODgfGo4eTKLkfoaSh5RS4kBHNn3ODvVg,4472
|
11
11
|
pyplumio/utils.py,sha256=GV7P1hPLoQsx3uqYviQ15FXJmkmTxwtDibAc-yRarvo,688
|
12
12
|
pyplumio/devices/__init__.py,sha256=O5SyEt_x1nJ1JYkG6v3dTZ54tu9sKIdj4l256JhvLHg,6585
|
13
|
-
pyplumio/devices/ecomax.py,sha256=
|
13
|
+
pyplumio/devices/ecomax.py,sha256=IPHyC8OjnGaQ_ZztcchgQjEJmNj8LfnP9sTJyslEQ14,16914
|
14
14
|
pyplumio/devices/ecoster.py,sha256=J4YtPmFmFwaq4LzYf28aMmB97cRAbMsVyUdBLGki42g,313
|
15
|
-
pyplumio/devices/mixer.py,sha256=
|
16
|
-
pyplumio/devices/thermostat.py,sha256=
|
15
|
+
pyplumio/devices/mixer.py,sha256=qJAmar7DdsQL1Syg0WOCBVQn3GyBTWEVyr5ZfpGytCk,2975
|
16
|
+
pyplumio/devices/thermostat.py,sha256=HCnLVBX8mn6lmpCgl1DbDoCMI6T97sqmK-36cYcjXVA,2430
|
17
17
|
pyplumio/frames/__init__.py,sha256=BAMbMHbn4F9psrf3sv0eJQA2Jd86qf7LQ5vBQY59gjA,7462
|
18
18
|
pyplumio/frames/messages.py,sha256=QLuvo1wlpDZR1MpOdu7s6fRUX20Dtt6EWFLkAsqyax4,3617
|
19
19
|
pyplumio/frames/requests.py,sha256=Ra8xH5oKYhkEUtadN-9ZsJKkt5xZkz5O7edQVsDhNsM,7221
|
20
20
|
pyplumio/frames/responses.py,sha256=j4awA2-MfsoPdENC4Fvae4_Oa70rDhH19ebmEoAqhh8,6532
|
21
21
|
pyplumio/helpers/__init__.py,sha256=H2xxdkF-9uADLwEbfBUoxNTdwru3L5Z2cfJjgsuRsn0,31
|
22
22
|
pyplumio/helpers/data_types.py,sha256=H_pYkLgIu30lDFU0UUZ1V3vYxa9A_-1nhiJu-HCLuoc,8212
|
23
|
-
pyplumio/helpers/event_manager.py,sha256=
|
23
|
+
pyplumio/helpers/event_manager.py,sha256=dCNLnSRZgewZ9Ppi-JtkxtvOmNd4ZejA7UT4oAT8FWM,5865
|
24
24
|
pyplumio/helpers/factory.py,sha256=eiTkYUCernUn0VNDDdEN4IyjNPrXK8vnJESXyLaqFzE,1017
|
25
25
|
pyplumio/helpers/parameter.py,sha256=gYCA2SLU_lbdtQZq5U64yzpyLoEIa0R1wyJJGmgL63I,8699
|
26
26
|
pyplumio/helpers/schedule.py,sha256=-IZJ-CU4PhFlsE586wTw--ovDrTo2Hs4JneCHhc0e-Y,5013
|
27
|
-
pyplumio/helpers/task_manager.py,sha256=
|
27
|
+
pyplumio/helpers/task_manager.py,sha256=y5j7u31V6UE7g2ZhdsYsPykY-Awo73oWsNRUOrLSILg,1075
|
28
28
|
pyplumio/helpers/timeout.py,sha256=k-829fBcHT5IR3isrMSgNbPYK-ubeY1BAwndCDIiX9E,824
|
29
29
|
pyplumio/helpers/typing.py,sha256=y55UdpIpPIRuUBPgfPmZHAwPdIUjQO924-kO7AVXhes,685
|
30
30
|
pyplumio/helpers/uid.py,sha256=yaBjcsFKuhOaznftk33kdIepQHpK-labEQr59QNKhPM,975
|
@@ -32,7 +32,7 @@ pyplumio/structures/__init__.py,sha256=EjK-5qJZ0F7lpP2b6epvTMg9cIBl4Kn91nqNkEcLw
|
|
32
32
|
pyplumio/structures/alerts.py,sha256=a1CIf8vSEj5aefdqECIfCY5kV4tQ4kabMkp-_ixeWic,3260
|
33
33
|
pyplumio/structures/boiler_load.py,sha256=p3mOzZUU-g7A2tG_yp8podEqpI81hlsOZmHELyPNRY8,838
|
34
34
|
pyplumio/structures/boiler_power.py,sha256=72qsvccg49FdRdXv2f2K5sGpjT7wAOLFjlIGWpO-DVg,901
|
35
|
-
pyplumio/structures/ecomax_parameters.py,sha256=
|
35
|
+
pyplumio/structures/ecomax_parameters.py,sha256=6HVEh4aNw0CGZD3CVQeYyKXQ0pzueQR_Tpm5fF3_0hA,25815
|
36
36
|
pyplumio/structures/fan_power.py,sha256=Q5fv-7_2NVuLeQPIVIylvgN7M8-a9D8rRUE0QGjyS3w,871
|
37
37
|
pyplumio/structures/frame_versions.py,sha256=x_OSirGYopQYgsRZIM3b1YlKHNIPmCbvAzhzO1wqy5k,1560
|
38
38
|
pyplumio/structures/fuel_consumption.py,sha256=_p2dI4H67Eopn7IF0Gj77A8c_8lNKhhDDAtmugxLd4s,976
|
@@ -41,7 +41,7 @@ pyplumio/structures/lambda_sensor.py,sha256=6iUVyrPe6_QaGPo1lRzOfqorcTIIXRwnq3h8
|
|
41
41
|
pyplumio/structures/mixer_parameters.py,sha256=ny7Ox94IooQd1ua22zGYkXLFaZQWGUYLEIM2_8vXk0U,8249
|
42
42
|
pyplumio/structures/mixer_sensors.py,sha256=O91929Ts1YXFmKdPRc1r_BYDgrqkv5QVtE1nGzLpuAI,2260
|
43
43
|
pyplumio/structures/modules.py,sha256=ukju4TQmRRJfgl94QU4zytZLU5px8nw3sgfSLn9JysU,2520
|
44
|
-
pyplumio/structures/network_info.py,sha256=
|
44
|
+
pyplumio/structures/network_info.py,sha256=ws2UdOhB89oKqmtW1Vsmfj0InRW4Sp6_kL1d4psk-8w,4094
|
45
45
|
pyplumio/structures/output_flags.py,sha256=07N0kxlvR5WZAURuChk_BqSiXR8eaQrtI5qlkgCf4Yc,1345
|
46
46
|
pyplumio/structures/outputs.py,sha256=1xsJPkjN643-aFawqVoupGatUIUJfQG_g252n051Qi0,1916
|
47
47
|
pyplumio/structures/pending_alerts.py,sha256=Uq9WpB4MW9AhDkqmDhk-g0J0h4pVq0Q50z12dYEv6kY,739
|
@@ -54,8 +54,8 @@ pyplumio/structures/statuses.py,sha256=wkoynyMRr1VREwfBC6vU48kPA8ZQ83pcXuciy2xHJ
|
|
54
54
|
pyplumio/structures/temperatures.py,sha256=1CDzehNmbALz1Jyt_9gZNIk52q6Wv-xQXjijVDCVYec,2337
|
55
55
|
pyplumio/structures/thermostat_parameters.py,sha256=pjbWsT6z7mlDiUrC5MWGqMtGP0deeVMYeeTa7yGEwJ8,7706
|
56
56
|
pyplumio/structures/thermostat_sensors.py,sha256=ZmjWgYtTZ5M8Lnz_Q5N4JD8G3MvEmByPFjYsy6XZOmo,3177
|
57
|
-
PyPlumIO-0.5.
|
58
|
-
PyPlumIO-0.5.
|
59
|
-
PyPlumIO-0.5.
|
60
|
-
PyPlumIO-0.5.
|
61
|
-
PyPlumIO-0.5.
|
57
|
+
PyPlumIO-0.5.21.dist-info/LICENSE,sha256=m-UuZFjXJ22uPTGm9kSHS8bqjsf5T8k2wL9bJn1Y04o,1088
|
58
|
+
PyPlumIO-0.5.21.dist-info/METADATA,sha256=mc-yvbFJArE1iYRxb8RCkL2MdoKZjkZKOn8nWgWD8t8,5415
|
59
|
+
PyPlumIO-0.5.21.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
60
|
+
PyPlumIO-0.5.21.dist-info/top_level.txt,sha256=kNBz9UPPkPD9teDn3U_sEy5LjzwLm9KfADCXtBlbw8A,9
|
61
|
+
PyPlumIO-0.5.21.dist-info/RECORD,,
|
pyplumio/_version.py
CHANGED
pyplumio/devices/ecomax.py
CHANGED
@@ -4,7 +4,6 @@ from __future__ import annotations
|
|
4
4
|
|
5
5
|
import asyncio
|
6
6
|
from collections.abc import Generator, Iterable, Sequence
|
7
|
-
from contextlib import suppress
|
8
7
|
import logging
|
9
8
|
import time
|
10
9
|
from typing import Any, ClassVar, Final
|
@@ -18,7 +17,7 @@ from pyplumio.const import (
|
|
18
17
|
DeviceType,
|
19
18
|
FrameType,
|
20
19
|
)
|
21
|
-
from pyplumio.devices import AddressableDevice
|
20
|
+
from pyplumio.devices import AddressableDevice, SubDevice
|
22
21
|
from pyplumio.devices.mixer import Mixer
|
23
22
|
from pyplumio.devices.thermostat import Thermostat
|
24
23
|
from pyplumio.filters import on_change
|
@@ -263,8 +262,12 @@ class EcoMAX(AddressableDevice):
|
|
263
262
|
if not parameters:
|
264
263
|
return False
|
265
264
|
|
266
|
-
|
267
|
-
|
265
|
+
await asyncio.gather(
|
266
|
+
*[
|
267
|
+
mixer.dispatch(ATTR_MIXER_PARAMETERS, parameters[mixer.index])
|
268
|
+
for mixer in self._mixers(indexes=parameters.keys())
|
269
|
+
]
|
270
|
+
)
|
268
271
|
|
269
272
|
return True
|
270
273
|
|
@@ -278,14 +281,18 @@ class EcoMAX(AddressableDevice):
|
|
278
281
|
if not sensors:
|
279
282
|
return False
|
280
283
|
|
281
|
-
|
282
|
-
|
284
|
+
await asyncio.gather(
|
285
|
+
*[
|
286
|
+
mixer.dispatch(ATTR_MIXER_SENSORS, sensors[mixer.index])
|
287
|
+
for mixer in self._mixers(indexes=sensors.keys())
|
288
|
+
]
|
289
|
+
)
|
283
290
|
|
284
291
|
return True
|
285
292
|
|
286
293
|
async def _add_schedules(
|
287
294
|
self, schedules: list[tuple[int, list[list[bool]]]]
|
288
|
-
) -> dict[str,
|
295
|
+
) -> dict[str, Schedule]:
|
289
296
|
"""Add schedules to the dataset."""
|
290
297
|
return {
|
291
298
|
SCHEDULES[index]: Schedule(
|
@@ -333,8 +340,9 @@ class EcoMAX(AddressableDevice):
|
|
333
340
|
For each sensor dispatch an event with the sensor's name and
|
334
341
|
value.
|
335
342
|
"""
|
336
|
-
|
337
|
-
|
343
|
+
await asyncio.gather(
|
344
|
+
*[self.dispatch(name, value) for name, value in sensors.items()]
|
345
|
+
)
|
338
346
|
|
339
347
|
return True
|
340
348
|
|
@@ -371,10 +379,14 @@ class EcoMAX(AddressableDevice):
|
|
371
379
|
if not parameters:
|
372
380
|
return False
|
373
381
|
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
382
|
+
await asyncio.gather(
|
383
|
+
*[
|
384
|
+
thermostat.dispatch(
|
385
|
+
ATTR_THERMOSTAT_PARAMETERS, parameters[thermostat.index]
|
386
|
+
)
|
387
|
+
for thermostat in self._thermostats(indexes=parameters.keys())
|
388
|
+
]
|
389
|
+
)
|
378
390
|
|
379
391
|
return True
|
380
392
|
|
@@ -401,10 +413,12 @@ class EcoMAX(AddressableDevice):
|
|
401
413
|
if not sensors:
|
402
414
|
return False
|
403
415
|
|
404
|
-
|
405
|
-
|
406
|
-
ATTR_THERMOSTAT_SENSORS, sensors[thermostat.index]
|
407
|
-
|
416
|
+
await asyncio.gather(
|
417
|
+
*[
|
418
|
+
thermostat.dispatch(ATTR_THERMOSTAT_SENSORS, sensors[thermostat.index])
|
419
|
+
for thermostat in self._thermostats(indexes=sensors.keys())
|
420
|
+
]
|
421
|
+
)
|
408
422
|
|
409
423
|
return True
|
410
424
|
|
@@ -438,10 +452,6 @@ class EcoMAX(AddressableDevice):
|
|
438
452
|
"""Shutdown tasks for the ecoMAX controller and sub-devices."""
|
439
453
|
mixers = self.get_nowait(ATTR_MIXERS, {})
|
440
454
|
thermostats = self.get_nowait(ATTR_THERMOSTATS, {})
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
with suppress(AttributeError):
|
445
|
-
await self.regdata.shutdown()
|
446
|
-
|
455
|
+
devices: Iterable[SubDevice] = (mixers | thermostats).values()
|
456
|
+
await asyncio.gather(*[device.shutdown() for device in devices])
|
447
457
|
await super().shutdown()
|
pyplumio/devices/mixer.py
CHANGED
@@ -37,8 +37,9 @@ class Mixer(SubDevice):
|
|
37
37
|
For each sensor dispatch an event with the
|
38
38
|
sensor's name and value.
|
39
39
|
"""
|
40
|
-
|
41
|
-
|
40
|
+
await asyncio.gather(
|
41
|
+
*[self.dispatch(name, value) for name, value in sensors.items()]
|
42
|
+
)
|
42
43
|
|
43
44
|
return True
|
44
45
|
|
pyplumio/devices/thermostat.py
CHANGED
@@ -33,8 +33,9 @@ class Thermostat(SubDevice):
|
|
33
33
|
For each sensor dispatch an event with the
|
34
34
|
sensor's name and value.
|
35
35
|
"""
|
36
|
-
|
37
|
-
|
36
|
+
await asyncio.gather(
|
37
|
+
*[self.dispatch(name, value) for name, value in sensors.items()]
|
38
|
+
)
|
38
39
|
|
39
40
|
return True
|
40
41
|
|
@@ -138,16 +138,16 @@ class EventManager(TaskManager):
|
|
138
138
|
"""Call a registered callbacks and dispatch the event without waiting."""
|
139
139
|
self.create_task(self.dispatch(name, value))
|
140
140
|
|
141
|
-
def load(self, data: dict[str, Any]) -> None:
|
142
|
-
"""Load
|
143
|
-
|
144
|
-
async def _dispatch_events(data: dict[str, Any]) -> None:
|
145
|
-
"""Dispatch events for a loaded data."""
|
146
|
-
for key, value in data.items():
|
147
|
-
await self.dispatch(key, value)
|
148
|
-
|
141
|
+
async def load(self, data: dict[str, Any]) -> None:
|
142
|
+
"""Load event data."""
|
149
143
|
self.data = data
|
150
|
-
|
144
|
+
await asyncio.gather(
|
145
|
+
*[self.dispatch(name, value) for name, value in data.items()]
|
146
|
+
)
|
147
|
+
|
148
|
+
def load_nowait(self, data: dict[str, Any]) -> None:
|
149
|
+
"""Load event data without waiting."""
|
150
|
+
self.create_task(self.load(data))
|
151
151
|
|
152
152
|
def create_event(self, name: str) -> asyncio.Event:
|
153
153
|
"""Create an event."""
|
pyplumio/helpers/task_manager.py
CHANGED
@@ -18,15 +18,14 @@ class TaskManager:
|
|
18
18
|
|
19
19
|
def create_task(self, coro: Coroutine[Any, Any, Any]) -> asyncio.Task:
|
20
20
|
"""Create asyncio task and store a reference for it."""
|
21
|
-
task
|
21
|
+
task = asyncio.create_task(coro)
|
22
22
|
self._tasks.add(task)
|
23
23
|
task.add_done_callback(self._tasks.discard)
|
24
24
|
return task
|
25
25
|
|
26
|
-
def cancel_tasks(self) ->
|
26
|
+
def cancel_tasks(self) -> bool:
|
27
27
|
"""Cancel all tasks."""
|
28
|
-
for task in self._tasks
|
29
|
-
task.cancel()
|
28
|
+
return all(task.cancel() for task in self._tasks)
|
30
29
|
|
31
30
|
async def wait_until_done(self, return_exceptions: bool = True) -> None:
|
32
31
|
"""Wait for all tasks to complete."""
|
pyplumio/protocol.py
CHANGED
@@ -107,8 +107,7 @@ class Queues:
|
|
107
107
|
|
108
108
|
async def join(self) -> None:
|
109
109
|
"""Wait for queues to finish."""
|
110
|
-
|
111
|
-
await queue.join()
|
110
|
+
await asyncio.gather(self.read.join(), self.write.join())
|
112
111
|
|
113
112
|
|
114
113
|
class AsyncProtocol(Protocol, EventManager):
|
@@ -171,22 +170,18 @@ class AsyncProtocol(Protocol, EventManager):
|
|
171
170
|
return
|
172
171
|
|
173
172
|
self.connected.clear()
|
174
|
-
for device in self.data.values():
|
175
|
-
# Notify devices about connection loss.
|
176
|
-
await device.dispatch(ATTR_CONNECTED, False)
|
177
|
-
|
178
173
|
await self.close_writer()
|
179
|
-
|
180
|
-
|
174
|
+
await asyncio.gather(
|
175
|
+
*[device.dispatch(ATTR_CONNECTED, False) for device in self.data.values()]
|
176
|
+
)
|
177
|
+
await asyncio.gather(*[callback() for callback in self.on_connection_lost])
|
181
178
|
|
182
179
|
async def shutdown(self) -> None:
|
183
180
|
"""Shutdown protocol tasks."""
|
184
181
|
await self._queues.join()
|
185
182
|
self.cancel_tasks()
|
186
183
|
await self.wait_until_done()
|
187
|
-
for device in self.data.values()
|
188
|
-
await device.shutdown()
|
189
|
-
|
184
|
+
await asyncio.gather(*[device.shutdown() for device in self.data.values()])
|
190
185
|
if self.connected.is_set():
|
191
186
|
self.connected.clear()
|
192
187
|
await self.close_writer()
|
@@ -18,7 +18,7 @@ DEFAULT_NETMASK: Final = "255.255.255.0"
|
|
18
18
|
NETWORK_INFO_SIZE: Final = 25
|
19
19
|
|
20
20
|
|
21
|
-
@dataclass
|
21
|
+
@dataclass(frozen=True)
|
22
22
|
class EthernetParameters:
|
23
23
|
"""Represents an ethernet parameters."""
|
24
24
|
|
@@ -35,7 +35,7 @@ class EthernetParameters:
|
|
35
35
|
status: bool = True
|
36
36
|
|
37
37
|
|
38
|
-
@dataclass
|
38
|
+
@dataclass(frozen=True)
|
39
39
|
class WirelessParameters(EthernetParameters):
|
40
40
|
"""Represents a wireless network parameters."""
|
41
41
|
|
@@ -50,7 +50,7 @@ class WirelessParameters(EthernetParameters):
|
|
50
50
|
signal_quality: int = 100
|
51
51
|
|
52
52
|
|
53
|
-
@dataclass
|
53
|
+
@dataclass(frozen=True)
|
54
54
|
class NetworkInfo:
|
55
55
|
"""Represents a network parameters."""
|
56
56
|
|
File without changes
|
File without changes
|
File without changes
|