feat(client-python): add write_array_elements default-fill helper and document semantics

Regenerate Python proto bindings to pick up MxSparseArray/MxSparseElement/
sparse_array_value from the shared mxaccess_gateway.proto. Add
Session.write_array_elements which builds an MxValue(sparse_array_value=…)
from a {index→scalar} dict and delegates to the existing write(). Add 8 pytest
tests covering builder correctness and full round-trip wire shape. Update
README with a default-fill semantics paragraph and bare-name array-write note.
This commit is contained in:
Joseph Doherty
2026-06-18 03:01:45 -04:00
parent db9c68ca9c
commit 0702551c25
9 changed files with 467 additions and 165 deletions
@@ -2,7 +2,7 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# NO CHECKED-IN PROTOBUF GENCODE
# source: galaxy_repository.proto
# Protobuf Python Version: 6.31.1
# Protobuf Python Version: 6.33.5
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
@@ -12,8 +12,8 @@ from google.protobuf.internal import builder as _builder
_runtime_version.ValidateProtobufRuntimeVersion(
_runtime_version.Domain.PUBLIC,
6,
31,
1,
33,
5,
'',
'galaxy_repository.proto'
)
@@ -5,7 +5,7 @@ import warnings
import galaxy_repository_pb2 as galaxy__repository__pb2
GRPC_GENERATED_VERSION = '1.80.0'
GRPC_GENERATED_VERSION = '1.81.1'
GRPC_VERSION = grpc.__version__
_version_not_supported = False
@@ -25,7 +25,7 @@ if _version_not_supported:
)
class GalaxyRepositoryStub(object):
class GalaxyRepositoryStub:
"""Wire-compatibility policy (ProtobufStyleGuide): this contract evolves
additively only. Never renumber or repurpose an existing field number or
enum value. When a field or enum value is removed, add a `reserved` range
@@ -72,7 +72,7 @@ class GalaxyRepositoryStub(object):
_registered_method=True)
class GalaxyRepositoryServicer(object):
class GalaxyRepositoryServicer:
"""Wire-compatibility policy (ProtobufStyleGuide): this contract evolves
additively only. Never renumber or repurpose an existing field number or
enum value. When a field or enum value is removed, add a `reserved` range
@@ -162,7 +162,7 @@ def add_GalaxyRepositoryServicer_to_server(servicer, server):
# This class is part of an EXPERIMENTAL API.
class GalaxyRepository(object):
class GalaxyRepository:
"""Wire-compatibility policy (ProtobufStyleGuide): this contract evolves
additively only. Never renumber or repurpose an existing field number or
enum value. When a field or enum value is removed, add a `reserved` range
File diff suppressed because one or more lines are too long
@@ -5,7 +5,7 @@ import warnings
import mxaccess_gateway_pb2 as mxaccess__gateway__pb2
GRPC_GENERATED_VERSION = '1.80.0'
GRPC_GENERATED_VERSION = '1.81.1'
GRPC_VERSION = grpc.__version__
_version_not_supported = False
@@ -25,7 +25,7 @@ if _version_not_supported:
)
class MxAccessGatewayStub(object):
class MxAccessGatewayStub:
"""Wire-compatibility policy (ProtobufStyleGuide): this contract evolves
additively only. Never renumber or repurpose an existing field number or
enum value. When a field or enum value is removed, add a `reserved` range
@@ -78,7 +78,7 @@ class MxAccessGatewayStub(object):
_registered_method=True)
class MxAccessGatewayServicer(object):
class MxAccessGatewayServicer:
"""Wire-compatibility policy (ProtobufStyleGuide): this contract evolves
additively only. Never renumber or repurpose an existing field number or
enum value. When a field or enum value is removed, add a `reserved` range
@@ -189,7 +189,7 @@ def add_MxAccessGatewayServicer_to_server(servicer, server):
# This class is part of an EXPERIMENTAL API.
class MxAccessGateway(object):
class MxAccessGateway:
"""Wire-compatibility policy (ProtobufStyleGuide): this contract evolves
additively only. Never renumber or repurpose an existing field number or
enum value. When a field or enum value is removed, add a `reserved` range
@@ -2,7 +2,7 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# NO CHECKED-IN PROTOBUF GENCODE
# source: mxaccess_worker.proto
# Protobuf Python Version: 6.31.1
# Protobuf Python Version: 6.33.5
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
@@ -12,8 +12,8 @@ from google.protobuf.internal import builder as _builder
_runtime_version.ValidateProtobufRuntimeVersion(
_runtime_version.Domain.PUBLIC,
6,
31,
1,
33,
5,
'',
'mxaccess_worker.proto'
)
@@ -4,7 +4,7 @@ import grpc
import warnings
GRPC_GENERATED_VERSION = '1.80.0'
GRPC_GENERATED_VERSION = '1.81.1'
GRPC_VERSION = grpc.__version__
_version_not_supported = False
@@ -489,6 +489,56 @@ class Session:
correlation_id=correlation_id,
)
async def write_array_elements(
self,
server_handle: int,
item_handle: int,
element_data_type: "pb.MxDataType.ValueType",
total_length: int,
elements: dict[int, MxValueInput],
*,
user_id: int = 0,
correlation_id: str = "",
) -> None:
"""Write a partial array by specifying only the indices you want to set.
The gateway expands the sparse representation into a full ``total_length``
array before forwarding the write to MXAccess. Indices not listed in
*elements* are filled with the type default for *element_data_type* (0,
False, empty string, Unix epoch for timestamps, etc.). The previous
value at those positions is **not** preserved — this is a full array
replacement, not a patch.
Args:
server_handle: Handle returned by :meth:`register`.
item_handle: Handle returned by :meth:`add_item`.
element_data_type: ``pb.MX_DATA_TYPE_*`` enum value for the scalar
element type of the target array attribute.
total_length: Total number of elements in the written array. Must
be > 0 and large enough to contain every index in *elements*.
elements: Mapping of zero-based element index to scalar value.
Values are converted with :func:`~zb_mom_ww_mxgateway.values.to_mx_value`.
user_id: Galaxy user id to stamp on the write (requires a prior
supervisory advise to take effect — see README).
correlation_id: Optional client-supplied correlation token echoed
in the command reply.
"""
sparse = pb.MxSparseArray(
element_data_type=element_data_type,
total_length=total_length,
elements=[
pb.MxSparseElement(index=idx, value=to_mx_value(val))
for idx, val in elements.items()
],
)
await self.write(
server_handle,
item_handle,
pb.MxValue(sparse_array_value=sparse),
user_id=user_id,
correlation_id=correlation_id,
)
async def write2(
self,
server_handle: int,