Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/server_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def setup_server(description=None, context=None, cmdline=None):
# Alternately, use the factory methods to initialize the DataBlocks
# or simply do not pass them to have them initialized to 0x00 on the
# full address range::
datablock = lambda : ModbusSequentialDataBlock.create() # pylint: disable=unnecessary-lambda-assignment,unnecessary-lambda
datablock = lambda : ModbusSequentialDataBlock(0x00, [0x00] * 65536) # pylint: disable=unnecessary-lambda-assignment

if args.device_ids > 1: # pragma: no cover
# The server then makes use of a server context that allows the server
Expand Down Expand Up @@ -197,7 +197,7 @@ async def run_async_server(args) -> None:
certfile=helper.get_certificate(
"crt"
), # The cert file path for TLS (used if sslctx is None)
# sslctx=sslctx, # The SSLContext to use for TLS (default None and auto create)
# sslctx=sslctx, # The SSLContext to use for TLS (default None and auto)
keyfile=helper.get_certificate(
"key"
), # The key file path for TLS (used if sslctx is None)
Expand Down
43 changes: 12 additions & 31 deletions pymodbus/datastore/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from ..constants import ExcCodes
from ..exceptions import NoSuchIdException
from ..logging import Log
from .sequential import ModbusSequentialDataBlock
from .store import BaseModbusDataBlock


Expand Down Expand Up @@ -67,23 +66,12 @@ def __init__(self, *_args,
hr: BaseModbusDataBlock | None = None,
):
"""Initialize the datastores."""
self.store = {}
self.store["d"] = di if di is not None else ModbusSequentialDataBlock.create()
self.store["c"] = co if co is not None else ModbusSequentialDataBlock.create()
self.store["i"] = ir if ir is not None else ModbusSequentialDataBlock.create()
self.store["h"] = hr if hr is not None else ModbusSequentialDataBlock.create()

def __str__(self):
"""Return a string representation of the context.

:returns: A string representation of the context
"""
return "Modbus device Context"

def reset(self):
"""Reset all the datastores to their default values."""
for datastore in iter(self.store.values()):
datastore.reset()
self.store = {
"d": di,
"c": co,
"i": ir,
"h": hr,
}

async def async_getValues(self, func_code, address, count=1) -> list[int] | list[bool] | ExcCodes:
"""Get `count` values from datastore.
Expand All @@ -95,7 +83,9 @@ async def async_getValues(self, func_code, address, count=1) -> list[int] | list
"""
address += 1
Log.debug("getValues: fc-[{}] address-{}: count-{}", func_code, address, count)
return await self.store[self.decode(func_code)].async_getValues(address, count)
if dt := self.store[self.decode(func_code)]:
return await dt.async_getValues(address, count)
return ExcCodes.ILLEGAL_ADDRESS

async def async_setValues(self, func_code, address, values) -> None | ExcCodes:
"""Set the datastore with the supplied values.
Expand All @@ -106,7 +96,9 @@ async def async_setValues(self, func_code, address, values) -> None | ExcCodes:
"""
address += 1
Log.debug("setValues[{}] address-{}: count-{}", func_code, address, len(values))
return await self.store[self.decode(func_code)].async_setValues(address, values)
if dt := self.store[self.decode(func_code)]:
return await dt.async_setValues(address, values)
return ExcCodes.ILLEGAL_ADDRESS


class ModbusServerContext:
Expand Down Expand Up @@ -162,17 +154,6 @@ async def async_setValues(self, device_id: int, func_code: int, address: int, va
dev = self.__get_device(device_id)
return await dev.async_setValues(func_code, address, values)

def __getitem__(self, device_id):
"""Use to get access to a device_id context.

:param device_id: The device context to get
:returns: The requested device context
:raises NoSuchIdException:
"""
if self.single:
device_id = 0
return self.__get_device(device_id)

def device_ids(self):
"""Get the configured device ids."""
return list(self._devices.keys())
25 changes: 0 additions & 25 deletions pymodbus/datastore/sequential.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,6 @@ def __init__(self, address, values):
self.values = list(values)
else:
self.values = [values]
self.default_value = self.values[0].__class__()

@classmethod
def create(cls):
"""Create a datastore.

With the full address space initialized to 0x00

:returns: An initialized datastore
"""
return cls(0x00, [0x00] * 65536)

def default(self, count, value=False):
"""Use to initialize a store to one value.

:param count: The number of fields to set
:param value: The default value to set to the fields
"""
self.default_value = value
self.values = [self.default_value] * count
self.address = 0x00

def reset(self):
"""Reset the datastore to the initialized default value."""
self.values = [self.default_value] * len(self.values)

async def async_getValues(self, address, count=1) -> list[int] | list[bool] | ExcCodes:
"""Return the requested values of the datastore.
Expand Down
22 changes: 1 addition & 21 deletions pymodbus/datastore/sparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,6 @@ def __init__(self, values=None, mutable=True):
self.values = {}
self._process_values(values)
self.mutable = mutable
self.default_value = self.values.copy()

@classmethod
def create(cls, values=None):
"""Create sparse datastore.

Use setValues to initialize registers.

:param values: Either a list or a dictionary of values
:returns: An initialized datastore
"""
return cls(values)

def reset(self):
"""Reset the store to the initially provided defaults."""
self.values = self.default_value.copy()

async def async_getValues(self, address, count=1) -> list[int] | list[bool] | ExcCodes:
"""Return the requested values of the datastore.
Expand Down Expand Up @@ -71,12 +55,11 @@ def _process_as_dict(values):
)
_process_as_dict(values)

