DLMS-SPODES-client 0.19.4__tar.gz → 0.19.6__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 (79) hide show
  1. {dlms_spodes_client-0.19.4/src/DLMS_SPODES_client.egg-info → dlms_spodes_client-0.19.6}/PKG-INFO +2 -2
  2. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/pyproject.toml +2 -2
  3. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/client.py +1 -1
  4. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/task.py +87 -33
  5. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6/src/DLMS_SPODES_client.egg-info}/PKG-INFO +2 -2
  6. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client.egg-info/requires.txt +1 -1
  7. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/test/client_log.txt +609 -0
  8. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/test/test_Client.py +9 -6
  9. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/.gitignore +0 -0
  10. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/README.md +0 -0
  11. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/setup.cfg +0 -0
  12. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/FCS16.py +0 -0
  13. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/__init__.py +0 -0
  14. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_common/enums/TraceLevel.py +0 -0
  15. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_common/enums/__init__.py +0 -0
  16. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/AesGcmParameter.py +0 -0
  17. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/CountType.py +0 -0
  18. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/GXByteBuffer.py +0 -0
  19. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/GXCiphering.py +0 -0
  20. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/GXDLMS.py +0 -0
  21. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSChippering.py +0 -0
  22. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSChipperingStream.py +0 -0
  23. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSConfirmedServiceError.py +0 -0
  24. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSException.py +0 -0
  25. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSLNParameters.py +0 -0
  26. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSSNParameters.py +0 -0
  27. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/GXDLMSSettings.py +0 -0
  28. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/GXReplyData.py +0 -0
  29. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/HdlcControlFrame.py +0 -0
  30. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/MBusCommand.py +0 -0
  31. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/MBusEncryptionMode.py +0 -0
  32. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/ResponseType.py +0 -0
  33. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/SetResponseType.py +0 -0
  34. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/_HDLCInfo.py +0 -0
  35. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/__init__.py +0 -0
  36. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/Access.py +0 -0
  37. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/ApplicationReference.py +0 -0
  38. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/Authentication.py +0 -0
  39. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/BerType.py +0 -0
  40. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/Command.py +0 -0
  41. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/Definition.py +0 -0
  42. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/ErrorCode.py +0 -0
  43. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/ExceptionServiceError.py +0 -0
  44. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/HardwareResource.py +0 -0
  45. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/HdlcFrameType.py +0 -0
  46. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/Initiate.py +0 -0
  47. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/LoadDataSet.py +0 -0
  48. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/ObjectType.py +0 -0
  49. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/Priority.py +0 -0
  50. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/RequestTypes.py +0 -0
  51. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/Security.py +0 -0
  52. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/Service.py +0 -0
  53. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/ServiceClass.py +0 -0
  54. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/ServiceError.py +0 -0
  55. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/Standard.py +0 -0
  56. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/StateError.py +0 -0
  57. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/Task.py +0 -0
  58. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/VdeStateError.py +0 -0
  59. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/enums/__init__.py +0 -0
  60. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/gurux_dlms/internal/_GXCommon.py +0 -0
  61. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/logger.py +0 -0
  62. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/py.typed +0 -0
  63. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/services.py +0 -0
  64. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/session.py +0 -0
  65. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client/settings.py +0 -0
  66. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client.egg-info/SOURCES.txt +0 -0
  67. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client.egg-info/dependency_links.txt +0 -0
  68. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client.egg-info/entry_points.txt +0 -0
  69. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/src/DLMS_SPODES_client.egg-info/top_level.txt +0 -0
  70. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/test/Firmwares/firmwares.dat +0 -0
  71. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/test/Firmwares/firmwares_1_2_11.dat +0 -0
  72. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/test/Firmwares/firmwares_1_7_2.dat +0 -0
  73. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/test/Types/303030/0000600101ff020009054d324d5f31/0000600102ff02000906312e332e3330.xml +0 -0
  74. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/test/Types/313031/0000600101ff020009054d324d5f31/0000600102ff02000906312e322e3131.xml +0 -0
  75. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/test/config.toml +0 -0
  76. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/test/name2.csv +0 -0
  77. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/test/test_logger.py +0 -0
  78. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/test/test_services.py +0 -0
  79. {dlms_spodes_client-0.19.4 → dlms_spodes_client-0.19.6}/test//320/272/320/276/320/275/321/204/320/270/320/263/321/203/321/200/320/260/321/206/320/270/321/217 GSM.csv" +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: DLMS_SPODES_client
3
- Version: 0.19.4
3
+ Version: 0.19.6
4
4
  Summary: dlms-spodes
5
5
  Author-email: Serj Kotilevski <youserj@outlook.com>
6
6
  Project-URL: Source, https://github.com/youserj/SPODESclient_prj
@@ -13,7 +13,7 @@ Description-Content-Type: text/markdown
13
13
  Requires-Dist: pydantic>=2.11
14
14
  Requires-Dist: pycryptodomex>=3.22.0
15
15
  Requires-Dist: semver>=3.0
16
- Requires-Dist: StructResult<0.9,>=0.8.10
16
+ Requires-Dist: StructResult<0.10,>=0.9.1
17
17
  Requires-Dist: DLMS-SPODES-communications<1.5,>=1.4.9
18
18
  Requires-Dist: DLMS_SPODES<0.88,>=0.87.6
19
19
  Requires-Dist: DLMSadapter<0.8,>=0.7.5
@@ -15,7 +15,7 @@ exclude = ["Types"]
15
15
 
16
16
  [project]
17
17
  name = "DLMS_SPODES_client"
18
- version = "0.19.4"
18
+ version = "0.19.6"
19
19
  requires-python = ">= 3.12"
20
20
  authors = [
21
21
  {name="Serj Kotilevski", email="youserj@outlook.com"}
@@ -24,7 +24,7 @@ dependencies = [
24
24
  "pydantic>=2.11",
25
25
  "pycryptodomex >= 3.22.0",
26
26
  "semver >= 3.0",
27
- "StructResult >= 0.8.10, <0.9",
27
+ "StructResult >= 0.9.1, <0.10",
28
28
  "DLMS-SPODES-communications >= 1.4.9, <1.5",
29
29
  "DLMS_SPODES >= 0.87.6, < 0.88",
30
30
  "DLMSadapter >= 0.7.5, < 0.8",
@@ -970,7 +970,7 @@ class Client:
970
970
  def set_params(self, field: str, value: str):
971
971
  self.__dict__[field] = eval(value)
972
972
 
973
- async def close(self):
973
+ async def close(self) -> None:
974
974
  """close , media is open"""
975
975
  self.log(logL.DEB, "close")
976
976
  if self.level > OSI.DATA_LINK:
@@ -5,7 +5,7 @@ import re
5
5
  from typing_extensions import deprecated
6
6
  import hashlib
7
7
  from dataclasses import dataclass, field
8
- from typing import Callable, Any, Optional, Protocol, cast, override, Self, Final
8
+ from typing import Callable, Any, Optional, Protocol, cast, override, Self, Final, Iterable, TypeVarTuple
9
9
  from itertools import count
10
10
  import datetime
11
11
  import time
@@ -35,7 +35,8 @@ from DLMS_SPODES.firmwares import get_firmware
35
35
  from DLMS_SPODES.cosem_interface_classes.image_transfer import image_transfer_status as i_t_status
36
36
  from DLMSAdapter.main import AdapterException, Adapter, gag
37
37
  from DLMSCommunicationProfile.osi import OSI
38
- from .client import Client, logL, Security, Data, mechanism_id, AcseServiceUser, State
38
+ from .logger import LogLevel as logL
39
+ from .client import Client, Security, Data, mechanism_id, AcseServiceUser, State
39
40
 
40
41
 
41
42
  firm_id_pat = re.compile(b".*(?P<fid>PWRM_M2M_[^_]{1,10}_[^_]{1,10}).+")
@@ -56,7 +57,7 @@ class Base[T: result.Result](Protocol):
56
57
  def copy(self) -> Self: ...
57
58
 
58
59
  @property
59
- def current(self) -> 'Base[T]':
60
+ def current(self) -> 'Base[T] | Self':
60
61
  return self
61
62
 
62
63
  async def run(self, c: Client) -> T | result.Error:
@@ -137,14 +138,14 @@ class Base[T: result.Result](Protocol):
137
138
  # todo: make tile
138
139
  return await self.application(c)
139
140
 
140
- async def AA(self, c: Client):
141
+ async def AA(self, c: Client) -> None:
141
142
  """Application Associate"""
142
143
  if c.invocationCounter and c.settings.cipher is not None and c.settings.cipher.security != Security.NONE:
143
144
  # create IC object. TODO: remove it after close connection, maybe???
144
145
  c.settings.proposedConformance |= Conformance.GENERAL_PROTECTION
145
146
 
146
147
  # my block
147
- IC: Data = c._objects.add_if_missing(ut.CosemClassId(1),
148
+ IC: Data = c.objects.add_if_missing(ut.CosemClassId(1),
148
149
  logical_name=cst.LogicalName(bytearray((0, c.get_channel_index(), 43, 1,
149
150
  c.current_association.security_setup_reference.e, 255))),
150
151
  version=cdt.Unsigned(0))
@@ -268,12 +269,18 @@ class CDT[T: cdt.CommonDataType](Simple[T], Protocol):
268
269
  async def exchange(self, c: Client) -> result.SimpleOrError[T]: ...
269
270
 
270
271
 
271
- class List[T](Base[result.List[T]], Protocol):
272
+ class _List[T](Base[result.List[T]], Protocol):
272
273
  """With List result"""
273
274
  @override
274
275
  async def exchange(self, c: Client) -> result.List[T] | result.Error: ...
275
276
 
276
277
 
278
+ class _Sequence[*Ts](Base[result.Sequence[*Ts]], Protocol):
279
+ """With List result"""
280
+ @override
281
+ async def exchange(self, c: Client) -> result.Sequence[*Ts] | result.Error: ...
282
+
283
+
277
284
  class OK(Base[result.Ok], Protocol):
278
285
  """Always result OK"""
279
286
 
@@ -289,12 +296,12 @@ class StrictOK(Base[result.StrictOk], Protocol):
289
296
 
290
297
 
291
298
  @dataclass
292
- class ClientBlocking(SimpleCopy, Base):
299
+ class ClientBlocking(SimpleCopy, OK):
293
300
  """complete by time or abort"""
294
301
  delay: Final[float] = field(default=99999999.0)
295
302
  msg: str = ""
296
303
 
297
- async def run(self, c: Client) -> result.Ok:
304
+ async def run(self, c: Client) -> result.Ok | result.Error:
298
305
  try:
299
306
  c.level = OSI.APPLICATION
300
307
  c.log(logL.WARN, F"blocked for {self.delay} second")
@@ -302,8 +309,9 @@ class ClientBlocking(SimpleCopy, Base):
302
309
  return result.OK
303
310
  finally:
304
311
  c.level = OSI.NONE
312
+ return result.OK
305
313
 
306
- async def exchange(self, c: Client) -> result.Result:
314
+ async def exchange(self, c: Client) -> result.Ok | result.Error:
307
315
  raise RuntimeError(f"not support for {self.__class__.__name__}")
308
316
 
309
317
 
@@ -432,7 +440,7 @@ class Scheduler[T: result.Result](Base[T]):
432
440
  repetition_delay_max: Final[int] = 100
433
441
  msg: str = ""
434
442
 
435
- def copy(self) -> Self:
443
+ def copy(self) -> "Scheduler[T]":
436
444
  return Scheduler(
437
445
  task=self.task.copy(),
438
446
  execution_datetime=self.execution_datetime,
@@ -479,37 +487,37 @@ class Scheduler[T: result.Result](Base[T]):
479
487
  @dataclass
480
488
  class Subtasks[U: Base[result.Result]](Protocol):
481
489
  """for register longer other tasks into task"""
482
- tasks: list[U]
490
+ tasks: Iterable[U]
483
491
 
484
492
  @property
485
493
  def current(self) -> U | Self: ...
486
494
 
487
495
 
488
- class Sequence[T: result.Result, U: Base[result.Result]](Subtasks[U], List[T]):
496
+ class List[T: result.Result, U: Base[result.Result]](Subtasks[U], _List[T]):
489
497
  """for exchange task sequence"""
490
498
  __is_exchange: bool
491
499
  msg: str
492
500
  err_ignore: bool
493
501
  __current: Base[T]
494
502
 
495
- def __init__(self, *tasks: Base[T], msg: str = None, err_ignore: bool = True):
503
+ def __init__(self, *tasks: Base[T], msg: str = "", err_ignore: bool = True):
496
504
  self.tasks = list(tasks)
497
505
  self.__current = self
498
506
  self.__is_exchange = False
499
- self.msg = self.msg = self.__class__.__name__ if msg == "" else msg
507
+ self.msg = self.__class__.__name__ if msg == "" else msg
500
508
  self.err_ignore = err_ignore
501
509
 
502
510
  def copy(self) -> Self:
503
511
  if all((isinstance(t, SimpleCopy) for t in self.tasks)):
504
512
  return self
505
- return Sequence(
513
+ return List(
506
514
  *(t.copy() for t in self.tasks),
507
515
  msg=self.msg,
508
516
  err_ignore=self.err_ignore
509
517
  )
510
518
 
511
519
  @property
512
- def current(self) -> 'Base[T]':
520
+ def current(self) -> 'Base[T] | Self':
513
521
  return self.__current
514
522
 
515
523
  def append(self, task: Base[T]):
@@ -535,6 +543,48 @@ class Sequence[T: result.Result, U: Base[result.Result]](Subtasks[U], List[T]):
535
543
  return res
536
544
 
537
545
 
546
+ class Sequence[*Ts](Subtasks[Base[result.Result]], _Sequence[*Ts]):
547
+ """for exchange task sequence"""
548
+ msg: str
549
+ err_ignore: bool
550
+ __current: "Base[result.Result] | Sequence[*Ts]"
551
+ tasks: tuple[Base[result.Result], ...]
552
+
553
+ def __init__(self, *tasks: Base[result.Result], msg: str = "", err_ignore: bool = False):
554
+ self.tasks = tasks
555
+ self.__current = self
556
+ self.msg = self.__class__.__name__ if msg == "" else msg
557
+ self.err_ignore = err_ignore
558
+
559
+ def copy(self) -> "Sequence[*Ts]":
560
+ if all((isinstance(t, SimpleCopy) for t in self.tasks)):
561
+ return self
562
+ return Sequence(
563
+ *(t.copy() for t in self.tasks),
564
+ msg=self.msg,
565
+ err_ignore=self.err_ignore
566
+ )
567
+
568
+ @property
569
+ def current(self) -> Base[result.Result] | Self:
570
+ return self.__current
571
+
572
+ async def exchange(self, c: Client) -> result.Sequence[*Ts] | result.Error:
573
+ res = result.Sequence()
574
+ for t in self.tasks:
575
+ self.__current = t
576
+ try:
577
+ if (
578
+ isinstance(res_one := await t.exchange(c), result.Error)
579
+ and not self.err_ignore
580
+ ):
581
+ return res_one
582
+ res = res.add(res_one)
583
+ except exc.ResultError as e: # todo: make without except
584
+ res.add(result.Error.from_e(e).with_msg(t.msg))
585
+ return cast("result.Sequence[*Ts]", res)
586
+
587
+
538
588
  class SetLocalTime(SimpleCopy, OK):
539
589
  """without decide time transfer"""
540
590
  msg: str
@@ -907,7 +957,6 @@ class InitType(SimpleCopy, Simple[collection.Collection]):
907
957
  FindFirmwareId(),
908
958
  FindFirmwareVersion(),
909
959
  msg="get collection.ID",
910
- err_ignore=False
911
960
  ).exchange(c)), result.Error):
912
961
  return res.with_msg("init type")
913
962
  ldn, f_id, f_ver = res.value
@@ -996,7 +1045,7 @@ class Par2Data[T: cdt.CommonDataType](SimpleCopy, CDT):
996
1045
  return res
997
1046
 
998
1047
 
999
- class ReadSequence(Sequence):
1048
+ class ReadSequence(List):
1000
1049
  tasks: list[ReadAttribute]
1001
1050
 
1002
1051
  def __post_init__(self):
@@ -1098,7 +1147,7 @@ class ActualizeAttributes(SimpleCopy, OK):
1098
1147
 
1099
1148
 
1100
1149
  @dataclass
1101
- class ReadAttributes(SimpleCopy, List[cdt.CommonDataType]):
1150
+ class ReadAttributes(SimpleCopy, _List[cdt.CommonDataType]):
1102
1151
  ln: collection.LNContaining
1103
1152
  indexes: tuple[int, ...]
1104
1153
  msg: str = ""
@@ -1645,7 +1694,7 @@ class AccessValidate(Base[result.Ok | result.Simple[list[Parameter]]]):
1645
1694
 
1646
1695
 
1647
1696
  @dataclass
1648
- class WriteParDatas(SimpleCopy, List[result.Ok]):
1697
+ class WriteParDatas(SimpleCopy, _List[result.Ok]):
1649
1698
  """write by ParData list"""
1650
1699
  par_datas: list[ParData]
1651
1700
  msg: str = ""
@@ -1664,34 +1713,39 @@ class WriteParDatas(SimpleCopy, List[result.Ok]):
1664
1713
  @dataclass
1665
1714
  class WriteParTranscript(SimpleCopy, OK):
1666
1715
  """write by ParValues[Transcript]"""
1667
- par_value: ParValues[cdt.Transcript]
1716
+ par: Parameter
1717
+ value: cdt.Transcript
1668
1718
  msg: str = ""
1669
1719
 
1670
1720
  async def exchange(self, c: Client) -> result.Ok | result.Error:
1671
- par, value = self.par_value
1672
- if isinstance((res := await Par2Data(par).exchange(c)), result.Error):
1721
+ if isinstance((res := await Par2Data(self.par).exchange(c)), result.Error):
1673
1722
  return res
1674
1723
  data = copy(res.value)
1675
1724
  if isinstance(data, cdt.Digital):
1676
- s_u = c.objects.par2su(par)
1725
+ s_u = c.objects.par2su(self.par)
1677
1726
  if isinstance(s_u, cdt.ScalUnitType):
1678
- value = int(float(value) * 10 ** -int(s_u.scaler))
1679
- data.set(value)
1727
+ value = int(float(self.value) * 10 ** -int(s_u.scaler))
1728
+ data.set(self.value)
1680
1729
  return await WriteAttribute(
1681
- ln=self.par_value.par.obis,
1682
- index=self.par_value.par.i,
1730
+ ln=self.par.obis,
1731
+ index=self.par.i,
1683
1732
  value=data.encoding
1684
1733
  ).exchange(c)
1685
1734
 
1686
1735
 
1736
+ Ts = TypeVarTuple("Ts")
1737
+
1738
+
1687
1739
  @dataclass
1688
- class WriteParTranscripts(SimpleCopy, Base):
1740
+ class WriteParTranscripts(SimpleCopy, Sequence[*Ts]):
1689
1741
  """write by ParValues[Transcript] list"""
1690
- par_values: Final[list[ParValues[cdt.Transcript]]]
1742
+ par_values: list[ParValues[cdt.Transcript]]
1691
1743
  msg: str = ""
1692
1744
 
1693
- async def exchange(self, c: Client) -> result.List:
1694
- res = result.List()
1745
+ async def exchange(self, c: Client) -> result.Sequence[*Ts] | result.Error:
1746
+ res = result.Sequence()
1695
1747
  for par_value in self.par_values:
1696
- WriteParTranscript(par_value)
1748
+ if isinstance(res_one := await WriteParTranscript(*par_value).exchange(c), result.Error):
1749
+ return res_one
1750
+ res = res.add(res_one)
1697
1751
  return res
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: DLMS_SPODES_client
3
- Version: 0.19.4
3
+ Version: 0.19.6
4
4
  Summary: dlms-spodes
5
5
  Author-email: Serj Kotilevski <youserj@outlook.com>
6
6
  Project-URL: Source, https://github.com/youserj/SPODESclient_prj
@@ -13,7 +13,7 @@ Description-Content-Type: text/markdown
13
13
  Requires-Dist: pydantic>=2.11
14
14
  Requires-Dist: pycryptodomex>=3.22.0
15
15
  Requires-Dist: semver>=3.0
16
- Requires-Dist: StructResult<0.9,>=0.8.10
16
+ Requires-Dist: StructResult<0.10,>=0.9.1
17
17
  Requires-Dist: DLMS-SPODES-communications<1.5,>=1.4.9
18
18
  Requires-Dist: DLMS_SPODES<0.88,>=0.87.6
19
19
  Requires-Dist: DLMSadapter<0.8,>=0.7.5
@@ -1,7 +1,7 @@
1
1
  pydantic>=2.11
2
2
  pycryptodomex>=3.22.0
3
3
  semver>=3.0
4
- StructResult<0.9,>=0.8.10
4
+ StructResult<0.10,>=0.9.1
5
5
  DLMS-SPODES-communications<1.5,>=1.4.9
6
6
  DLMS_SPODES<0.88,>=0.87.6
7
7
  DLMSadapter<0.8,>=0.7.5