async def async_setValues(self, address, values, use_as_default=False) -> None | ExcCodes:
async def async_setValues(self, address, values) -> None | ExcCodes:
"""Set the requested values of the datastore.

:param address: The register starting address
:param values: The new values to be set.
:param use_as_default: Use the values as default

Values can be given in different formats:
- a single register value or
Expand All @@ -98,9 +81,6 @@ async def async_setValues(self, address, values, use_as_default=False) -> None |
if address + idx not in self.values and not self.mutable:
raise ParameterException("Offset {address+idx} not in range")
self.values[address + idx] = val
if use_as_default:
for idx, val in iter(self.values.items()):
self.default_value[idx] = val
except KeyError:
return ExcCodes.ILLEGAL_ADDRESS
return None
Expand Down
19 changes: 0 additions & 19 deletions pymodbus/datastore/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,3 @@ async def async_setValues(self, address: int, values: list[int] | list[bool]) ->
:param values: The values to store
:raises TypeError:
"""

def reset(self):
"""Reset the datastore to the initialized default value."""

def __str__(self):
"""Build a representation of the datastore.

:returns: A string representation of the datastore
"""
return f"DataStore({len(self.values)}, {self.default_value})"

def __iter__(self):
"""Iterate over the data block data.

:returns: An iterator of the data block data
"""
if isinstance(self.values, dict):
return iter(self.values.items())
return enumerate(self.values, self.address)
18 changes: 0 additions & 18 deletions test/datastore/test_context.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
"""Test datastore context."""
import pytest

from pymodbus.datastore import (
ModbusBaseDeviceContext,
ModbusDeviceContext,
ModbusServerContext,
)
from pymodbus.exceptions import NoSuchIdException


class TestContextDataStore:
Expand All @@ -18,12 +16,6 @@ async def test_datastore_base_device(self):
await dev.async_getValues(0x01, 0x01)
await dev.async_setValues(0x05, 0x01, [0])

def test_datastore_device(self):
"""Test ModbusDeviceContext."""
dev = ModbusDeviceContext()
str(dev)
dev.reset()

async def test_datastore_device_Values(self):
"""Test ModbusDeviceContext."""
dev = ModbusDeviceContext()
Expand All @@ -43,13 +35,3 @@ def test_datastore_server_ids(self):
srv = ModbusServerContext()
assert isinstance(srv.device_ids(), list)

def test_datastore_get(self):
"""Test ModbusServerContext."""
server = ModbusServerContext(devices={1: {}}, single=False)
with pytest.raises(NoSuchIdException):
server[5]
server = ModbusServerContext(devices={1: {}, 0: {}}, single=False)
assert isinstance(server[5], dict)
server = ModbusServerContext(devices={1: {}}, single=True)
assert isinstance(server[5], dict)

7 changes: 0 additions & 7 deletions test/datastore/test_sequential.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ def test_datastore_Sequential(self):
"""Test ModbusDeviceContext."""
ModbusSequentialDataBlock(0x01, [17])
ModbusSequentialDataBlock(0x01, 17)
ModbusSequentialDataBlock(0x01, 17).default(112)

async def test_datastore_Sequential_get(self):
"""Test ModbusDeviceContext."""
Expand All @@ -24,9 +23,3 @@ async def test_datastore_Sequential_set(self):
await block.async_setValues(1, [19])
await block.async_setValues(1, 19)
assert await block.async_setValues(13, [17]) == ExcCodes.ILLEGAL_ADDRESS

def test_datastore_Sequential_iter(self):
"""Test check frame."""
block = ModbusSequentialDataBlock(0x01, [17])
str(block)
_ = list(block)
23 changes: 1 addition & 22 deletions test/datastore/test_sparse_datastore.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,9 @@ async def test_sparse_datastore_check(self):
assert await datablock.async_getValues(key, 1) == [value]
key += 1

async def test_sparse_datastore_create(self):
"""Test check frame."""
datablock = ModbusSparseDataBlock.create(self.data_in_block)
for key, entry in self.data_in_block.items():
if isinstance(entry, int):
entry = [entry]
for value in entry:
assert await datablock.async_getValues(key, 1) == [value]
key += 1

def test_sparse_datastore_reset(self):
"""Test check frame."""
datablock = ModbusSparseDataBlock.create()
datablock.reset()

async def test_sparse_datastore_get(self):
"""Test check frame."""
datablock = ModbusSparseDataBlock.create()
datablock = ModbusSparseDataBlock()
assert await datablock.async_getValues(117) == ExcCodes.ILLEGAL_ADDRESS

async def test_sparse_datastore_set(self):
Expand All @@ -75,7 +60,6 @@ async def test_sparse_datastore_set(self):
assert not await datablock.async_setValues(1, {1: 5})
assert not await datablock.async_setValues(1, [5])
assert not await datablock.async_setValues(1, 5)
assert not await datablock.async_setValues(1, 5, use_as_default=True)

async def test_sparse_datastore_async_set(self):
"""Test check frame."""
Expand All @@ -92,8 +76,3 @@ async def test_sparse_datastore_set_not_ok(self):
datablock = ModbusSparseDataBlock(self.data_in_block)
datablock._process_values = mock.Mock(side_effect=KeyError) # type: ignore[method-assign]
assert await datablock.async_setValues(30, {17: 0}) == ExcCodes.ILLEGAL_ADDRESS

def test_sparse_datastore_iter(self):
"""Test check frame."""
datablock = ModbusSparseDataBlock(self.data_in_block)
_ = list(datablock)