From 18aa46349a0ceae65479b4b915f9657b3cb4854a Mon Sep 17 00:00:00 2001 From: jan iversen Date: Tue, 3 May 2022 17:25:13 +0200 Subject: [PATCH] Flake8 clean pymodbus. (#871) --- .flake8 | 5 + .github/workflows/ci.yml | 2 +- doc/api/doxygen/build.py | 18 +- doc/api/epydoc/build.py | 11 +- doc/api/pydoc/build.py | 872 +++++++++--------- doc/api/pydoctor/build.py | 9 +- doc/conf.py | 42 +- examples/common/async_asyncio_client.py | 66 +- .../common/async_asyncio_serial_client.py | 43 +- examples/common/async_tornado_client.py | 23 +- .../common/async_tornado_client_serial.py | 25 +- examples/common/async_twisted_client.py | 30 +- .../common/async_twisted_client_serial.py | 26 +- examples/common/asynchronous_processor.py | 49 +- examples/common/asynchronous_server.py | 15 +- examples/common/asyncio_server.py | 11 +- examples/common/callback_server.py | 30 +- examples/common/changing_framers.py | 7 +- examples/common/custom_datablock.py | 14 +- examples/common/custom_message.py | 26 +- examples/common/custom_synchronous_server.py | 11 +- examples/common/dbstore_update_server.py | 17 +- examples/common/modbus_logging.py | 6 +- examples/common/modbus_payload.py | 22 +- examples/common/modbus_payload_server.py | 9 +- examples/common/performance.py | 20 +- examples/common/synchronous_client.py | 55 +- examples/common/synchronous_client_ext.py | 7 +- examples/common/synchronous_server.py | 9 +- examples/common/updating_server.py | 11 +- .../asynchronous_asyncio_modbus_tls_client.py | 10 +- .../asynchronous_asyncio_serial_client.py | 46 +- examples/contrib/bcd_payload.py | 62 +- examples/contrib/concurrent_client.py | 58 +- .../contrib/deviceinfo_showcase_client.py | 9 +- .../contrib/deviceinfo_showcase_server.py | 9 +- examples/contrib/libmodbus_client.py | 111 +-- examples/contrib/message_generator.py | 24 +- examples/contrib/message_parser.py | 60 +- examples/contrib/modbus_mapper.py | 104 +-- examples/contrib/modbus_saver.py | 83 +- examples/contrib/modbus_scraper.py | 79 +- examples/contrib/modbus_simulator.py | 40 +- examples/contrib/modbus_tls_client.py | 3 +- examples/contrib/modicon_payload.py | 83 +- examples/contrib/remote_server_context.py | 64 +- examples/contrib/serial_forwarder.py | 7 +- examples/contrib/sunspec_client.py | 206 ++--- examples/contrib/thread_safe_datastore.py | 84 +- ez_setup.py | 124 +-- pymodbus/__init__.py | 11 +- pymodbus/bit_read_message.py | 88 +- pymodbus/bit_write_message.py | 112 ++- pymodbus/client/__init__.py | 1 + pymodbus/client/asynchronous/__init__.py | 16 +- .../client/asynchronous/async_io/__init__.py | 223 ++--- .../asynchronous/deprecated/__init__.py | 2 +- .../asynchronous/deprecated/asynchronous.py | 56 +- .../client/asynchronous/factory/serial.py | 45 +- pymodbus/client/asynchronous/factory/tcp.py | 30 +- pymodbus/client/asynchronous/factory/tls.py | 14 +- pymodbus/client/asynchronous/factory/udp.py | 18 +- pymodbus/client/asynchronous/mixins.py | 17 +- .../asynchronous/schedulers/__init__.py | 3 +- pymodbus/client/asynchronous/serial.py | 21 +- pymodbus/client/asynchronous/tcp.py | 9 +- pymodbus/client/asynchronous/thread.py | 22 +- pymodbus/client/asynchronous/tls.py | 12 +- .../client/asynchronous/tornado/__init__.py | 139 +-- .../client/asynchronous/twisted/__init__.py | 62 +- pymodbus/client/asynchronous/udp.py | 12 +- pymodbus/client/common.py | 58 +- pymodbus/client/sync.py | 156 ++-- pymodbus/client/sync_diag.py | 18 +- pymodbus/client/tls_helper.py | 8 +- pymodbus/constants.py | 100 +- pymodbus/datastore/__init__.py | 6 +- pymodbus/datastore/context.py | 55 +- pymodbus/datastore/database/__init__.py | 6 +- .../datastore/database/redis_datastore.py | 81 +- pymodbus/datastore/database/sql_datastore.py | 57 +- pymodbus/datastore/remote.py | 60 +- pymodbus/datastore/store.py | 83 +- pymodbus/device.py | 425 ++++----- pymodbus/diag_message.py | 437 +++++---- pymodbus/events.py | 77 +- pymodbus/exceptions.py | 46 +- pymodbus/factory.py | 211 ++--- pymodbus/file_message.py | 179 ++-- pymodbus/framer/__init__.py | 31 +- pymodbus/framer/ascii_framer.py | 37 +- pymodbus/framer/binary_framer.py | 40 +- pymodbus/framer/rtu_framer.py | 52 +- pymodbus/framer/socket_framer.py | 48 +- pymodbus/framer/tls_framer.py | 46 +- pymodbus/interfaces.py | 101 +- pymodbus/mei_message.py | 70 +- pymodbus/other_message.py | 193 ++-- pymodbus/payload.py | 146 ++- pymodbus/pdu.py | 94 +- pymodbus/register_read_message.py | 127 +-- pymodbus/register_write_message.py | 127 +-- pymodbus/repl/__init__.py | 3 +- pymodbus/repl/client/__init__.py | 4 +- pymodbus/repl/client/completer.py | 30 +- pymodbus/repl/client/helper.py | 58 +- pymodbus/repl/client/main.py | 70 +- pymodbus/repl/client/mclient.py | 215 +++-- pymodbus/repl/server/__init__.py | 4 +- pymodbus/repl/server/cli.py | 61 +- pymodbus/repl/server/main.py | 21 +- pymodbus/server/__init__.py | 2 +- pymodbus/server/async_io.py | 232 ++--- pymodbus/server/asynchronous.py | 93 +- pymodbus/server/reactive/__init__.py | 4 +- pymodbus/server/reactive/default_config.py | 66 +- pymodbus/server/reactive/main.py | 70 +- pymodbus/server/sync.py | 133 +-- pymodbus/server/tls_helper.py | 8 +- pymodbus/transaction.py | 119 ++- pymodbus/utilities.py | 59 +- pymodbus/version.py | 13 +- setup.py | 4 +- setup_commands.py | 60 +- test/__init__.py | 1 + test/asyncio_test_helper.py | 11 +- test/modbus_mocks.py | 19 +- test/test_all_messages.py | 32 +- test/test_bit_read_messages.py | 90 +- test/test_bit_write_messages.py | 82 +- test/test_client_async.py | 179 ++-- test/test_client_async_asyncio.py | 244 ++--- test/test_client_async_tornado.py | 127 +-- test/test_client_async_twisted.py | 129 +-- test/test_client_common.py | 66 +- test/test_client_sync.py | 266 +++--- test/test_client_sync_diag.py | 39 +- test/test_datastore.py | 242 ++--- test/test_device.py | 133 +-- test/test_diag_messages.py | 87 +- test/test_events.py | 40 +- test/test_exceptions.py | 28 +- test/test_factory.py | 182 ++-- test/test_file_message.py | 216 ++--- test/test_fixes.py | 18 +- test/test_framers.py | 194 ++-- test/test_interfaces.py | 49 +- test/test_mei_messages.py | 79 +- test/test_other_messages.py | 34 +- test/test_payload.py | 112 +-- test/test_pdu.py | 39 +- test/test_ptwisted.py | 27 +- test/test_register_read_messages.py | 128 +-- test/test_register_write_messages.py | 81 +- test/test_remote_datastore.py | 62 +- test/test_server_async.py | 102 +- test/test_server_asyncio.py | 305 +++--- test/test_server_context.py | 54 +- test/test_server_sync.py | 100 +- test/test_transaction.py | 276 +++--- test/test_utilities.py | 51 +- test/test_version.py | 20 +- tox.ini | 7 - 163 files changed, 6232 insertions(+), 5893 deletions(-) create mode 100644 .flake8 diff --git a/.flake8 b/.flake8 new file mode 100644 index 000000000..397b9cdd1 --- /dev/null +++ b/.flake8 @@ -0,0 +1,5 @@ +# flake8 configuration. +[flake8] +exclude = .tox,.git,__pycache__ +ignore = D211,D400,E251,E731,W503 +max-line-length = 120 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a3e138ac3..b0284d7f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -191,7 +191,7 @@ jobs: # continue_on_error: true - name: flake8 tox: flake8 - continue_on_error: true + # continue_on_error: true - name: Docs tox: docs os: diff --git a/doc/api/doxygen/build.py b/doc/api/doxygen/build.py index ddcab224c..6ee2bf044 100644 --- a/doc/api/doxygen/build.py +++ b/doc/api/doxygen/build.py @@ -1,19 +1,21 @@ #!/usr/bin/env python3 -""" Doxygen API Builder ---------------------- -""" +"""Doxygen API Builder.""" import os import shutil + def is_exe(path): - """ Returns if the program is executable + """Return if the program is executable. + :param path: The path to the file :return: True if it is, False otherwise """ return os.path.exists(path) and os.access(path, os.X_OK) + def which(program): - """ Check to see if an executable exists + """Check to see if an executable exists. + :param program: The program to check for :return: The full path of the executable or None if not found """ @@ -28,9 +30,11 @@ def which(program): return exe_file return None + if which('doxygen') is not None: print("Building Doxygen API Documentation") - os.system("doxygen .doxygen") #nosec + os.system("doxygen .doxygen") # nosec if os.path.exists('../../../build'): shutil.move("html", "../../../build/doxygen") -else: print("Doxygen not available...not building") +else: + print("Doxygen not available...not building") diff --git a/doc/api/epydoc/build.py b/doc/api/epydoc/build.py index d9e350616..a81ff1901 100755 --- a/doc/api/epydoc/build.py +++ b/doc/api/epydoc/build.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Epydoc API Runner ------------------- +"""Epydoc API Runner. Using pkg_resources, we attempt to see if epydoc is installed, if so, we use its cli program to compile the documents @@ -14,7 +13,7 @@ try: pkg_resources.require("epydoc") - from epydoc.cli import cli # pylint: disable=import-error + from epydoc.cli import cli # pylint: disable=import-error sys.argv = """epydoc.py pymodbus --html --simple-term --quiet --include-log @@ -25,7 +24,7 @@ --exclude=tests --output=html/ """.split() - #bugs in trunk for --docformat=restructuredtext + # bugs in trunk for --docformat=restructuredtext if not os.path.exists("./html"): os.mkdir("./html") @@ -35,6 +34,6 @@ if os.path.exists('../../../build'): shutil.move("html", "../../../build/epydoc") -except Exception: # pylint: disable=broad-except +except Exception: # pylint: disable=broad-except traceback.print_exc(file=sys.stdout) - print( "Epydoc not available...not building") + print("Epydoc not available...not building") diff --git a/doc/api/pydoc/build.py b/doc/api/pydoc/build.py index 460a1d23b..f2fd4cc49 100644 --- a/doc/api/pydoc/build.py +++ b/doc/api/pydoc/build.py @@ -1,448 +1,464 @@ #!/usr/bin/env python3 # pylint: disable-all -""" -Pydoc sub-class for generating documentation for entire packages. +"""Pydoc sub-class for generating documentation for entire packages. Taken from: http://pyopengl.sourceforge.net/pydoc/OpenGLContext.pydoc.pydoc2.html Author: Mike Fletcher """ import logging -import pydoc, inspect, os, string, shutil -import sys, imp, os, stat, re, types, inspect -from repr import Repr -from string import expandtabs, find, join, lower, split, strip, rfind, rstrip +import pydoc +import inspect +import os +import string +import shutil +import sys +from string import join, split, strip _log = logging.getLogger(__name__) + def classify_class_attrs(cls): - """Return list of attribute-descriptor tuples. - - For each name in dir(cls), the return list contains a 4-tuple - with these elements: - - 0. The name (a string). - - 1. The kind of attribute this is, one of these strings: - 'class method' created via classmethod() - 'static method' created via staticmethod() - 'property' created via property() - 'method' any other flavor of method - 'data' not a method - - 2. The class which defined this attribute (a class). - - 3. The object as obtained directly from the defining class's - __dict__, not via getattr. This is especially important for - data attributes: C.data is just a data object, but - C.__dict__['data'] may be a data descriptor with additional - info, like a __doc__ string. - - Note: This version is patched to work with Zope Interface-bearing objects - """ - - mro = inspect.getmro(cls) - names = dir(cls) - result = [] - for name in names: - # Get the object associated with the name. - # Getting an obj from the __dict__ sometimes reveals more than - # using getattr. Static and class methods are dramatic examples. - if name in cls.__dict__: - obj = cls.__dict__[name] - else: - try: - obj = getattr(cls, name) - except AttributeError: - continue - - # Figure out where it was defined. - homecls = getattr(obj, "__objclass__", None) - if homecls is None: - # search the dicts. - for base in mro: - if name in base.__dict__: - homecls = base - break - - # Get the object again, in order to get it from the defining - # __dict__ instead of via getattr (if possible). - if homecls is not None and name in homecls.__dict__: - obj = homecls.__dict__[name] - - # Also get the object via getattr. - obj_via_getattr = getattr(cls, name) - - # Classify the object. - if isinstance(obj, staticmethod): - kind = "static method" - elif isinstance(obj, classmethod): - kind = "class method" - elif isinstance(obj, property): - kind = "property" - elif (inspect.ismethod(obj_via_getattr) or - inspect.ismethoddescriptor(obj_via_getattr)): - kind = "method" - else: - kind = "data" - - result.append((name, kind, homecls, obj)) - - return result + """Return list of attribute-descriptor tuples. + + For each name in dir(cls), the return list contains a 4-tuple + with these elements: + + 0. The name (a string). + + 1. The kind of attribute this is, one of these strings: + 'class method' created via classmethod() + 'static method' created via staticmethod() + 'property' created via property() + 'method' any other flavor of method + 'data' not a method + + 2. The class which defined this attribute (a class). + + 3. The object as obtained directly from the defining class's + __dict__, not via getattr. This is especially important for + data attributes: C.data is just a data object, but + C.__dict__['data'] may be a data descriptor with additional + info, like a __doc__ string. + + Note: This version is patched to work with Zope Interface-bearing objects + """ + mro = inspect.getmro(cls) + names = dir(cls) + result = [] + for name in names: + # Get the object associated with the name. + # Getting an obj from the __dict__ sometimes reveals more than + # using getattr. Static and class methods are dramatic examples. + if name in cls.__dict__: + obj = cls.__dict__[name] + else: + try: + obj = getattr(cls, name) + except AttributeError: + continue + + # Figure out where it was defined. + homecls = getattr(obj, "__objclass__", None) + if homecls is None: + # search the dicts. + for base in mro: + if name in base.__dict__: + homecls = base + break + + # Get the object again, in order to get it from the defining + # __dict__ instead of via getattr (if possible). + if homecls is not None and name in homecls.__dict__: + obj = homecls.__dict__[name] + + # Also get the object via getattr. + obj_via_getattr = getattr(cls, name) + + # Classify the object. + if isinstance(obj, staticmethod): + kind = "static method" + elif isinstance(obj, classmethod): + kind = "class method" + elif isinstance(obj, property): + kind = "property" + elif (inspect.ismethod(obj_via_getattr) or # noqa W504 + inspect.ismethoddescriptor(obj_via_getattr)): + kind = "method" + else: + kind = "data" + + result.append((name, kind, homecls, obj)) + + return result + + inspect.classify_class_attrs = classify_class_attrs class DefaultFormatter(pydoc.HTMLDoc): - def docmodule(self, object, name=None, mod=None, packageContext = None, *ignored): - """Produce HTML documentation for a module object.""" - my_name = object.__name__ # ignore the passed-in name - parts = split(my_name, '.') - links = [] - for i in range(len(parts)-1): - links.append( - '%s' % - (join(parts[:i+1], '.'), parts[i])) - linkedname = join(links + parts[-1:], '.') - head = '%s' % linkedname - try: - path = inspect.getabsfile(object) - url = path - if sys.platform == 'win32': - import nturl2path - url = nturl2path.pathname2url(path) - filelink = '%s' % (url, path) - except TypeError: - filelink = '(built-in)' - info = [] - if hasattr(object, '__version__'): - version = str(object.__version__) - if version[:11] == '$' + 'Revision: ' and version[-1:] == '$': - version = strip(version[11:-1]) - info.append('version %s' % self.escape(version)) - if hasattr(object, '__date__'): - info.append(self.escape(str(object.__date__))) - if info: - head = head + ' (%s)' % join(info, ', ') - result = self.heading( - head, '#ffffff', '#7799ee', 'index
' + filelink) - - modules = inspect.getmembers(object, inspect.ismodule) - - classes, cdict = [], {} - for key, value in inspect.getmembers(object, inspect.isclass): - if (inspect.getmodule(value) or object) is object: - classes.append((key, value)) - cdict[key] = cdict[value] = '#' + key - for key, value in classes: - for base in value.__bases__: - key, modname = base.__name__, base.__module__ - module = sys.modules.get(modname) - if modname != my_name and module and hasattr(module, key): - if getattr(module, key) is base: - if not cdict.has_key(key): - cdict[key] = cdict[base] = modname + '.html#' + key - funcs, fdict = [], {} - for key, value in inspect.getmembers(object, inspect.isroutine): - if inspect.isbuiltin(value) or inspect.getmodule(value) is object: - funcs.append((key, value)) - fdict[key] = '#-' + key - if inspect.isfunction(value): fdict[value] = fdict[key] - data = [] - for key, value in inspect.getmembers(object, pydoc.isdata): - if key not in ['__builtins__', '__doc__']: - data.append((key, value)) - - doc = self.markup(pydoc.getdoc(object), self.preformat, fdict, cdict) - doc = doc and '%s' % doc - result = result + '

%s

\n' % doc - - packageContext.clean ( classes, object ) - packageContext.clean ( funcs, object ) - packageContext.clean ( data, object ) - - if hasattr(object, '__path__'): - modpkgs = [] - modnames = [] - for file in os.listdir(object.__path__[0]): - path = os.path.join(object.__path__[0], file) - modname = inspect.getmodulename(file) - if modname and modname not in modnames: - modpkgs.append((modname, my_name, 0, 0)) - modnames.append(modname) - elif pydoc.ispackage(path): - modpkgs.append((file, my_name, 1, 0)) - modpkgs.sort() - contents = self.multicolumn(modpkgs, self.modpkglink) -## result = result + self.bigsection( -## 'Package Contents', '#ffffff', '#aa55cc', contents) - result = result + self.moduleSection( object, packageContext) - elif modules: -#FIX contents = self.multicolumn( -#FIX modules, lambda (key, value), s=self: s.modulelink(value)) - result = result + self.bigsection( - 'Modules', '#fffff', '#aa55cc', contents) - - - if classes: -#FIX classlist = map(lambda (key, value): value, classes) - contents = [ - self.formattree(inspect.getclasstree(classlist, 1), my_name)] - for key, value in classes: - contents.append(self.document(value, key, my_name, fdict, cdict)) - result = result + self.bigsection( - 'Classes', '#ffffff', '#ee77aa', join(contents)) - if funcs: - contents = [] - for key, value in funcs: - contents.append(self.document(value, key, my_name, fdict, cdict)) - result = result + self.bigsection( - 'Functions', '#ffffff', '#eeaa77', join(contents)) - if data: - contents = [] - for key, value in data: - try: - contents.append(self.document(value, key)) - except Exception: #nosec - pass - result = result + self.bigsection( - 'Data', '#ffffff', '#55aa55', join(contents, '
\n')) - if hasattr(object, '__author__'): - contents = self.markup(str(object.__author__), self.preformat) - result = result + self.bigsection( - 'Author', '#ffffff', '#7799ee', contents) - if hasattr(object, '__credits__'): - contents = self.markup(str(object.__credits__), self.preformat) - result = result + self.bigsection( - 'Credits', '#ffffff', '#7799ee', contents) - - return result - - def classlink(self, object, modname): - """Make a link for a class.""" - name, module = object.__name__, sys.modules.get(object.__module__) - if hasattr(module, name) and getattr(module, name) is object: - return '%s' % ( - module.__name__, name, name - ) - return pydoc.classname(object, modname) - - def moduleSection( self, object, packageContext ): - """Create a module-links section for the given object (module)""" - modules = inspect.getmembers(object, inspect.ismodule) - packageContext.clean ( modules, object ) - packageContext.recurseScan( modules ) - - if hasattr(object, '__path__'): - modpkgs = [] - modnames = [] - for file in os.listdir(object.__path__[0]): - path = os.path.join(object.__path__[0], file) - modname = inspect.getmodulename(file) - if modname and modname not in modnames: - modpkgs.append((modname, object.__name__, 0, 0)) - modnames.append(modname) - elif pydoc.ispackage(path): - modpkgs.append((file, object.__name__, 1, 0)) - modpkgs.sort() - # do more recursion here... - for (modname, name, ya,yo) in modpkgs: - packageContext.addInteresting( join( (object.__name__, modname), '.')) - items = [] - for (modname, name, ispackage,isshadowed) in modpkgs: - try: - # get the actual module object... -## if modname == "events": -## import pdb -## pdb.set_trace() - module = pydoc.safeimport( "%s.%s"%(name,modname) ) - description, documentation = pydoc.splitdoc( inspect.getdoc( module )) - if description: - items.append( - """%s -- %s"""% ( - self.modpkglink( (modname, name, ispackage, isshadowed) ), - description, - ) - ) - else: - items.append( - self.modpkglink( (modname, name, ispackage, isshadowed) ) - ) - except: - items.append( - self.modpkglink( (modname, name, ispackage, isshadowed) ) - ) - contents = string.join( items, '
') - result = self.bigsection( - 'Package Contents', '#ffffff', '#aa55cc', contents) - elif modules: -#FIX contents = self.multicolumn( -#FIX modules, lambda (key, value), s=self: s.modulelink(value)) - result = self.bigsection( - 'Modules', '#fffff', '#aa55cc', contents) - else: - result = "" - return result - - + """Default formatter.""" + + def docmodule(self, object, name=None, mod=None, packageContext = None, *ignored): + """Produce HTML documentation for a module object.""" + my_name = object.__name__ # ignore the passed-in name + parts = split(my_name, '.') + links = [] + for i in range(len(parts) - 1): + links.append( + '%s' % + (join(parts[:i + 1], '.'), parts[i])) + linkedname = join(links + parts[-1:], '.') + head = '%s' % linkedname + try: + path = inspect.getabsfile(object) + url = path + if sys.platform == 'win32': + import nturl2path + url = nturl2path.pathname2url(path) + filelink = '%s' % (url, path) + except TypeError: + filelink = '(built-in)' + info = [] + if hasattr(object, '__version__'): + version = str(object.__version__) + if version[:11] == '$' + 'Revision: ' and version[-1:] == '$': + version = strip(version[11:-1]) + info.append('version %s' % self.escape(version)) + if hasattr(object, '__date__'): + info.append(self.escape(str(object.__date__))) + if info: + head = head + ' (%s)' % join(info, ', ') + result = self.heading( + head, '#ffffff', '#7799ee', 'index
' + filelink) + + modules = inspect.getmembers(object, inspect.ismodule) + + classes, cdict = [], {} + for key, value in inspect.getmembers(object, inspect.isclass): + if (inspect.getmodule(value) or object) is object: + classes.append((key, value)) + cdict[key] = cdict[value] = '#' + key + for key, value in classes: + for base in value.__bases__: + key, modname = base.__name__, base.__module__ + module = sys.modules.get(modname) + if modname != my_name and module and hasattr(module, key): + if getattr(module, key) is base: + if key not in cdict: + cdict[key] = cdict[base] = modname + '.html#' + key + funcs, fdict = [], {} + for key, value in inspect.getmembers(object, inspect.isroutine): + if inspect.isbuiltin(value) or inspect.getmodule(value) is object: + funcs.append((key, value)) + fdict[key] = '#-' + key + if inspect.isfunction(value): + fdict[value] = fdict[key] + data = [] + for key, value in inspect.getmembers(object, pydoc.isdata): + if key not in ['__builtins__', '__doc__']: + data.append((key, value)) + + doc = self.markup(pydoc.getdoc(object), self.preformat, fdict, cdict) + doc = doc and '%s' % doc + result = result + '

%s

\n' % doc + + packageContext.clean(classes, object) + packageContext.clean(funcs, object) + packageContext.clean(data, object) + + if hasattr(object, '__path__'): + modpkgs = [] + modnames = [] + for file in os.listdir(object.__path__[0]): + path = os.path.join(object.__path__[0], file) + modname = inspect.getmodulename(file) + if modname and modname not in modnames: + modpkgs.append((modname, my_name, 0, 0)) + modnames.append(modname) + elif pydoc.ispackage(path): + modpkgs.append((file, my_name, 1, 0)) + modpkgs.sort() + contents = self.multicolumn(modpkgs, self.modpkglink) + # # result = result + self.bigsection( + # # 'Package Contents', '#ffffff', '#aa55cc', contents) + result = result + self.moduleSection(object, packageContext) + elif modules: + # FIX contents = self.multicolumn( + # FIX modules, lambda (key, value), s=self: s.modulelink(value)) + result = result + self.bigsection( + 'Modules', '#fffff', '#aa55cc', contents) + + if classes: + # FIX classlist = map(lambda (key, value): value, classes) + contents = [ + self.formattree(inspect.getclasstree(classlist, 1), my_name)] # noqa F821 + for key, value in classes: + contents.append(self.document(value, key, my_name, fdict, cdict)) + result = result + self.bigsection( + 'Classes', '#ffffff', '#ee77aa', join(contents)) + if funcs: + contents = [] + for key, value in funcs: + contents.append(self.document(value, key, my_name, fdict, cdict)) + result = result + self.bigsection( + 'Functions', '#ffffff', '#eeaa77', join(contents)) + if data: + contents = [] + for key, value in data: + try: + contents.append(self.document(value, key)) + except Exception: # nosec + pass + result = result + self.bigsection( + 'Data', '#ffffff', '#55aa55', join(contents, '
\n')) + if hasattr(object, '__author__'): + contents = self.markup(str(object.__author__), self.preformat) + result = result + self.bigsection( + 'Author', '#ffffff', '#7799ee', contents) + if hasattr(object, '__credits__'): + contents = self.markup(str(object.__credits__), self.preformat) + result = result + self.bigsection( + 'Credits', '#ffffff', '#7799ee', contents) + + return result + + def classlink(self, object, modname): + """Make a link for a class.""" + name, module = object.__name__, sys.modules.get(object.__module__) + if hasattr(module, name) and getattr(module, name) is object: + return '%s' % ( + module.__name__, name, name + ) + return pydoc.classname(object, modname) + + def moduleSection(self, object, packageContext): + """Create a module-links section for the given object (module)""" + modules = inspect.getmembers(object, inspect.ismodule) + packageContext.clean(modules, object) + packageContext.recurseScan(modules) + + if hasattr(object, '__path__'): + modpkgs = [] + modnames = [] + for file in os.listdir(object.__path__[0]): + path = os.path.join(object.__path__[0], file) + modname = inspect.getmodulename(file) + if modname and modname not in modnames: + modpkgs.append((modname, object.__name__, 0, 0)) + modnames.append(modname) + elif pydoc.ispackage(path): + modpkgs.append((file, object.__name__, 1, 0)) + modpkgs.sort() + # do more recursion here... + for (modname, name, ya, yo) in modpkgs: + packageContext.addInteresting(join((object.__name__, modname), '.')) + items = [] + for (modname, name, ispackage, isshadowed) in modpkgs: + try: + module = pydoc.safeimport("%s.%s" % (name, modname)) + description, documentation = pydoc.splitdoc(inspect.getdoc(module)) + if description: + txt = f"{self.modpkglink((modname, name, ispackage, isshadowed))} -- {description}" + items.append(txt) + else: + items.append( + self.modpkglink((modname, name, ispackage, isshadowed)) + ) + except: # noqa E722 NOSONAR + items.append( + self.modpkglink((modname, name, ispackage, isshadowed)) + ) + contents = string.join(items, '
') + result = self.bigsection( + 'Package Contents', '#ffffff', '#aa55cc', contents) + elif modules: + result = self.bigsection( + 'Modules', '#fffff', '#aa55cc', contents) + else: + result = "" + return result + + class AlreadyDone(Exception): - pass - + """Already done.""" + + pass class PackageDocumentationGenerator: - """A package document generator creates documentation - for an entire package using pydoc's machinery. - - baseModules -- modules which will be included - and whose included and children modules will be - considered fair game for documentation - destinationDirectory -- the directory into which - the HTML documentation will be written - recursion -- whether to add modules which are - referenced by and/or children of base modules - exclusions -- a list of modules whose contents will - not be shown in any other module, commonly - such modules as OpenGL.GL, wxPython.wx etc. - recursionStops -- a list of modules which will - explicitly stop recursion (i.e. they will never - be included), even if they are children of base - modules. - formatter -- allows for passing in a custom formatter - see DefaultFormatter for sample implementation. - """ - def __init__ ( - self, baseModules, destinationDirectory = ".", - recursion = 1, exclusions = (), - recursionStops = (), - formatter = None - ): - self.destinationDirectory = os.path.abspath( destinationDirectory) - self.exclusions = {} - self.warnings = [] - self.baseSpecifiers = {} - self.completed = {} - self.recursionStops = {} - self.recursion = recursion - for stop in recursionStops: - self.recursionStops[ stop ] = 1 - self.pending = [] - for exclusion in exclusions: - try: - self.exclusions[ exclusion ]= pydoc.locate ( exclusion) - except pydoc.ErrorDuringImport: - self.warn( """Unable to import the module %s which was specified as an exclusion module"""% (repr(exclusion))) - self.formatter = formatter or DefaultFormatter() - for base in baseModules: - self.addBase( base ) - def warn( self, message ): - """Warnings are used for recoverable, but not necessarily ignorable conditions""" - self.warnings.append (message) - def info (self, message): - """Information/status report""" - _log.debug(message) - - def addBase(self, specifier): - """Set the base of the documentation set, only children of these modules will be documented""" - try: - self.baseSpecifiers [specifier] = pydoc.locate ( specifier) - self.pending.append (specifier) - except pydoc.ErrorDuringImport: - self.warn( """Unable to import the module %s which was specified as a base module"""% (repr(specifier))) - def addInteresting( self, specifier): - """Add a module to the list of interesting modules""" - if self.checkScope( specifier): - self.pending.append (specifier) - else: - self.completed[ specifier] = 1 - def checkScope (self, specifier): - """Check that the specifier is "in scope" for the recursion""" - if not self.recursion: - return 0 - items = string.split (specifier, ".") - stopCheck = items [:] - while stopCheck: - name = string.join(items, ".") - if self.recursionStops.get( name): - return 0 - elif self.completed.get (name): - return 0 - del stopCheck[-1] - while items: - if self.baseSpecifiers.get( string.join(items, ".")): - return 1 - del items[-1] - # was not within any given scope - return 0 - - def process( self ): - """Having added all of the base and/or interesting modules, - proceed to generate the appropriate documentation for each - module in the appropriate directory, doing the recursion - as we go.""" - try: - while self.pending: - try: - if self.completed.has_key( self.pending[0] ): - raise AlreadyDone( self.pending[0] ) - self.info( """Start %s"""% (repr(self.pending[0]))) - object = pydoc.locate ( self.pending[0] ) - self.info( """ ... found %s"""% (repr(object.__name__))) - except AlreadyDone: - pass - except pydoc.ErrorDuringImport as value: - self.info( """ ... FAILED %s"""% (repr( value))) - self.warn( """Unable to import the module %s"""% (repr(self.pending[0]))) - except (SystemError, SystemExit) as value: - self.info( """ ... FAILED %s"""% (repr( value))) - self.warn( """Unable to import the module %s"""% (repr(self.pending[0]))) - except Exception as value: - self.info( """ ... FAILED %s"""% (repr( value))) - self.warn( """Unable to import the module %s"""% (repr(self.pending[0]))) - else: - page = self.formatter.page( - pydoc.describe(object), - self.formatter.docmodule( - object, - object.__name__, - packageContext = self, - ) - ) - file = open ( - os.path.join( - self.destinationDirectory, - self.pending[0] + ".html", - ), - 'w', - ) - file.write(page) - file.close() - self.completed[ self.pending[0]] = object - del self.pending[0] - finally: - for item in self.warnings: - _log.info(item) - - def clean (self, objectList, object): - """callback from the formatter object asking us to remove - those items in the key, value pairs where the object is - imported from one of the excluded modules""" - for key, value in objectList[:]: - for excludeObject in self.exclusions.values(): - if hasattr( excludeObject, key ) and excludeObject is not object: - if ( - getattr( excludeObject, key) is value or - (hasattr( excludeObject, '__name__') and - excludeObject.__name__ == "Numeric" - ) - ): - objectList[:] = [ (k,o) for k,o in objectList if k != key ] - def recurseScan(self, objectList): - """Process the list of modules trying to add each to the - list of interesting modules""" - for key, value in objectList: - self.addInteresting( value.__name__ ) - -#---------------------------------------------------------------------------# -# Main Runner -#---------------------------------------------------------------------------# + """A package document generator creates documentation. + + for an entire package using pydoc's machinery. + + baseModules -- modules which will be included + and whose included and children modules will be + considered fair game for documentation + destinationDirectory -- the directory into which + the HTML documentation will be written + recursion -- whether to add modules which are + referenced by and/or children of base modules + exclusions -- a list of modules whose contents will + not be shown in any other module, commonly + such modules as OpenGL.GL, wxPython.wx etc. + recursionStops -- a list of modules which will + explicitly stop recursion (i.e. they will never + be included), even if they are children of base + modules. + formatter -- allows for passing in a custom formatter + see DefaultFormatter for sample implementation. + """ + + def __init__( + self, baseModules, destinationDirectory = ".", + recursion = 1, exclusions = (), + recursionStops = (), + formatter = None + ): + """Initialize.""" + self.destinationDirectory = os.path.abspath(destinationDirectory) + self.exclusions = {} + self.warnings = [] + self.baseSpecifiers = {} + self.completed = {} + self.recursionStops = {} + self.recursion = recursion + for stop in recursionStops: + self.recursionStops[stop] = 1 + self.pending = [] + for exclusion in exclusions: + try: + self.exclusions[exclusion] = pydoc.locate(exclusion) + except pydoc.ErrorDuringImport: + self.warn("""Unable to import the module %s which was specified as an exclusion module""" % + (repr(exclusion))) + self.formatter = formatter or DefaultFormatter() + for base in baseModules: + self.addBase(base) + + def warn(self, message): + """Get warnings are used for recoverable, but not necessarily ignorable conditions.""" + self.warnings.append(message) + + def info(self, message): + """Get information/status report.""" + _log.debug(message) + + def addBase(self, specifier): + """Set the base of the documentation set, only children of these modules will be documented.""" + try: + self.baseSpecifiers[specifier] = pydoc.locate(specifier) + self.pending.append(specifier) + except pydoc.ErrorDuringImport: + self.warn("""Unable to import the module %s which was specified as a base module""" % (repr(specifier))) + + def addInteresting(self, specifier): + """Add a module to the list of interesting modules.""" + if self.checkScope(specifier): + self.pending.append(specifier) + else: + self.completed[specifier] = 1 + + def checkScope(self, specifier): + """Check that the specifier is "in scope" for the recursion.""" + if not self.recursion: + return 0 + items = string.split(specifier, ".") + stopCheck = items[:] + while stopCheck: + name = string.join(items, ".") + if self.recursionStops.get(name): + return 0 + elif self.completed.get(name): + return 0 + del stopCheck[-1] + while items: + if self.baseSpecifiers.get(string.join(items, ".")): + return 1 + del items[-1] + # was not within any given scope + return 0 + + def process(self): + """Process. + + Having added all of the base and/or interesting modules, + proceed to generate the appropriate documentation for each + module in the appropriate directory, doing the recursion + as we go. + """ + try: + while self.pending: + try: + if self.pending[0] in self.completed: + raise AlreadyDone(self.pending[0]) + self.info("""Start %s""" % (repr(self.pending[0]))) + object = pydoc.locate(self.pending[0]) + self.info(""" ... found %s""" % (repr(object.__name__))) + except AlreadyDone: + pass + except pydoc.ErrorDuringImport as value: + self.info(""" ... FAILED %s""" % (repr(value))) + self.warn("""Unable to import the module %s""" % (repr(self.pending[0]))) + except (SystemError, SystemExit) as value: + self.info(""" ... FAILED %s""" % (repr(value))) + self.warn("""Unable to import the module %s""" % (repr(self.pending[0]))) + except Exception as value: + self.info(""" ... FAILED %s""" % (repr(value))) + self.warn("""Unable to import the module %s""" % (repr(self.pending[0]))) + else: + page = self.formatter.page( + pydoc.describe(object), + self.formatter.docmodule( + object, + object.__name__, + packageContext = self, + ) + ) + file = open( + os.path.join( + self.destinationDirectory, + self.pending[0] + ".html", + ), + 'w', + ) + file.write(page) + file.close() + self.completed[self.pending[0]] = object + del self.pending[0] + finally: + for item in self.warnings: + _log.info(item) + + def clean(self, objectList, object): + """Clean. + + Callback from the formatter object asking us to remove + those items in the key, value pairs where the object is + imported from one of the excluded modules. + """ + for key, value in objectList[:]: + for excludeObject in self.exclusions.values(): + if hasattr(excludeObject, key) and excludeObject is not object: + if ( + getattr(excludeObject, key) is value or # noqa W504 + (hasattr(excludeObject, '__name__') and # noqa W504 + excludeObject.__name__ == "Numeric" + ) + ): + objectList[:] = [(k, o) for k, o in objectList if k != key] + + def recurseScan(self, objectList): + """Process the list of modules. + + trying to add each to the + list of interesting modules. + """ + for key, value in objectList: + self.addInteresting(value.__name__) + + +# ---------------------------------------------------------------------------# +# Main Runner +# ---------------------------------------------------------------------------# if __name__ == "__main__": if not os.path.exists("./html"): os.mkdir("./html") @@ -453,7 +469,7 @@ def recurseScan(self, objectList): destinationDirectory = "./html/", exclusions = ['math', 'string', 'twisted'], recursionStops = [], - ).process () + ).process() if os.path.exists('../../../build'): shutil.move("html", "../../../build/pydoc") diff --git a/doc/api/pydoctor/build.py b/doc/api/pydoctor/build.py index 2f67cef59..4c6f37eb1 100755 --- a/doc/api/pydoctor/build.py +++ b/doc/api/pydoctor/build.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pydoctor API Runner ---------------------- +"""Pydoctor API Runner. Using pkg_resources, we attempt to see if pydoctor is installed, if so, we use its cli program to compile the documents @@ -12,7 +11,7 @@ import pkg_resources pkg_resources.require("pydoctor") - from pydoctor.driver import main # pylint: disable=import-error + from pydoctor.driver import main # pylint: disable=import-error sys.argv = """pydoctor.py --quiet --project-name=Pymodbus --project-url=http://code.google.com/p/pymodbus/ @@ -20,10 +19,10 @@ --html-output=html --html-write-function-pages --make-html""".split() - print( "Building Pydoctor API Documentation") + print("Building Pydoctor API Documentation") main(sys.argv[1:]) if os.path.exists('../../../build'): shutil.move("html", "../../../build/pydoctor") -except: #NOSONAR pylint: disable=bare-except +except: # noqa E722 NOSONAR pylint: disable=bare-except print("Pydoctor unavailable...not building") diff --git a/doc/conf.py b/doc/conf.py index c7248959e..36a9b75bb 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -1,4 +1,4 @@ -""" Document configuration. """ +"""Document configuration.""" # -*- coding: utf-8 -*- # # PyModbus documentation build configuration file, created by @@ -34,7 +34,7 @@ # sys.path.extend([examples, example_common, example_contrib, example_gui]) # sys.path.insert(0, os.path.abspath('../')) -github_doc_root = 'https://github.com/riptideio/pymodbus/tree/master/doc/' # pylint: disable=invalid-name +github_doc_root = 'https://github.com/riptideio/pymodbus/tree/master/doc/' # pylint: disable=invalid-name # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. @@ -45,7 +45,7 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -#extensions = ['sphinx.ext.autodoc', 'm2r', 'recommonmark'] +# extensions = ['sphinx.ext.autodoc', 'm2r', 'recommonmark'] extensions = ['sphinx.ext.autodoc', 'm2r2'] # Add any paths that contain templates here, relative to this directory. @@ -54,20 +54,20 @@ # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # -#source_parsers = { +# source_parsers = { # '.md': CommonMarkParser, -#} +# } source_suffix = ['.rst', '.md'] # source_suffix = '.rst' # The master toctree document. -master_doc = 'index' # pylint: disable=invalid-name +master_doc = 'index' # pylint: disable=invalid-name # General information about the project. -project = 'PyModbus' # pylint: disable=invalid-name -copyright = '2017, Sanjay' # pylint: disable=redefined-builtin,invalid-name -author = 'Sanjay' # pylint: disable=invalid-name +project = 'PyModbus' # pylint: disable=invalid-name +copyright = '2017, Sanjay' # pylint: disable=redefined-builtin,invalid-name +author = 'Sanjay' # pylint: disable=invalid-name # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -83,7 +83,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None # pylint: disable=invalid-name +language = None # pylint: disable=invalid-name # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -91,10 +91,10 @@ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' # pylint: disable=invalid-name +pygments_style = 'sphinx' # pylint: disable=invalid-name # If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = False # pylint: disable=invalid-name +todo_include_todos = False # pylint: disable=invalid-name # -- Options for HTML output ---------------------------------------------- @@ -102,7 +102,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'sphinx_rtd_theme' # pylint: disable=invalid-name +html_theme = 'sphinx_rtd_theme' # pylint: disable=invalid-name # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -132,7 +132,7 @@ # -- Options for HTMLHelp output ------------------------------------------ # Output file base name for HTML help builder. -htmlhelp_basename = 'PyModbusdoc' # pylint: disable=invalid-name +htmlhelp_basename = 'PyModbusdoc' # pylint: disable=invalid-name # -- Options for LaTeX output --------------------------------------------- @@ -158,8 +158,8 @@ # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). -latex_documents = [ #NOSONAR - (master_doc, 'PyModbus.tex', 'PyModbus Documentation', #NOSONAR +latex_documents = [ # NOSONAR + (master_doc, 'PyModbus.tex', 'PyModbus Documentation', # NOSONAR 'Sanjay', 'manual'), ] @@ -187,9 +187,11 @@ def setup(app): - """ Setup. """ + """Do setup.""" app.add_config_value('recommonmark_config', { - 'url_resolver': lambda url: github_doc_root + url, - 'auto_toc_tree_section': 'Contents', - }, True) + 'url_resolver': lambda url: github_doc_root + url, + 'auto_toc_tree_section': 'Contents', + }, + True + ) app.add_transform(AutoStructify) diff --git a/examples/common/async_asyncio_client.py b/examples/common/async_asyncio_client.py index db564938d..13023f7d9 100644 --- a/examples/common/async_asyncio_client.py +++ b/examples/common/async_asyncio_client.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Asynchronous Client Examples --------------------------------------------------------------------------- +"""Pymodbus Asynchronous Client Examples. The following is an example of how to use the asynchronous modbus client implementation from pymodbus with asyncio. @@ -41,7 +40,7 @@ async def start_async_test(client): - """ Start async test. """ + """Start async test.""" # ----------------------------------------------------------------------- # # specify slave to query # ----------------------------------------------------------------------- # @@ -67,14 +66,14 @@ async def start_async_test(client): _logger.debug("Write to a Coil and read back") rq = await client.write_coil(0, True, unit=UNIT) rr = await client.read_coils(0, 1, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error - assert rr.bits[0] #nosec test the expected value + assert rq.function_code < 0x80 # nosec test that we are not an error + assert rr.bits[0] # nosec test the expected value _logger.debug("Write to multiple coils and read back- test 1") rq = await client.write_coils(1, [True] * 8, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error + assert rq.function_code < 0x80 # nosec test that we are not an error rr = await client.read_coils(1, 21, unit=UNIT) - assert rr.function_code < 0x80 #nosec test that we are not an error + assert rr.function_code < 0x80 # nosec test that we are not an error resp = [True] * 21 # If the returned output quantity is not a multiple of eight, @@ -82,33 +81,33 @@ async def start_async_test(client): # (toward the high order end of the byte). resp.extend([False] * 3) - assert rr.bits == resp #nosec test the expected value + assert rr.bits == resp # nosec test the expected value _logger.debug("Write to multiple coils and read back - test 2") rq = await client.write_coils(1, [False] * 8, unit=UNIT) rr = await client.read_coils(1, 8, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error - assert rr.bits == [False] * 8 #nosec test the expected value + assert rq.function_code < 0x80 # nosec test that we are not an error + assert rr.bits == [False] * 8 # nosec test the expected value _logger.debug("Read discrete inputs") rr = await client.read_discrete_inputs(0, 8, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error + assert rq.function_code < 0x80 # nosec test that we are not an error _logger.debug("Write to a holding register and read back") rq = await client.write_register(1, 10, unit=UNIT) rr = await client.read_holding_registers(1, 1, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error - assert rr.registers[0] == 10 #nosec test the expected value + assert rq.function_code < 0x80 # nosec test that we are not an error + assert rr.registers[0] == 10 # nosec test the expected value _logger.debug("Write to multiple holding registers and read back") rq = await client.write_registers(1, [10] * 8, unit=UNIT) rr = await client.read_holding_registers(1, 8, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error - assert rr.registers == [10] * 8 #nosec test the expected value + assert rq.function_code < 0x80 # nosec test that we are not an error + assert rr.registers == [10] * 8 # nosec test the expected value _logger.debug("Read input registers") rr = await client.read_input_registers(1, 8, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error + assert rq.function_code < 0x80 # nosec test that we are not an error arguments = { 'read_address': 1, @@ -119,20 +118,21 @@ async def start_async_test(client): _logger.debug("Read write registers simultaneously") rq = await client.readwrite_registers(unit=UNIT, **arguments) rr = await client.read_holding_registers(1, 8, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error - assert rq.registers == [20] * 8 #nosec test the expected value - assert rr.registers == [20] * 8 #nosec test the expected value + assert rq.function_code < 0x80 # nosec test that we are not an error + assert rq.registers == [20] * 8 # nosec test the expected value + assert rr.registers == [20] * 8 # nosec test the expected value await asyncio.sleep(1) def run_with_not_running_loop(): - """ A loop is created and is passed to ModbusClient factory to be used. """ + """Create loop and pass to ModbusClient factory to be used.""" _logger.debug("Running Async client with asyncio loop not yet started") _logger.debug("------------------------------------------------------") loop = asyncio.new_event_loop() - assert not loop.is_running() #nosec + assert not loop.is_running() # nosec asyncio.set_event_loop(loop) - new_loop, client = ModbusClient(schedulers.ASYNC_IO, port=5020, loop=loop) #NOSONAR pylint: disable=unpacking-non-sequence + new_loop, client = ModbusClient(schedulers.ASYNC_IO, # NOSONAR pylint: disable=unpacking-non-sequence + port=5020, loop=loop) loop.run_until_complete(start_async_test(client.protocol)) loop.close() _logger.debug("--------------RUN_WITH_NOT_RUNNING_LOOP---------------") @@ -140,19 +140,16 @@ def run_with_not_running_loop(): async def run_with_already_running_loop(): - """ An already running loop is passed to ModbusClient Factory. """ + """Pass an already running loop to ModbusClient Factory.""" _logger.debug("Running Async client with asyncio loop already started") _logger.debug("------------------------------------------------------") - def done(future): # pylint: disable=unused-argument - """ Done. """ + def done(future): # pylint: disable=unused-argument + """Done.""" _logger.info("Done !!!") def start_loop(loop): - """ Start Loop - :param loop: - :return: - """ + """Start Loop""" asyncio.set_event_loop(loop) loop.run_forever() @@ -162,9 +159,10 @@ def start_loop(loop): # Start the loop mythread.start() asyncio.sleep(1) - assert loop.is_running() #nosec + assert loop.is_running() # nosec asyncio.set_event_loop(loop) - loop, client = ModbusClient(schedulers.ASYNC_IO, port=5020, loop=loop) #NOSONAR pylint: disable=unpacking-non-sequence + loop, client = ModbusClient(schedulers.ASYNC_IO, # NOSONAR pylint: disable=unpacking-non-sequence + port=5020, loop=loop) future = asyncio.run_coroutine_threadsafe( start_async_test(client.protocol), loop=loop) future.add_done_callback(done) @@ -176,11 +174,9 @@ def start_loop(loop): def run_with_no_loop(): - """ ModbusClient Factory creates a loop. - :return: - """ + """Create a loop.""" _logger.debug("---------------------RUN_WITH_NO_LOOP-----------------") - loop, client = ModbusClient(schedulers.ASYNC_IO, port=5020) #NOSONAR pylint: disable=unpacking-non-sequence + loop, client = ModbusClient(schedulers.ASYNC_IO, port=5020) # NOSONAR pylint: disable=unpacking-non-sequence loop.run_until_complete(start_async_test(client.protocol)) loop.close() _logger.debug("--------DONE RUN_WITH_NO_LOOP-------------") diff --git a/examples/common/async_asyncio_serial_client.py b/examples/common/async_asyncio_serial_client.py index 282fe9bde..4bac40c60 100755 --- a/examples/common/async_asyncio_serial_client.py +++ b/examples/common/async_asyncio_serial_client.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Asynchronous Client Examples --------------------------------------------------------------------------- +"""Pymodbus Asynchronous Client Examples. The following is an example of how to use the asynchronous serial modbus client implementation from pymodbus with asyncio. @@ -32,8 +31,8 @@ UNIT = 0x01 -async def start_async_test(client): # pylint: disable=redefined-outer-name - """ Start async test. """ +async def start_async_test(client): # pylint: disable=redefined-outer-name + """Start async test.""" # ----------------------------------------------------------------------- # # specify slave to query # ----------------------------------------------------------------------- # @@ -59,15 +58,15 @@ async def start_async_test(client): # pylint: disable=redefined-outer-name rq = await client.write_coil(0, True, unit=UNIT) rr = await client.read_coils(0, 1, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error - assert rr.bits[0] #nosec test the expected value + assert rq.function_code < 0x80 # nosec test that we are not an error + assert rr.bits[0] # nosec test the expected value log.debug("Write to multiple coils and read back- test 1") rq = await client.write_coils(1, [True] * 8, unit=UNIT) rr = await client.read_coils(1, 21, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error - assert rr.function_code < 0x80 #nosec test that we are not an error + assert rq.function_code < 0x80 # nosec test that we are not an error + assert rr.function_code < 0x80 # nosec test that we are not an error # If the returned output quantity is not a multiple of eight, # the remaining bits in the final data byte will be padded with zeros @@ -75,33 +74,33 @@ async def start_async_test(client): # pylint: disable=redefined-outer-name resp = [True] * 21 resp.extend([False] * 3) - assert rr.bits == resp #nosec test the expected value + assert rr.bits == resp # nosec test the expected value log.debug("Write to multiple coils and read back - test 2") rq = await client.write_coils(1, [False] * 8, unit=UNIT) rr = await client.read_coils(1, 8, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error - assert rr.bits == [False] * 8 #nosec test the expected value + assert rq.function_code < 0x80 # nosec test that we are not an error + assert rr.bits == [False] * 8 # nosec test the expected value log.debug("Read discrete inputs") rr = await client.read_discrete_inputs(0, 8, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error + assert rq.function_code < 0x80 # nosec test that we are not an error log.debug("Write to a holding register and read back") rq = await client.write_register(1, 10, unit=UNIT) rr = await client.read_holding_registers(1, 1, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error - assert rr.registers[0] == 10 #nosec test the expected value + assert rq.function_code < 0x80 # nosec test that we are not an error + assert rr.registers[0] == 10 # nosec test the expected value log.debug("Write to multiple holding registers and read back") rq = await client.write_registers(1, [10] * 8, unit=UNIT) rr = await client.read_holding_registers(1, 8, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error - assert rr.registers == [10] * 8 #nosec test the expected value + assert rq.function_code < 0x80 # nosec test that we are not an error + assert rr.registers == [10] * 8 # nosec test the expected value log.debug("Read input registers") rr = await client.read_input_registers(1, 8, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error + assert rq.function_code < 0x80 # nosec test that we are not an error arguments = { 'read_address': 1, @@ -112,10 +111,10 @@ async def start_async_test(client): # pylint: disable=redefined-outer-name log.debug("Read write registers simultaneously") rq = await client.readwrite_registers(unit=UNIT, **arguments) rr = await client.read_holding_registers(1, 8, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error - assert rq.registers == [20] * 8 #nosec test the expected value - assert rr.registers == [20] * 8 #nosec test the expected value - except Exception as exc: # pylint: disable=broad-except + assert rq.function_code < 0x80 # nosec test that we are not an error + assert rq.registers == [20] * 8 # nosec test the expected value + assert rr.registers == [20] * 8 # nosec test the expected value + except Exception as exc: # pylint: disable=broad-except log.exception(exc) client.transport.close() await asyncio.sleep(1) @@ -128,7 +127,7 @@ async def start_async_test(client): # pylint: disable=redefined-outer-name # ----------------------------------------------------------------------- # # socat -d -d PTY,link=/tmp/ptyp0,raw,echo=0,ispeed=9600 PTY, # link=/tmp/ttyp0,raw,echo=0,ospeed=9600 - loop, client = ModbusClient(schedulers.ASYNC_IO, port='/tmp/ttyp0', #nosec pylint: disable=unpacking-non-sequence + loop, client = ModbusClient(schedulers.ASYNC_IO, port='/tmp/ttyp0', # nosec pylint: disable=unpacking-non-sequence baudrate=9600, method="rtu") loop.run_until_complete(start_async_test(client.protocol)) loop.close() diff --git a/examples/common/async_tornado_client.py b/examples/common/async_tornado_client.py index 9ea7c69d5..c85815293 100755 --- a/examples/common/async_tornado_client.py +++ b/examples/common/async_tornado_client.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Asynchronous Client Examples --------------------------------------------------------------------------- +"""Pymodbus Asynchronous Client Examples. The following is an example of how to use the asynchronous modbus client implementation from pymodbus using Tornado. @@ -29,12 +28,12 @@ # ---------------------------------------------------------------------------# -def dassert(future, callback): # pylint: disable=redefined-outer-name - """ Dassert. """ +def dassert(future, callback): # pylint: disable=redefined-outer-name + """Dassert.""" def _assertor(value): # by pass assertion, an error here stops the write callbacks - assert value #nosec + assert value # nosec def on_done(f_trans): if (exc := f_trans.exception()): @@ -47,7 +46,7 @@ def on_done(f_trans): def _print(value): - """ Internal print. """ + """Print.""" if hasattr(value, "bits"): result = value.bits elif hasattr(value, "registers"): @@ -74,8 +73,8 @@ def _print(value): # ---------------------------------------------------------------------------# -def begin_asynchronous_test(client, protocol): # pylint: disable=redefined-outer-name - """ Begin async test. """ +def begin_asynchronous_test(client, protocol): # pylint: disable=redefined-outer-name + """Begin async test.""" rq = client.write_coil(1, True, unit=UNIT) rr = client.read_coils(1, 1, unit=UNIT) dassert(rq, lambda r: r.function_code < 0x80) # test for no error @@ -128,13 +127,13 @@ def begin_asynchronous_test(client, protocol): # pylint: disable=redefined-outer def err(*args, **kwargs): - """ Error. """ + """Error.""" txt = f"Err {args} {kwargs}" _logger.error(txt) -def callback(protocol, future): # pylint: disable=redefined-outer-name - """ Callback. """ +def callback(protocol, future): # pylint: disable=redefined-outer-name + """Call as callback.""" _logger.debug("Client connected") if (exp := future.exception()): return err(exp) @@ -144,5 +143,5 @@ def callback(protocol, future): # pylint: disable=redefined-outer-name if __name__ == "__main__": - protocol, future = ModbusClient(schedulers.IO_LOOP, port=5020) #NOSONAR pylint: disable=unpacking-non-sequence + protocol, future = ModbusClient(schedulers.IO_LOOP, port=5020) # NOSONAR pylint: disable=unpacking-non-sequence future.add_done_callback(functools.partial(callback, protocol)) diff --git a/examples/common/async_tornado_client_serial.py b/examples/common/async_tornado_client_serial.py index 20a1da1b9..70b7466d4 100755 --- a/examples/common/async_tornado_client_serial.py +++ b/examples/common/async_tornado_client_serial.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Asynchronous Client Examples --------------------------------------------------------------------------- +"""Pymodbus Asynchronous Client Examples. The following is an example of how to use the asynchronous serial modbus client implementation from pymodbus using tornado. @@ -36,12 +35,12 @@ # ---------------------------------------------------------------------------# -def dassert(future, callback): # pylint: disable=redefined-outer-name - """ Dassert. """ +def dassert(future, callback): # pylint: disable=redefined-outer-name + """Dassert.""" def _assertor(value): # by pass assertion, an error here stops the write callbacks - assert value #nosec + assert value # nosec def on_done(f_trans): if (exc := f_trans.exception()): @@ -54,7 +53,7 @@ def on_done(f_trans): def _print(value): - """ Internal print """ + """Print.""" if hasattr(value, "bits"): result = value.bits elif hasattr(value, "registers"): @@ -79,8 +78,8 @@ def _print(value): # ---------------------------------------------------------------------------# -def begin_asynchronous_test(client, protocol): #NOSONAR pylint: disable=redefined-outer-name - """ Begin async test. """ +def begin_asynchronous_test(client, protocol): # NOSONAR pylint: disable=redefined-outer-name + """Begin async test.""" rq = client.write_coil(1, True, unit=UNIT) rr = client.read_coils(1, 1, unit=UNIT) dassert(rq, lambda r: r.function_code < 0x80) # test for no error @@ -133,13 +132,13 @@ def begin_asynchronous_test(client, protocol): #NOSONAR pylint: disable=redefine # ---------------------------------------------------------------------------# def err(*args, **kwargs): - """" handle error. """ + """Handle error.""" txt = f"Err {args} {kwargs}" log.error(txt) -def callback(protocol, future): # pylint: disable=redefined-outer-name - """ Callback. """ +def callback(protocol, future): # pylint: disable=redefined-outer-name + """Call Callback.""" log.debug("Client connected") if (exp := future.exception()): return err(exp) @@ -159,9 +158,9 @@ def callback(protocol, future): # pylint: disable=redefined-outer-name # ----------------------------------------------------------------------- # # Rtu - protocol, future = AsyncModbusSerialClient(schedulers.IO_LOOP, # NOSONAR pylint: disable=unpacking-non-sequence + protocol, future = AsyncModbusSerialClient(schedulers.IO_LOOP, # NOSONAR pylint: disable=unpacking-non-sequence method="rtu", - port="/tmp/ptyp0", # nosec NOSONAR + port="/tmp/ptyp0", # nosec NOSONAR baudrate=9600, timeout=2) diff --git a/examples/common/async_twisted_client.py b/examples/common/async_twisted_client.py index 7354cbe42..f1ac9bf41 100755 --- a/examples/common/async_twisted_client.py +++ b/examples/common/async_twisted_client.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Asynchronous Client Examples --------------------------------------------------------------------------- +"""Pymodbus Asynchronous Client Examples. The following is an example of how to use the asynchronous modbus client implementation from pymodbus. @@ -21,7 +20,7 @@ # --------------------------------------------------------------------------- # FORMAT = ('%(asctime)-15s %(threadName)-15s' ' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s') -logging.basicConfig(format=FORMAT) #NOSONAR +logging.basicConfig(format=FORMAT) # NOSONAR log = logging.getLogger() log.setLevel(logging.DEBUG) @@ -31,15 +30,15 @@ def err(*args, **kwargs): - """ Error. """ + """Error.""" txt = f"Err-{args}-{kwargs}" logging.error(txt) -def dassert(deferred, callback): # pylint: disable=redefined-outer-name - """ Dassert. """ +def dassert(deferred, callback): # pylint: disable=redefined-outer-name + """Dassert.""" def _assertor(value): - assert value #nosec + assert value # nosec deferred.addCallback(lambda r: _assertor(callback(r))) deferred.addErrback(err) @@ -56,12 +55,12 @@ def _assertor(value): def process_response(result): - """ Process response. """ + """Process response.""" log.debug(result) def example_requests(client): - """ Example requests. """ + """Do example requests.""" rr = client.read_coils(1, 1, unit=0x02) rr.addCallback(process_response) rr = client.read_holding_registers(1, 1, unit=0x02) @@ -85,16 +84,16 @@ def example_requests(client): def stop_asynchronous_test(client): - """ Stop async test. """ + """Stop async test.""" # ----------------------------------------------------------------------- # # close the client at some time later # ----------------------------------------------------------------------- # - reactor.callLater(1, client.transport.loseConnection) # pylint: disable=no-member - reactor.callLater(2, reactor.stop) # pylint: disable=no-member + reactor.callLater(1, client.transport.loseConnection) # pylint: disable=no-member + reactor.callLater(2, reactor.stop) # pylint: disable=no-member def begin_asynchronous_test(client): - """ Begin async test. """ + """Begin async test.""" rq = client.write_coil(1, True, unit=UNIT) rr = client.read_coils(1, 1, unit=UNIT) dassert(rq, lambda r: not r.isError()) # test for no error @@ -136,7 +135,7 @@ def begin_asynchronous_test(client): # close the client at some time later # ----------------------------------------------------------------------- # # reactor.callLater(1, client.transport.loseConnection) - reactor.callLater(2, reactor.stop) # pylint: disable=no-member + reactor.callLater(2, reactor.stop) # pylint: disable=no-member # --------------------------------------------------------------------------- # # extra requests @@ -164,6 +163,7 @@ def begin_asynchronous_test(client): if __name__ == "__main__": - protocol, deferred = AsyncModbusTCPClient(schedulers.REACTOR, port=5020) #NOSONAR pylint: disable=unpacking-non-sequence + protocol, deferred = AsyncModbusTCPClient(schedulers.REACTOR, # NOSONAR pylint: disable=unpacking-non-sequence + port=5020) deferred.addCallback(begin_asynchronous_test) deferred.addErrback(err) diff --git a/examples/common/async_twisted_client_serial.py b/examples/common/async_twisted_client_serial.py index dfa04585a..8be410be1 100755 --- a/examples/common/async_twisted_client_serial.py +++ b/examples/common/async_twisted_client_serial.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Asynchronous Client Examples --------------------------------------------------------------------------- +"""Pymodbus Asynchronous Client Examples. The following is an example of how to use the asynchronous serial modbus client implementation from pymodbus with twisted. @@ -19,7 +18,7 @@ # state a few constants # ---------------------------------------------------------------------------# -SERIAL_PORT = "/tmp/ptyp0" # nosec NOSONAR +SERIAL_PORT = "/tmp/ptyp0" # nosec NOSONAR STATUS_REGS = (1, 2) STATUS_COILS = (1, 3) CLIENT_DELAY = 1 @@ -27,27 +26,26 @@ class ExampleProtocol(ModbusClientProtocol): - """ Example protocol. """ + """Example protocol.""" def __init__(self, framer): - """ Initializes our custom protocol + """Initialize our custom protocol :param framer: The decoder to use to process messages :param endpoint: The endpoint to send results to """ ModbusClientProtocol.__init__(self, framer) log.debug("Beginning the processing loop") - reactor.callLater(CLIENT_DELAY, self.fetch_holding_registers) # pylint: disable=no-member + reactor.callLater(CLIENT_DELAY, self.fetch_holding_registers) # pylint: disable=no-member def fetch_holding_registers(self): - """ Defer fetching holding registers - """ + """Defer fetching holding registers""" log.debug("Starting the next cycle") result = self.read_holding_registers(*STATUS_REGS, unit=UNIT) result.addCallbacks(self.send_holding_registers, self.error_handler) def send_holding_registers(self, response): - """ Write values of holding registers, defer fetching coils + """Write values of holding registers, defer fetching coils :param response: The response to process """ @@ -57,17 +55,17 @@ def send_holding_registers(self, response): result.addCallbacks(self.start_next_cycle, self.error_handler) def start_next_cycle(self, response): - """ Write values of coils, trigger next cycle + """Write values of coils, trigger next cycle :param response: The response to process """ log.info(response.getBit(0)) log.info(response.getBit(1)) log.info(response.getBit(2)) - reactor.callLater(CLIENT_DELAY, self.fetch_holding_registers) # pylint: disable=no-member + reactor.callLater(CLIENT_DELAY, self.fetch_holding_registers) # pylint: disable=no-member - def error_handler(self, failure): # pylint: disable=no-self-use - """ Handle any twisted errors + def error_handler(self, failure): # pylint: disable=no-self-use + """Handle any twisted errors :param failure: The error to handle """ @@ -76,7 +74,7 @@ def error_handler(self, failure): # pylint: disable=no-self-use if __name__ == "__main__": import time - proto, client = AsyncModbusSerialClient(schedulers.REACTOR, # pylint: disable=unpacking-non-sequence + proto, client = AsyncModbusSerialClient(schedulers.REACTOR, # pylint: disable=unpacking-non-sequence method="rtu", port=SERIAL_PORT, timeout=2, diff --git a/examples/common/asynchronous_processor.py b/examples/common/asynchronous_processor.py index 11d3e5d24..9fd9a0883 100755 --- a/examples/common/asynchronous_processor.py +++ b/examples/common/asynchronous_processor.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Asynchronous Processor Example --------------------------------------------------------------------------- +"""Pymodbus Asynchronous Processor Example. The following is a full example of a continuous client processor. Feel free to use it as a skeleton guide in implementing your own. @@ -29,7 +28,7 @@ # --------------------------------------------------------------------------- # FORMAT = ('%(asctime)-15s %(threadName)-15s' ' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s') -logging.basicConfig(format=FORMAT) #NOSONAR +logging.basicConfig(format=FORMAT) # NOSONAR log = logging.getLogger() log.setLevel(logging.DEBUG) @@ -51,10 +50,10 @@ # callbacks. # --------------------------------------------------------------------------- # class ExampleProtocol(ModbusClientProtocol): - """ Example protocol. """ + """Example protocol.""" def __init__(self, framer, endpoint): - """ Initializes our custom protocol + """Initialize our custom protocol :param framer: The decoder to use to process messages :param endpoint: The endpoint to send results to @@ -62,17 +61,16 @@ def __init__(self, framer, endpoint): ModbusClientProtocol.__init__(self, framer) self.endpoint = endpoint log.debug("Beginning the processing loop") - reactor.callLater(CLIENT_DELAY, self.fetch_holding_registers) # pylint: disable=no-member + reactor.callLater(CLIENT_DELAY, self.fetch_holding_registers) # pylint: disable=no-member def fetch_holding_registers(self): - """ Defer fetching holding registers - """ + """Defer fetching holding registers""" log.debug("Starting the next cycle") data = self.read_holding_registers(*STATUS_REGS, unit=UNIT) data.addCallbacks(self.send_holding_registers, self.error_handler) def send_holding_registers(self, response): - """ Write values of holding registers, defer fetching coils + """Write values of holding registers, defer fetching coils :param response: The response to process """ @@ -82,17 +80,17 @@ def send_holding_registers(self, response): result.addCallbacks(self.start_next_cycle, self.error_handler) def start_next_cycle(self, response): - """ Write values of coils, trigger next cycle + """Write values of coils, trigger next cycle :param response: The response to process """ self.endpoint.write(response.getBit(0)) self.endpoint.write(response.getBit(1)) self.endpoint.write(response.getBit(2)) - reactor.callLater(CLIENT_DELAY, self.fetch_holding_registers) # pylint: disable=no-member + reactor.callLater(CLIENT_DELAY, self.fetch_holding_registers) # pylint: disable=no-member - def error_handler(self, failure): # pylint: disable=no-self-use - """ Handle any twisted errors + def error_handler(self, failure): # pylint: disable=no-self-use + """Handle any twisted errors :param failure: The error to handle """ @@ -111,17 +109,17 @@ def error_handler(self, failure): # pylint: disable=no-self-use # It also persists data between client instances (think protocol singleton). # --------------------------------------------------------------------------- # class ExampleFactory(ClientFactory): - """ Example factory. """ + """Example factory.""" protocol = ExampleProtocol def __init__(self, framer, endpoint): - """ Remember things necessary for building a protocols """ + """Remember things necessary for building a protocols""" self.framer = framer self.endpoint = endpoint def buildProtocol(self, _): - """ Create a protocol and start the reading cycle """ + """Create a protocol and start the reading cycle""" proto = self.protocol(self.framer, self.endpoint) proto.factory = self return proto @@ -137,10 +135,11 @@ def buildProtocol(self, _): # # How you start your client is really up to you. # --------------------------------------------------------------------------- # -class SerialModbusClient(serialport.SerialPort): # pylint: disable=abstract-method - """ Serial modbus client. """ +class SerialModbusClient(serialport.SerialPort): # pylint: disable=abstract-method + """Serial modbus client.""" + def __init__(self, factory, *args, **kwargs): - """ Setup the client and start listening on the serial port + """Do setup the client and start listening on the serial port :param factory: The factory to build clients with """ @@ -157,11 +156,11 @@ def __init__(self, factory, *args, **kwargs): # - a context recorder # - a database or file recorder # --------------------------------------------------------------------------- # -class LoggingLineReader: # pylint: disable=too-few-public-methods - """ Logging line reader. """ +class LoggingLineReader: # pylint: disable=too-few-public-methods + """Logging line reader.""" - def write(self, response): # pylint: disable=no-self-use - """ Handle the next modbus response + def write(self, response): # pylint: disable=no-self-use + """Handle the next modbus response :param response: The response to process """ @@ -181,7 +180,7 @@ def write(self, response): # pylint: disable=no-self-use def main(): - """ Main. """ + """Run Main.""" log.debug("Initializing the client") framer = ModbusFramer(ClientDecoder(), client=None) reader = LoggingLineReader() @@ -189,7 +188,7 @@ def main(): SerialModbusClient(factory, SERIAL_PORT, reactor) # factory = reactor.connectTCP("localhost", 502, factory) log.debug("Starting the client") - reactor.run() # pylint: disable=no-member + reactor.run() # pylint: disable=no-member if __name__ == "__main__": diff --git a/examples/common/asynchronous_server.py b/examples/common/asynchronous_server.py index 42b1adde5..e47c22af8 100755 --- a/examples/common/asynchronous_server.py +++ b/examples/common/asynchronous_server.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Asynchronous Server Example --------------------------------------------------------------------------- +"""Pymodbus Asynchronous Server Example. The asynchronous server is a high performance implementation using the twisted library as its backend. This allows it to scale to many thousands @@ -11,7 +10,7 @@ # --------------------------------------------------------------------------- # import logging -from custom_message import CustomModbusRequest # pylint: disable=import-error +from custom_message import CustomModbusRequest # pylint: disable=import-error from pymodbus.version import version from pymodbus.server.asynchronous import StartTcpServer @@ -20,24 +19,24 @@ from pymodbus.device import ModbusDeviceIdentification from pymodbus.datastore import ModbusSequentialDataBlock from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext -#from pymodbus.transaction import ( #NOSONAR +# from pymodbus.transaction import ( #NOSONAR # ModbusRtuFramer, #NOSONAR # ModbusAsciiFramer, #NOSONAR # ModbusBinaryFramer, #NOSONAR -#) #NOSONAR +# ) #NOSONAR # --------------------------------------------------------------------------- # # configure the service logging # --------------------------------------------------------------------------- # FORMAT = ('%(asctime)-15s %(threadName)-15s' ' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s') -logging.basicConfig(format=FORMAT) #NOSONAR +logging.basicConfig(format=FORMAT) # NOSONAR log = logging.getLogger() log.setLevel(logging.DEBUG) def run_async_server(): - """ Run async server. """ + """Run async server.""" # ----------------------------------------------------------------------- # # initialize your data store # ----------------------------------------------------------------------- # @@ -111,7 +110,7 @@ def run_async_server(): 'ModelName': 'Pymodbus Server', 'MajorMinorRevision': version.short(), 'ProductCode': 'PM', - 'VendorUrl': 'http://github.com/riptideio/pymodbus/', #NOSONAR + 'VendorUrl': 'http://github.com/riptideio/pymodbus/', # NOSONAR 'ProductName': 'Pymodbus Server', }) diff --git a/examples/common/asyncio_server.py b/examples/common/asyncio_server.py index e5a858270..c730e0468 100755 --- a/examples/common/asyncio_server.py +++ b/examples/common/asyncio_server.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Asyncio Server Example --------------------------------------------------------------------------- +"""Pymodbus Asyncio Server Example. The asyncio server is implemented in pure python without any third party libraries (unless you need to use the serial protocols which require @@ -28,13 +27,13 @@ # --------------------------------------------------------------------------- # FORMAT = ('%(asctime)-15s %(threadName)-15s' ' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s') -logging.basicConfig(format=FORMAT) #NOSONAR +logging.basicConfig(format=FORMAT) # NOSONAR log = logging.getLogger() log.setLevel(logging.DEBUG) async def run_server(): - """ Run server. """ + """Run server.""" # ----------------------------------------------------------------------- # # initialize your data store # ----------------------------------------------------------------------- # @@ -105,7 +104,7 @@ async def run_server(): identity = ModbusDeviceIdentification(info_name= { 'VendorName': 'Pymodbus', 'ProductCode': 'PM', - 'VendorUrl': 'http://github.com/riptideio/pymodbus/', #NOSONAR + 'VendorUrl': 'http://github.com/riptideio/pymodbus/', # NOSONAR 'ProductName': 'Pymodbus Server', 'ModelName': 'Pymodbus Server', 'MajorMinorRevision': version.short(), @@ -121,7 +120,7 @@ async def run_server(): # defer_start=False) # deferred start: - server = await StartTcpServer(context, identity=identity, address=("0.0.0.0", 5020), #nosec + server = await StartTcpServer(context, identity=identity, address=("0.0.0.0", 5020), # nosec allow_reuse_address=True, defer_start=True) asyncio.get_event_loop().call_later(20, lambda: server.serve_forever) diff --git a/examples/common/callback_server.py b/examples/common/callback_server.py index c06081d97..059070534 100755 --- a/examples/common/callback_server.py +++ b/examples/common/callback_server.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Server With Callbacks --------------------------------------------------------------------------- +"""Pymodbus Server With Callbacks. This is an example of adding callbacks to a running modbus server when a value is written to it. In order for this to work, it needs @@ -32,13 +31,13 @@ class CallbackDataBlock(ModbusSparseDataBlock): - """ A datablock that stores the new value in memory - and passes the operation to a message queue for further - processing. + """A datablock that stores the new value in memory, + + and passes the operation to a message queue for further processing. """ def __init__(self, devices, queue): - """ Initialize. """ + """Initialize.""" self.devices = devices self.queue = queue @@ -46,8 +45,8 @@ def __init__(self, devices, queue): values[0xbeef] = len(values) # the number of devices super().__init__(values) - def setValues(self, address, value): # pylint: disable=arguments-differ - """ Sets the requested values of the datastore + def setValues(self, address, value): # pylint: disable=arguments-differ + """Set the requested values of the datastore :param address: The starting address :param values: The new values to be set @@ -61,8 +60,7 @@ def setValues(self, address, value): # pylint: disable=arguments-differ def rescale_value(value): - """ Rescale the input value from the range - of 0..100 to -3200..3200. + """Rescale the input value from the range of 0..100 to -3200..3200. :param value: The input value to scale :returns: The rescaled value @@ -73,8 +71,7 @@ def rescale_value(value): def device_writer(queue): - """ A worker process that processes new messages - from a queue to write to device outputs + """Process new messages from a queue to write to device outputs :param queue: The queue to get new messages from """ @@ -93,8 +90,7 @@ def device_writer(queue): def read_device_map(path): - """ A helper method to read the device - path to address mapping from file:: + """Read the device path to address mapping from file:: 0x0001,/dev/device1 0x0002,/dev/device2 @@ -103,7 +99,7 @@ def read_device_map(path): :returns: The input mapping file """ devices = {} - with open(path, 'r') as stream: # pylint: disable=unspecified-encoding + with open(path, 'r') as stream: # pylint: disable=unspecified-encoding for line in stream: piece = line.strip().split(',') devices[int(piece[0], 16)] = piece[1] @@ -111,7 +107,7 @@ def read_device_map(path): def run_callback_server(): - """ Run callback server. """ + """Run callback server.""" # ----------------------------------------------------------------------- # # initialize your data store # ----------------------------------------------------------------------- # @@ -127,7 +123,7 @@ def run_callback_server(): identity = ModbusDeviceIdentification(info_name= { 'VendorName': 'pymodbus', 'ProductCode': 'PM', - 'VendorUrl': 'http://github.com/riptideio/pymodbus/', #NOSONAR + 'VendorUrl': 'http://github.com/riptideio/pymodbus/', # NOSONAR 'ProductName': 'pymodbus Server', 'ModelName': 'pymodbus Server', 'MajorMinorRevision': version.short(), diff --git a/examples/common/changing_framers.py b/examples/common/changing_framers.py index d13a9407c..4fad82cab 100755 --- a/examples/common/changing_framers.py +++ b/examples/common/changing_framers.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Client Framer Overload --------------------------------------------------------------------------- +"""Pymodbus Client Framer Overload. All of the modbus clients are designed to have pluggable framers so that the transport and protocol are decoupled. This allows a user @@ -42,8 +41,8 @@ # ----------------------------------------------------------------------- # rq = client.write_coil(1, True) rr = client.read_coils(1, 1) - assert not rq.isError() #nosec test that we are not an error - assert rr.bits[0] #nosec test the expected value + assert not rq.isError() # nosec test that we are not an error + assert rr.bits[0] # nosec test the expected value # ----------------------------------------------------------------------- # # close the client diff --git a/examples/common/custom_datablock.py b/examples/common/custom_datablock.py index 9dd8f41b3..d7f9ac274 100755 --- a/examples/common/custom_datablock.py +++ b/examples/common/custom_datablock.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Server With Custom Datablock Side Effect --------------------------------------------------------------------------- +"""Pymodbus Server With Custom Datablock Side Effect. This is an example of performing custom logic after a value has been written to the datastore. @@ -30,12 +29,13 @@ class CustomDataBlock(ModbusSparseDataBlock): - """ A datablock that stores the new value in memory + """A datablock that stores the new value in memory, + and performs a custom action after it has been stored. """ - def setValues(self, address, value): # pylint: disable=arguments-differ - """ Sets the requested values of the datastore + def setValues(self, address, value): # pylint: disable=arguments-differ + """Set the requested values of the datastore :param address: The starting address :param values: The new values to be set @@ -50,7 +50,7 @@ def setValues(self, address, value): # pylint: disable=arguments-differ def run_custom_db_server(): - """ Run custom db server. """ + """Run custom db server.""" # ----------------------------------------------------------------------- # # initialize your data store # ----------------------------------------------------------------------- # @@ -65,7 +65,7 @@ def run_custom_db_server(): identity = ModbusDeviceIdentification(info_name= { 'VendorName': 'pymodbus', 'ProductCode': 'PM', - 'VendorUrl': 'http://github.com/riptideio/pymodbus/', #NOSONAR + 'VendorUrl': 'http://github.com/riptideio/pymodbus/', # NOSONAR 'ProductName': 'pymodbus Server', 'ModelName': 'pymodbus Server', 'MajorMinorRevision': version.short(), diff --git a/examples/common/custom_message.py b/examples/common/custom_message.py index 5ceda0f6d..d90b9231d 100755 --- a/examples/common/custom_message.py +++ b/examples/common/custom_message.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Synchronous Client Examples --------------------------------------------------------------------------- +"""Pymodbus Synchronous Client Examples. The following is an example of how to use the synchronous modbus client implementation from pymodbus. @@ -37,16 +36,18 @@ class CustomModbusResponse(ModbusResponse): - """ Custom modbus response. """ + """Custom modbus response.""" + function_code = 55 _rtu_byte_count_pos = 2 def __init__(self, values=None, **kwargs): + """Initialize.""" ModbusResponse.__init__(self, **kwargs) self.values = values or [] def encode(self): - """ Encodes response pdu + """Encode response pdu :returns: The encoded packet message """ @@ -56,7 +57,7 @@ def encode(self): return res def decode(self, data): - """ Decodes response pdu + """Decode response pdu :param data: The packet data to decode """ @@ -67,28 +68,27 @@ def decode(self, data): class CustomModbusRequest(ModbusRequest): - """ Custom modbus request. """ + """Custom modbus request.""" function_code = 55 _rtu_frame_size = 8 def __init__(self, address=None, **kwargs): - """ Init. """ - + """Initialize.""" ModbusRequest.__init__(self, **kwargs) self.address = address self.count = 16 def encode(self): - """ Encode. """ + """Encode.""" return struct.pack('>HH', self.address, self.count) def decode(self, data): - """ Decode. """ + """Decode.""" self.address, self.count = struct.unpack('>HH', data) def execute(self, context): - """ Execute. """ + """Execute.""" if not 1 <= self.count <= 0x7d0: return self.doException(ModbusExceptions.IllegalValue) if not context.validate(self.function_code, self.address, self.count): @@ -103,10 +103,10 @@ def execute(self, context): class Read16CoilsRequest(ReadCoilsRequest): - """ Read 16 coils in one request. """ + """Read 16 coils in one request.""" def __init__(self, address, **kwargs): - """ Initializes a new instance + """Initialize a new instance :param address: The address to start reading from """ diff --git a/examples/common/custom_synchronous_server.py b/examples/common/custom_synchronous_server.py index 31e5b6e12..3eb1efd58 100755 --- a/examples/common/custom_synchronous_server.py +++ b/examples/common/custom_synchronous_server.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Synchronous Server Example with Custom functions --------------------------------------------------------------------------- +"""Pymodbus Synchronous Server Example with Custom functions. Implements a custom function code not in standard modbus function code list and its response which otherwise would throw `IllegalFunction (0x1)` error. @@ -61,7 +60,7 @@ def decode(self, data): # --------------------------------------------------------------------------- # # import the various server implementations # --------------------------------------------------------------------------- # -from custom_message import CustomModbusRequest # pylint: disable=import-error +from custom_message import CustomModbusRequest # pylint: disable=import-error from pymodbus.version import version from pymodbus.server.sync import StartTcpServer @@ -78,13 +77,13 @@ def decode(self, data): FORMAT = ('%(asctime)-15s %(threadName)-15s' ' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s') -logging.basicConfig(format=FORMAT) #NOSONAR +logging.basicConfig(format=FORMAT) # NOSONAR log = logging.getLogger() log.setLevel(logging.DEBUG) def run_server(): - """ Run server. """ + """Run server.""" store = ModbusSlaveContext( di=ModbusSequentialDataBlock(0, [17] * 100), co=ModbusSequentialDataBlock(0, [17] * 100), @@ -103,7 +102,7 @@ def run_server(): identity = ModbusDeviceIdentification(info_name= { 'VendorName': 'Pymodbus', 'ProductCode': 'PM', - 'VendorUrl': 'http://github.com/riptideio/pymodbus/', #NOSONAR + 'VendorUrl': 'http://github.com/riptideio/pymodbus/', # NOSONAR 'ProductName': 'Pymodbus Server', 'ModelName': 'Pymodbus Server', 'MajorMinorRevision': version.short(), diff --git a/examples/common/dbstore_update_server.py b/examples/common/dbstore_update_server.py index 0a0e7be07..b244c5742 100644 --- a/examples/common/dbstore_update_server.py +++ b/examples/common/dbstore_update_server.py @@ -1,5 +1,5 @@ -""" Pymodbus Server With Updating Thread --------------------------------------------------------------------------- +"""Pymodbus Server With Updating Thread. + This is an example of having a background thread updating the context in an SQLite4 database while the server is operating. @@ -43,8 +43,9 @@ def updating_writer(parm1): - """ A worker process that runs every so often and - updates live values of the context which resides in an SQLite3 database. + """Run every so often, + + and updates live values of the context which resides in an SQLite3 database. It should be noted that there is a race condition for the update. :param arguments: The input arguments to the call """ @@ -57,8 +58,8 @@ def updating_writer(parm1): # import pdb; pdb.set_trace() - rand_value = random.randint(0, 9999) #NOSONAR #nosec - rand_addr = random.randint(0, 65000) #NOSONAR #nosec + rand_value = random.randint(0, 9999) # NOSONAR #nosec + rand_addr = random.randint(0, 65000) # NOSONAR #nosec txt = f"Writing to datastore: {rand_addr}, {rand_value}" log.debug(txt) # import pdb; pdb.set_trace() @@ -70,7 +71,7 @@ def updating_writer(parm1): def run_dbstore_update_server(): - """ Run dbstore update server. """ + """Run dbstore update server.""" # ----------------------------------------------------------------------- # # initialize your data store # ----------------------------------------------------------------------- # @@ -86,7 +87,7 @@ def run_dbstore_update_server(): identity = ModbusDeviceIdentification(info_name= { 'VendorName': 'pymodbus', 'ProductCode': 'PM', - 'VendorUrl': 'http://github.com/riptideio/pymodbus/', #NOSONAR + 'VendorUrl': 'http://github.com/riptideio/pymodbus/', # NOSONAR 'ProductName': 'pymodbus Server', 'ModelName': 'pymodbus Server', 'MajorMinorRevision': version.short(), diff --git a/examples/common/modbus_logging.py b/examples/common/modbus_logging.py index a98fc7227..1bdff46d4 100755 --- a/examples/common/modbus_logging.py +++ b/examples/common/modbus_logging.py @@ -1,7 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Logging Examples --------------------------------------------------------------------------- -""" +"""Pymodbus Logging Examples.""" import logging import logging.handlers as Handlers @@ -39,4 +37,4 @@ Handlers.SysLogHandler(facility="daemon"), Handlers.DatagramHandler('localhost', 12345), ] - [log.addHandler(h) for h in handlers] # pylint: disable=expression-not-assigned + [log.addHandler(h) for h in handlers] # pylint: disable=expression-not-assigned diff --git a/examples/common/modbus_payload.py b/examples/common/modbus_payload.py index dc3d5e880..57ed026d1 100755 --- a/examples/common/modbus_payload.py +++ b/examples/common/modbus_payload.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Payload Building/Decoding Example --------------------------------------------------------------------------- +"""Pymodbus Payload Building/Decoding Example. # Run modbus_payload_server.py or synchronous_server.py to check the behavior """ @@ -18,7 +17,7 @@ FORMAT = ('%(asctime)-15s %(threadName)-15s' ' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s') -logging.basicConfig(format=FORMAT) #NOSONAR +logging.basicConfig(format=FORMAT) # NOSONAR log = logging.getLogger() log.setLevel(logging.INFO) @@ -29,7 +28,7 @@ def run_binary_payload_ex(): - """ Run binary payload. """ + """Run binary payload.""" # ----------------------------------------------------------------------- # # We are going to use a simple client to send our requests # ----------------------------------------------------------------------- # @@ -85,8 +84,8 @@ def run_binary_payload_ex(): # ----------------------------------------------------------------------- # combos = [(word_endian, byte_endian) - for word_endian in (Endian.Big, Endian.Little) - for byte_endian in (Endian.Big, Endian.Little)] + for word_endian in (Endian.Big, Endian.Little) + for byte_endian in (Endian.Big, Endian.Little)] for word_endian, byte_endian in combos: print("-" * 60) print(f"Word Order: {ORDER_DICT[word_endian]}") @@ -163,11 +162,11 @@ def run_binary_payload_ex(): byteorder=byte_endian, wordorder=word_endian) - assert decoder._byteorder == (builder._byteorder, #nosec pylint: disable=protected-access - "Make sure byteorder is consistent between BinaryPayloadBuilder and BinaryPayloadDecoder") + assert decoder._byteorder == (builder._byteorder, # nosec pylint: disable=protected-access + "Make sure byteorder is consistent between BinaryPayloadBuilder and BinaryPayloadDecoder") # noqa E501 - assert decoder._wordorder == (builder._wordorder, #nosec pylint: disable=protected-access - "Make sure wordorder is consistent between BinaryPayloadBuilder and BinaryPayloadDecoder") + assert decoder._wordorder == (builder._wordorder, # nosec pylint: disable=protected-access + "Make sure wordorder is consistent between BinaryPayloadBuilder and BinaryPayloadDecoder") # noqa E501 decoded = OrderedDict([ ('string', decoder.decode_string(len(my_string))), @@ -193,7 +192,8 @@ def run_binary_payload_ex(): print("Decoded Data") print("-" * 60) for name, value in iter(decoded.items()): - print("%s\t" % name, hex(value) if isinstance(value, int) else value) # pylint: disable=consider-using-f-string + print("%s\t" % name, hex(value) if isinstance(value, int) # pylint: disable=consider-using-f-string + else value) # ----------------------------------------------------------------------- # # close the client diff --git a/examples/common/modbus_payload_server.py b/examples/common/modbus_payload_server.py index 0c06d930e..bf28634c1 100755 --- a/examples/common/modbus_payload_server.py +++ b/examples/common/modbus_payload_server.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Server Payload Example --------------------------------------------------------------------------- +"""Pymodbus Server Payload Example. If you want to initialize a server context with a complicated memory layout, you can actually use the payload builder. @@ -24,13 +23,13 @@ # --------------------------------------------------------------------------- # FORMAT = ('%(asctime)-15s %(threadName)-15s' ' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s') -logging.basicConfig(format=FORMAT) #NOSONAR +logging.basicConfig(format=FORMAT) # NOSONAR log = logging.getLogger() log.setLevel(logging.DEBUG) def run_payload_server(): - """ Run payload server. """ + """Run payload server.""" # ----------------------------------------------------------------------- # # build your payload # ----------------------------------------------------------------------- # @@ -72,7 +71,7 @@ def run_payload_server(): identity = ModbusDeviceIdentification(info_name= { 'VendorName': 'Pymodbus', 'ProductCode': 'PM', - 'VendorUrl': 'http://github.com/riptideio/pymodbus/', #NOSONAR + 'VendorUrl': 'http://github.com/riptideio/pymodbus/', # NOSONAR 'ProductName': 'Pymodbus Server', 'ModelName': 'Pymodbus Server', 'MajorMinorRevision': version.short(), diff --git a/examples/common/performance.py b/examples/common/performance.py index 82f8c68a4..94e8bf1dc 100755 --- a/examples/common/performance.py +++ b/examples/common/performance.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Performance Example --------------------------------------------------------------------------- +"""Pymodbus Performance Example. The following is an quick performance check of the synchronous modbus client. @@ -38,9 +37,9 @@ # * cycles - the total number of requests to send # * host - the host to send the requests to # --------------------------------------------------------------------------- # -workers = 10 # pylint: disable=invalid-name -cycles = 1000 # pylint: disable=invalid-name -host = '127.0.0.1' # pylint: disable=invalid-name +workers = 10 # pylint: disable=invalid-name +cycles = 1000 # pylint: disable=invalid-name +host = '127.0.0.1' # pylint: disable=invalid-name # --------------------------------------------------------------------------- # @@ -51,8 +50,7 @@ # associated with each strategy. # --------------------------------------------------------------------------- # def single_client_test(n_host, n_cycles): - """ Performs a single threaded test of a synchronous - client against the specified host + """Perform a single threaded test of a synchronous client against the specified host :param host: The host to connect to :param cycles: The number of iterations to perform @@ -68,14 +66,14 @@ def single_client_test(n_host, n_cycles): while count < n_cycles: client.read_holding_registers(10, 123, unit=1) count += 1 - except Exception: # pylint: disable=broad-except + except Exception: # pylint: disable=broad-except logger.exception("failed to run test successfully") txt = f"finished worker: {os.getpid()}" logger.debug(txt) def multiprocessing_test(func, extras): - """ Multiprocessing test. """ + """Multiprocessing test.""" start_time = time() procs = [mWorker(target=func, args=extras) for _ in range(workers)] @@ -86,7 +84,7 @@ def multiprocessing_test(func, extras): def thread_test(func, extras): - """ Thread test. """ + """Thread test.""" start_time = time() procs = [tWorker(target=func, args=extras) for _ in range(workers)] @@ -97,7 +95,7 @@ def thread_test(func, extras): def thread_pool_exe_test(func, extras): - """ Thread pool exe. """ + """Thread pool exe.""" start_time = time() with eWorker(max_workers=workers, thread_name_prefix="Perform") as exe: futures = {exe.submit(func, *extras): job for job in range(workers)} diff --git a/examples/common/synchronous_client.py b/examples/common/synchronous_client.py index f30c4df10..5c01afe93 100755 --- a/examples/common/synchronous_client.py +++ b/examples/common/synchronous_client.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Synchronous Client Examples --------------------------------------------------------------------------- +"""Pymodbus Synchronous Client Examples. The following is an example of how to use the synchronous modbus client implementation from pymodbus. @@ -23,7 +22,7 @@ # --------------------------------------------------------------------------- # FORMAT = ('%(asctime)-15s %(threadName)-15s ' '%(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s') -logging.basicConfig(format=FORMAT) #NOSONAR +logging.basicConfig(format=FORMAT) # NOSONAR log = logging.getLogger() log.setLevel(logging.DEBUG) @@ -31,7 +30,7 @@ def run_sync_client(): - """ Run sync client. """ + """Run sync client.""" # ------------------------------------------------------------------------# # choose the client you want # ------------------------------------------------------------------------# @@ -100,15 +99,15 @@ def run_sync_client(): log.debug("Write to a Coil and read back") rq = client.write_coil(0, True, unit=UNIT) rr = client.read_coils(0, 1, unit=UNIT) - assert not rq.isError() #nosec test that we are not an error - assert not rr.isError() #nosec test that we are not an error - assert rr.bits[0] #nosec test the expected value + assert not rq.isError() # nosec test that we are not an error + assert not rr.isError() # nosec test that we are not an error + assert rr.bits[0] # nosec test the expected value log.debug("Write to multiple coils and read back- test 1") rq = client.write_coils(1, [True] * 8, unit=UNIT) rr = client.read_coils(1, 21, unit=UNIT) - assert not rq.isError() #nosec test that we are not an error - assert not rr.isError() #nosec test that we are not an error + assert not rq.isError() # nosec test that we are not an error + assert not rr.isError() # nosec test that we are not an error resp = [True] * 21 # If the returned output quantity is not a multiple of eight, @@ -116,50 +115,50 @@ def run_sync_client(): # (toward the high order end of the byte). resp.extend([False] * 3) - assert rr.bits == resp #nosec test the expected value + assert rr.bits == resp # nosec test the expected value log.debug("Write to multiple coils and read back - test 2") rq = client.write_coils(1, [False] * 8, unit=UNIT) rr = client.read_coils(1, 8, unit=UNIT) - assert not rq.isError() #nosec test that we are not an error - assert not rr.isError() #nosec test that we are not an error - assert rr.bits == [False] * 8 #nosec test the expected value + assert not rq.isError() # nosec test that we are not an error + assert not rr.isError() # nosec test that we are not an error + assert rr.bits == [False] * 8 # nosec test the expected value log.debug("Read discrete inputs") rr = client.read_discrete_inputs(0, 8, unit=UNIT) - assert not rr.isError() #nosec test that we are not an error + assert not rr.isError() # nosec test that we are not an error log.debug("Write to a holding register and read back") rq = client.write_register(1, 10, unit=UNIT) rr = client.read_holding_registers(1, 1, unit=UNIT) - assert not rq.isError() #nosec test that we are not an error - assert not rr.isError() #nosec test that we are not an error - assert rr.registers[0] == 10 #nosec test the expected value + assert not rq.isError() # nosec test that we are not an error + assert not rr.isError() # nosec test that we are not an error + assert rr.registers[0] == 10 # nosec test the expected value log.debug("Write to multiple holding registers and read back") rq = client.write_registers(1, [10] * 8, unit=UNIT) rr = client.read_holding_registers(1, 8, unit=UNIT) - assert not rq.isError() #nosec test that we are not an error - assert not rr.isError() #nosec test that we are not an error - assert rr.registers == [10] * 8 #nosec test the expected value + assert not rq.isError() # nosec test that we are not an error + assert not rr.isError() # nosec test that we are not an error + assert rr.registers == [10] * 8 # nosec test the expected value log.debug("Read input registers") rr = client.read_input_registers(1, 8, unit=UNIT) - assert not rr.isError() #nosec test that we are not an error + assert not rr.isError() # nosec test that we are not an error arguments = { - 'read_address': 1, # noqa E221 - 'read_count': 8, # noqa E221 - 'write_address': 1, # noqa E221 + 'read_address': 1, # noqa E221 + 'read_count': 8, # noqa E221 + 'write_address': 1, # noqa E221 'write_registers': [20] * 8, } log.debug("Read write registers simultaneously") rq = client.readwrite_registers(unit=UNIT, **arguments) rr = client.read_holding_registers(1, 8, unit=UNIT) - assert not rq.isError() #nosec test that we are not an error - assert not rr.isError() #nosec test that we are not an error - assert rq.registers == [20] * 8 #nosec test the expected value - assert rr.registers == [20] * 8 #nosec test the expected value + assert not rq.isError() # nosec test that we are not an error + assert not rr.isError() # nosec test that we are not an error + assert rq.registers == [20] * 8 # nosec test the expected value + assert rr.registers == [20] * 8 # nosec test the expected value # ----------------------------------------------------------------------- # # close the client diff --git a/examples/common/synchronous_client_ext.py b/examples/common/synchronous_client_ext.py index 59488f260..e4aae413d 100755 --- a/examples/common/synchronous_client_ext.py +++ b/examples/common/synchronous_client_ext.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Synchronous Client Extended Examples --------------------------------------------------------------------------- +"""Pymodbus Synchronous Client Extended Examples. The following is an example of how to use the synchronous modbus client implementation from pymodbus to perform the extended portions of the @@ -46,7 +45,7 @@ # --------------------------------------------------------------------------- # FORMAT = ('%(asctime)-15s %(threadName)-15s ' '%(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s') -logging.basicConfig(format=FORMAT) #NOSONAR +logging.basicConfig(format=FORMAT) # NOSONAR log = logging.getLogger() log.setLevel(logging.DEBUG) @@ -54,7 +53,7 @@ def execute_extended_requests(): - """ Execute extended requests. """ + """Execute extended requests.""" # ------------------------------------------------------------------------# # choose the client you want # ------------------------------------------------------------------------# diff --git a/examples/common/synchronous_server.py b/examples/common/synchronous_server.py index c0efed263..32d094611 100755 --- a/examples/common/synchronous_server.py +++ b/examples/common/synchronous_server.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Synchronous Server Example --------------------------------------------------------------------------- +"""Pymodbus Synchronous Server Example. The synchronous server is implemented in pure python without any third party libraries (unless you need to use the serial protocols which require @@ -27,13 +26,13 @@ # --------------------------------------------------------------------------- # FORMAT = ('%(asctime)-15s %(threadName)-15s' ' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s') -logging.basicConfig(format=FORMAT) #NOSONAR +logging.basicConfig(format=FORMAT) # NOSONAR log = logging.getLogger() log.setLevel(logging.DEBUG) def run_server(): - """ Run server. """ + """Run server.""" # ----------------------------------------------------------------------- # # initialize your data store # ----------------------------------------------------------------------- # @@ -104,7 +103,7 @@ def run_server(): ModbusDeviceIdentification(info_name= { 'VendorName': 'Pymodbus', 'ProductCode': 'PM', - 'VendorUrl': 'http://github.com/riptideio/pymodbus/', #NOSONAR + 'VendorUrl': 'http://github.com/riptideio/pymodbus/', # NOSONAR 'ProductName': 'Pymodbus Server', 'ModelName': 'Pymodbus Server', 'MajorMinorRevision': version.short(), diff --git a/examples/common/updating_server.py b/examples/common/updating_server.py index 8981c76fc..bf1f0b40e 100755 --- a/examples/common/updating_server.py +++ b/examples/common/updating_server.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Server With Updating Thread +"""Pymodbus Server With Updating Thread. This is an example of having a background thread updating the context while the server is operating. This can also be done with @@ -38,8 +38,9 @@ def updating_writer(extra): - """ A worker process that runs every so often and - updates live values of the context. It should be noted + """Run every so often, + + and updates live values of the context. It should be noted that there is a race condition for the update. :param arguments: The input arguments to the call @@ -57,7 +58,7 @@ def updating_writer(extra): def run_updating_server(): - """ Run updating server. """ + """Run updating server.""" # ----------------------------------------------------------------------- # # initialize your data store # ----------------------------------------------------------------------- # @@ -75,7 +76,7 @@ def run_updating_server(): identity = ModbusDeviceIdentification(info_name= { 'VendorName': 'pymodbus', 'ProductCode': 'PM', - 'VendorUrl': 'http://github.com/riptideio/pymodbus/', #NOSONAR + 'VendorUrl': 'http://github.com/riptideio/pymodbus/', # NOSONAR 'ProductName': 'pymodbus Server', 'ModelName': 'pymodbus Server', 'MajorMinorRevision': version.short(), diff --git a/examples/contrib/asynchronous_asyncio_modbus_tls_client.py b/examples/contrib/asynchronous_asyncio_modbus_tls_client.py index 62050366c..b8e391eda 100755 --- a/examples/contrib/asynchronous_asyncio_modbus_tls_client.py +++ b/examples/contrib/asynchronous_asyncio_modbus_tls_client.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -"""Simple Asynchronous Modbus TCP over TLS client ---------------------------------------------------------------------------- +"""Simple Asynchronous Modbus TCP over TLS client. This is a simple example of writing a asynchronous modbus TCP over TLS client that uses Python builtin module ssl - TLS/SSL wrapper for socket objects for @@ -26,7 +25,7 @@ async def start_async_test(client): - """ Start async test. """ + """Start async test.""" result = await client.read_coils(1, 8) print(result.bits) await client.write_coils(1, [False] * 3) @@ -37,7 +36,8 @@ async def start_async_test(client): # ----------------------------------------------------------------------- # # pass SSLContext which is the context here to ModbusTcpClient() # ----------------------------------------------------------------------- # - loop, new_client = AsyncModbusTLSClient(ASYNC_IO, 'test.host.com', 8020, #NOSONAR pylint: disable=unpacking-non-sequence - sslctx=sslctx) + loop, new_client = AsyncModbusTLSClient(ASYNC_IO, # NOSONAR pylint: disable=unpacking-non-sequence + 'test.host.com', 8020, # NOSONAR + sslctx=sslctx) loop.run_until_complete(start_async_test(new_client.protocol)) loop.close() diff --git a/examples/contrib/asynchronous_asyncio_serial_client.py b/examples/contrib/asynchronous_asyncio_serial_client.py index a082fbaef..0db06770a 100755 --- a/examples/contrib/asynchronous_asyncio_serial_client.py +++ b/examples/contrib/asynchronous_asyncio_serial_client.py @@ -1,4 +1,4 @@ -""" Async serial client. """ +"""Async serial client.""" import logging import asyncio from serial_asyncio import create_serial_connection @@ -18,7 +18,7 @@ async def start_async_test(client): - """ Start async test. """ + """Start async test.""" # ----------------------------------------------------------------------- # # specify slave to query # ----------------------------------------------------------------------- # @@ -44,62 +44,62 @@ async def start_async_test(client): log.debug("Write to a Coil and read back") rq = await client.write_coil(0, True, unit=UNIT) rr = await client.read_coils(0, 1, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error - assert rr.bits[0] #nosec test the expected value + assert rq.function_code < 0x80 # nosec test that we are not an error + assert rr.bits[0] # nosec test the expected value log.debug("Write to multiple coils and read back- test 1") rq = await client.write_coils(1, [True] * 8, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error + assert rq.function_code < 0x80 # nosec test that we are not an error rr = await client.read_coils(1, 21, unit=UNIT) - assert rr.function_code < 0x80 #nosec test that we are not an error + assert rr.function_code < 0x80 # nosec test that we are not an error resp = [True] * 21 resp.extend([False] * 3) - assert rr.bits == resp #nosec test the expected value + assert rr.bits == resp # nosec test the expected value rq = await client.write_coils(1, [False] * 8, unit=UNIT) rr = await client.read_coils(1, 8, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error - assert rr.bits == [False] * 8 #nosec test the expected value + assert rq.function_code < 0x80 # nosec test that we are not an error + assert rr.bits == [False] * 8 # nosec test the expected value rr = await client.read_discrete_inputs(0, 8, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error + assert rq.function_code < 0x80 # nosec test that we are not an error rq = await client.write_register(1, 10, unit=UNIT) rr = await client.read_holding_registers(1, 1, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error - assert rr.registers[0] == 10 #nosec test the expected value + assert rq.function_code < 0x80 # nosec test that we are not an error + assert rr.registers[0] == 10 # nosec test the expected value rq = await client.write_registers(1, [10] * 8, unit=UNIT) rr = await client.read_holding_registers(1, 8, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error - assert rr.registers == [10] * 8 #nosec test the expected value + assert rq.function_code < 0x80 # nosec test that we are not an error + assert rr.registers == [10] * 8 # nosec test the expected value rr = await client.read_input_registers(1, 8, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error + assert rq.function_code < 0x80 # nosec test that we are not an error arguments = { - 'read_address': 1, # noqa E221 - 'read_count': 8, # noqa E221 - 'write_address': 1, # noqa E221 + 'read_address': 1, # noqa E221 + 'read_count': 8, # noqa E221 + 'write_address': 1, # noqa E221 'write_registers': [20] * 8, } rq = await client.readwrite_registers(unit=UNIT, **arguments) rr = await client.read_holding_registers(1, 8, unit=UNIT) - assert rq.function_code < 0x80 #nosec test that we are not an error - assert rq.registers == [20] * 8 #nosec test the expected value - assert rr.registers == [20] * 8 #nosec test the expected value + assert rq.function_code < 0x80 # nosec test that we are not an error + assert rq.registers == [20] * 8 # nosec test the expected value + assert rr.registers == [20] * 8 # nosec test the expected value # create_serial_connection doesn't allow to pass arguments # to protocol so that this is kind of workaround def make_protocol(): - """ Make protocol. """ + """Make protocol.""" return ModbusClientProtocol(framer=ModbusRtuFramer(ClientDecoder())) if __name__ == '__main__': loop = asyncio.get_event_loop() - coro = create_serial_connection(loop, make_protocol, '/tmp/ttyp0', # nosec NOSONAR + coro = create_serial_connection(loop, make_protocol, '/tmp/ttyp0', # nosec NOSONAR baudrate=9600) transport, protocol = loop.run_until_complete(asyncio.gather(coro))[0] loop.run_until_complete(start_async_test(protocol)) diff --git a/examples/contrib/bcd_payload.py b/examples/contrib/bcd_payload.py index 67e7ac016..7c937aa07 100644 --- a/examples/contrib/bcd_payload.py +++ b/examples/contrib/bcd_payload.py @@ -1,5 +1,4 @@ -""" Modbus BCD Payload Builder ------------------------------------------------------------ +"""Modbus BCD Payload Builder. This is an example of building a custom payload builder that can be used in the pymodbus library. Below is a @@ -15,7 +14,7 @@ def convert_to_bcd(decimal): - """ Converts a decimal value to a bcd value + """Convert a decimal value to a bcd value :param value: The decimal value to to pack into bcd :returns: The number in bcd form @@ -30,7 +29,7 @@ def convert_to_bcd(decimal): def convert_from_bcd(bcd): - """ Converts a bcd value to a decimal value + """Convert a bcd value to a decimal value :param value: The value to unpack from bcd :returns: The number in decimal form @@ -45,7 +44,7 @@ def convert_from_bcd(bcd): def count_bcd_digits(bcd): - """ Count the number of digits in a bcd value + """Count the number of digits in a bcd value :param bcd: The bcd number to count the digits of :returns: The number of digits in the bcd string @@ -58,8 +57,9 @@ def count_bcd_digits(bcd): class BcdPayloadBuilder(IPayloadBuilder): - """ A utility that helps build binary coded decimal payload - messages to be written with the various modbus messages. + """A utility that helps build binary coded decimal payload messages + + to be written with the various modbus messages. example:: builder = BcdPayloadBuilder() @@ -69,7 +69,7 @@ class BcdPayloadBuilder(IPayloadBuilder): """ def __init__(self, payload=None, endian=Endian.Little): - """ Initialize a new instance of the payload builder + """Initialize a new instance of the payload builder :param payload: Raw payload data to initialize with :param endian: The endianness of the payload @@ -78,19 +78,18 @@ def __init__(self, payload=None, endian=Endian.Little): self._payload = payload or [] def __str__(self): - """ Return the payload buffer as a string + """Return the payload buffer as a string :returns: The payload buffer as a string """ return ''.join(self._payload) def reset(self): - """ Reset the payload buffer - """ + """Reset the payload buffer""" self._payload = [] def build(self): - """ Return the payload buffer as a list + """Return the payload buffer as a list This list is two bytes per element and can thus be treated as a list of registers. @@ -103,7 +102,7 @@ def build(self): return [string[i:i + 2] for i in range(0, length, 2)] def add_bits(self, values): - """ Adds a collection of bits to be encoded + """Add a collection of bits to be encoded If these are less than a multiple of eight, they will be left padded with 0 bits to make @@ -115,7 +114,7 @@ def add_bits(self, values): self._payload.append(value) def add_number(self, value, size=None): - """ Adds any 8bit numeric type to the buffer + """Add any 8bit numeric type to the buffer :param value: The value to add to the buffer """ @@ -130,7 +129,7 @@ def add_number(self, value, size=None): self._payload.extend(encoded) def add_string(self, value): - """ Adds a string to the buffer + """Add a string to the buffer :param value: The value to add to the buffer """ @@ -138,9 +137,9 @@ def add_string(self, value): class BcdPayloadDecoder: - """ A utility that helps decode binary coded decimal payload - messages from a modbus response message. What follows is - a simple example:: + """A utility that helps decode binary coded decimal payload messages from a modbus response message. + + What follows is a simple example:: decoder = BcdPayloadDecoder(payload) first = decoder.decode_int(2) @@ -148,7 +147,7 @@ class BcdPayloadDecoder: """ def __init__(self, payload): - """ Initialize a new payload decoder + """Initialize a new payload decoder :param payload: The payload to decode with """ @@ -156,9 +155,10 @@ def __init__(self, payload): self._pointer = 0x00 @staticmethod - def fromRegisters(registers, endian=Endian.Little): # pylint: disable=invalid-name - """ Initialize a payload decoder with the result of - reading a collection of registers from a modbus device. + def fromRegisters(registers, endian=Endian.Little): # pylint: disable=invalid-name + """Initialize a payload decoder + + with the result of reading a collection of registers from a modbus device. The registers are treated as a list of 2 byte values. We have to do this because of how the data has already @@ -174,9 +174,10 @@ def fromRegisters(registers, endian=Endian.Little): # pylint: disable=invalid-na raise ParameterException('Invalid collection of registers supplied') @staticmethod - def fromCoils(coils, endian=Endian.Little): # pylint: disable=invalid-name - """ Initialize a payload decoder with the result of - reading a collection of coils from a modbus device. + def fromCoils(coils, endian=Endian.Little): # pylint: disable=invalid-name + """Initialize a payload decoder. + + with the result of reading a collection of coils from a modbus device. The coils are treated as a list of bit(boolean) values. @@ -190,26 +191,23 @@ def fromCoils(coils, endian=Endian.Little): # pylint: disable=invalid-name raise ParameterException('Invalid collection of coils supplied') def reset(self): - """ Reset the decoder pointer back to the start - """ + """Reset the decoder pointer back to the start""" self._pointer = 0x00 def decode_int(self, size=1): - """ Decodes a int or long from the buffer - """ + """Decode a int or long from the buffer""" self._pointer += size handle = self._payload[self._pointer - size:self._pointer] return convert_from_bcd(handle) def decode_bits(self): - """ Decodes a byte worth of bits from the buffer - """ + """Decode a byte worth of bits from the buffer""" self._pointer += 1 handle = self._payload[self._pointer - 1:self._pointer] return unpack_bitstring(handle) def decode_string(self, size=1): - """ Decodes a string from the buffer + """Decode a string from the buffer :param size: The size of the string to decode """ diff --git a/examples/contrib/concurrent_client.py b/examples/contrib/concurrent_client.py index cd7321434..2ab46b627 100755 --- a/examples/contrib/concurrent_client.py +++ b/examples/contrib/concurrent_client.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Concurrent Modbus Client ---------------------------------------------------------------------------- +"""Concurrent Modbus Client. This is an example of writing a high performance modbus client that allows a high level of concurrency by using worker threads/processes to handle @@ -29,15 +28,16 @@ # -------------------------------------------------------------------------- # log = logging.getLogger("pymodbus") log.setLevel(logging.DEBUG) -logging.basicConfig() # NOSONAR +logging.basicConfig() # NOSONAR # -------------------------------------------------------------------------- # # Initialize out concurrency primitives # -------------------------------------------------------------------------- # -class _Primitives: # pylint: disable=too-few-public-methods) - """ This is a helper class used to group the - threading primitives depending on the type of +class _Primitives: # pylint: disable=too-few-public-methods) + """This is a helper class. + + used to group the threading primitives depending on the type of worker situation we want to run (threads or processes). """ @@ -48,8 +48,7 @@ def __init__(self, **kwargs): @classmethod def create(cls, in_process=False): - """ Initialize a new instance of the concurrency - primitives. + """Initialize a new instance of the concurrency primitives. :param in_process: True for threaded, False for processes :returns: An initialized instance of concurrency primitives @@ -66,7 +65,7 @@ def create(cls, in_process=False): # We use named tuples here as they are very lightweight while giving us # all the benefits of classes. # -------------------------------------------------------------------------- # -WorkRequest = namedtuple('WorkRequest', 'request, work_id') # noqa 241 +WorkRequest = namedtuple('WorkRequest', 'request, work_id') # noqa 241 WorkResponse = namedtuple('WorkResponse', 'is_exception, work_id, response') @@ -74,7 +73,9 @@ def create(cls, in_process=False): # Define our worker processes # -------------------------------------------------------------------------- # def _client_worker_process(factory, input_queue, output_queue, is_shutdown): - """ This worker process takes input requests, issues them on its + """Take input requests, + + issues them on its client handle, and then sends the client response (success or failure) to the manager to deliver back to the application. @@ -98,19 +99,21 @@ def _client_worker_process(factory, input_queue, output_queue, is_shutdown): log.debug("executing request on thread: %s", workitem) result = my_client.execute(workitem.request) output_queue.put(WorkResponse(False, workitem.work_id, result)) - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except txt = f"error in worker thread: {threading.current_thread()}" log.exception(txt) output_queue.put(WorkResponse(True, workitem.work_id, exc)) - except Exception: #nosec pylint: disable=broad-except + except Exception: # nosec pylint: disable=broad-except pass log.info("request worker shutting down: %s", threading.current_thread()) def _manager_worker_process(output_queue, my_futures, is_shutdown): - """ This worker process manages taking output responses and - tying them back to the future keyed on the initial transaction id. + """Take output responses and tying them back to the future. + + keyed on the initial transaction id. + Basically this can be thought of as the delivery worker. It should be noted that there are one of these threads and it must @@ -136,7 +139,7 @@ def _manager_worker_process(output_queue, my_futures, is_shutdown): txt = f"updated future result: {my_future}" log.debug(txt) del futures[workitem.work_id] - except Exception: # pylint: disable=broad-except + except Exception: # pylint: disable=broad-except log.exception("error in manager") txt = f"manager worker shutting down: {threading.current_thread()}" log.info(txt) @@ -146,15 +149,15 @@ def _manager_worker_process(output_queue, my_futures, is_shutdown): # Define our concurrent client # -------------------------------------------------------------------------- # class ConcurrentClient(ModbusClientMixin): - """ This is a high performance client that can be used - to read/write a large number of requests at once asynchronously. + """This is a high performance client. + + that can be used to read/write a large number of requests at once asynchronously. This operates with a backing worker pool of processes or threads to achieve its performance. """ def __init__(self, **kwargs): - """ Initialize a new instance of the client - """ + """Initialize a new instance of the client.""" worker_count = kwargs.get('count', multiprocessing.cpu_count()) self.factory = kwargs.get('factory') primitives = _Primitives.create(kwargs.get('in_process', False)) @@ -174,7 +177,7 @@ def __init__(self, **kwargs): self.workers.append(self.manager) # creating the request workers - for i in range(worker_count): #NOSONAR + for i in range(worker_count): # NOSONAR worker = primitives.worker( target=_client_worker_process, args=(self.factory, self.input_queue, self.output_queue, @@ -184,9 +187,7 @@ def __init__(self, **kwargs): self.workers.append(worker) def shutdown(self): - """ Shutdown all the workers being used to - concurrently process the requests. - """ + """Shutdown all the workersbeing used to concurrently process the requests.""" log.info("stating to shut down workers") self.is_shutdown.set() # to wake up the manager @@ -196,7 +197,9 @@ def shutdown(self): log.info("finished shutting down workers") def execute(self, request): - """ Given a request, enqueue it to be processed + """Given a request- + + enqueue it to be processed and then return a future linked to the response of the call. @@ -209,8 +212,9 @@ def execute(self, request): return fut def execute_silently(self, request): - """ Given a write request, enqueue it to - be processed without worrying about calling the + """Given a write request. + + enqueue it to be processed without worrying about calling the application back (fire and forget) :param request: The request to execute @@ -222,7 +226,7 @@ def execute_silently(self, request): from pymodbus.client.sync import ModbusTcpClient def client_factory(): - """ Client factory. """ + """Client factory.""" log.debug("creating client for: %s", threading.current_thread()) my_client = ModbusTcpClient('127.0.0.1', port=5020) my_client.connect() diff --git a/examples/contrib/deviceinfo_showcase_client.py b/examples/contrib/deviceinfo_showcase_client.py index 926763a3a..c4c6d082d 100755 --- a/examples/contrib/deviceinfo_showcase_client.py +++ b/examples/contrib/deviceinfo_showcase_client.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Synchronous Client Example to showcase Device Information --------------------------------------------------------------------------- +"""Pymodbus Synchronous Client Example to showcase Device Information. This client demonstrates the use of Device Information to get information about servers connected to the client. This is part of the MODBUS specification, @@ -25,7 +24,7 @@ # --------------------------------------------------------------------------- # FORMAT = ('%(asctime)-15s %(threadName)-15s ' '%(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s') -logging.basicConfig(format=FORMAT) #NOSONAR +logging.basicConfig(format=FORMAT) # NOSONAR log = logging.getLogger() log.setLevel(logging.DEBUG) @@ -33,7 +32,7 @@ def run_sync_client(): - """ Run sync client. """ + """Run sync client.""" # ------------------------------------------------------------------------# # choose the client you want # ------------------------------------------------------------------------# @@ -90,7 +89,7 @@ def run_sync_client(): log.debug(rr) print("Device Information : ") - for key in information.keys(): # pylint: disable=consider-iterating-dictionary,consider-using-dict-items + for key in information.keys(): # pylint: disable=consider-iterating-dictionary,consider-using-dict-items print(key, information[key]) # ----------------------------------------------------------------------- # diff --git a/examples/contrib/deviceinfo_showcase_server.py b/examples/contrib/deviceinfo_showcase_server.py index 47915d688..a0bbcb543 100755 --- a/examples/contrib/deviceinfo_showcase_server.py +++ b/examples/contrib/deviceinfo_showcase_server.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Synchronous Server Example to showcase Device Information --------------------------------------------------------------------------- +"""Pymodbus Synchronous Server Example to showcase Device Information. This server demonstrates the use of Device Information to provide information to clients about the device. This is part of the MODBUS specification, and @@ -26,13 +25,13 @@ # --------------------------------------------------------------------------- # FORMAT = ('%(asctime)-15s %(threadName)-15s' ' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s') -logging.basicConfig(format=FORMAT) #NOSONAR +logging.basicConfig(format=FORMAT) # NOSONAR log = logging.getLogger() log.setLevel(logging.DEBUG) def run_server(): - """ Run server. """ + """Run server.""" # ----------------------------------------------------------------------- # # initialize your data store # ----------------------------------------------------------------------- # @@ -47,7 +46,7 @@ def run_server(): identity = ModbusDeviceIdentification(info_name= { 'VendorName': 'Pymodbus', 'ProductCode': 'PM', - 'VendorUrl': 'http://github.com/riptideio/pymodbus/', #NOSONAR + 'VendorUrl': 'http://github.com/riptideio/pymodbus/', # NOSONAR 'ProductName': 'Pymodbus Server', 'ModelName': 'Pymodbus Server', 'MajorMinorRevision': version.short(), diff --git a/examples/contrib/libmodbus_client.py b/examples/contrib/libmodbus_client.py index 6f8d8aa90..ef646274e 100755 --- a/examples/contrib/libmodbus_client.py +++ b/examples/contrib/libmodbus_client.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Libmodbus Protocol Wrapper ------------------------------------------------------------- +"""Libmodbus Protocol Wrapper. What follows is an example wrapper of the libmodbus library (http://libmodbus.org/documentation/) for use with pymodbus. @@ -107,27 +106,27 @@ def get_float(data): - """ Get float. """ + """Get float.""" return LIB.modbus_get_float(data) def set_float(value, data): - """ Set float. """ + """Set float.""" LIB.modbus_set_float(value, data) def cast_to_int16(data): - """ Cast to int16. """ + """Cast to int16.""" return int(compiler.cast('int16_t', data)) def cast_to_int32(data): - """ Cast to int32. """ + """Cast to int32.""" return int(compiler.cast('int32_t', data)) class NotImplementedException(Exception): - """ Not implemented exception. """ + """Not implemented exception.""" # -------------------------------------------------------------------------- # @@ -136,44 +135,46 @@ class NotImplementedException(Exception): class LibmodbusLevel1Client: - """ A raw wrapper around the libmodbus c library. Feel free - to use it if you want increased performance and don't mind the + """A raw wrapper around the libmodbus c library. + + Feel free to use it if you want increased performance and don't mind the entire protocol not being implemented. """ @classmethod def create_tcp_client(cls, my_host='127.0.0.1', my_port=Defaults.Port): - """ Create a TCP modbus client for the supplied parameters. + """Create a TCP modbus client for the supplied parameters. - :param host: The host to connect to - :param port: The port to connect to on that host - :returns: A new level1 client + :param host: The host to connect to + :param port: The port to connect to on that host + :returns: A new level1 client """ my_client = LIB.modbus_new_tcp(my_host.encode(), my_port) return cls(my_client) @classmethod def create_rtu_client(cls, **kwargs): - """ Create a TCP modbus client for the supplied parameters. - - :param port: The serial port to attach to - :param stopbits: The number of stop bits to use - :param bytesize: The bytesize of the serial messages - :param parity: Which kind of parity to use - :param baudrate: The baud rate to use for the serial device - :returns: A new level1 client + """Create a TCP modbus client for the supplied parameters. + + :param port: The serial port to attach to + :param stopbits: The number of stop bits to use + :param bytesize: The bytesize of the serial messages + :param parity: Which kind of parity to use + :param baudrate: The baud rate to use for the serial device + :returns: A new level1 client """ - my_port = kwargs.get('port', '/dev/ttyS0') # noqa E221 + my_port = kwargs.get('port', '/dev/ttyS0') # noqa E221 baudrate = kwargs.get('baud', Defaults.Baudrate) - parity = kwargs.get('parity', Defaults.Parity) # noqa E221 + parity = kwargs.get('parity', Defaults.Parity) # noqa E221 bytesize = kwargs.get('bytesize', Defaults.Bytesize) stopbits = kwargs.get('stopbits', Defaults.Stopbits) my_client = LIB.modbus_new_rtu(my_port, baudrate, parity, bytesize, stopbits) return cls(my_client) def __init__(self, my_client): - """ Initialize a new instance of the LibmodbusLevel1Client. This - method should not be used, instead new instances should be created + """Initialize a new instance of the LibmodbusLevel1Client. + + This method should not be used, instead new instances should be created using the two supplied factory methods: * LibmodbusLevel1Client.create_rtu_client(...) @@ -185,31 +186,30 @@ def __init__(self, my_client): self.slave = Defaults.UnitId def set_slave(self, slave): - """ Set the current slave to operate against. + """Set the current slave to operate against. :param slave: The new slave to operate against :returns: The resulting slave to operate against """ - self.slave = self._execute(LIB.modbus_set_slave, slave) # pylint: disable=no-member + self.slave = self._execute(LIB.modbus_set_slave, slave) # pylint: disable=no-member return self.slave def connect(self): - """ Attempt to connect to the client target. + """Attempt to connect to the client target. :returns: True if successful, throws otherwise """ return not self.__execute(LIB.modbus_connect) def flush(self): - """ Discards the existing bytes on the wire. + """Discard the existing bytes on the wire. :returns: The number of flushed bytes, or throws """ return self.__execute(LIB.modbus_flush) def close(self): - """ Closes and frees the underlying connection - and context structure. + """Close and frees the underlying connection and context structure. :returns: Always True """ @@ -218,9 +218,9 @@ def close(self): return True def __execute(self, command, *args): - """ Run the supplied command against the currently - instantiated client with the supplied arguments. This - will make sure to correctly handle resulting errors. + """Run the supplied command against the currently instantiated client with the supplied arguments. + + This will make sure to correctly handle resulting errors. :param command: The command to execute against the context :param *args: The arguments for the given command @@ -232,7 +232,7 @@ def __execute(self, command, *args): return result def read_bits(self, address, count=1): - """ Read bits. + """Read bits. :param address: The starting address to read from :param count: The number of coils to read @@ -243,7 +243,7 @@ def read_bits(self, address, count=1): return result def read_input_bits(self, address, count=1): - """ Read input bits. + """Read input bits. :param address: The starting address to read from :param count: The number of discretes to read @@ -254,7 +254,7 @@ def read_input_bits(self, address, count=1): return result def write_bit(self, address, value): - """ Write bit. + """Write bit. :param address: The starting address to write to :param value: The value to write to the specified address @@ -263,7 +263,7 @@ def write_bit(self, address, value): return self.__execute(LIB.modbus_write_bit, address, value) def write_bits(self, address, values): - """ Write bits. + """Write bits. :param address: The starting address to write to :param values: The values to write to the specified address @@ -273,7 +273,7 @@ def write_bits(self, address, values): return self.__execute(LIB.modbus_write_bits, address, count, values) def write_register(self, address, value): - """ Write register. + """Write register. :param address: The starting address to write to :param value: The value to write to the specified address @@ -282,7 +282,7 @@ def write_register(self, address, value): return self.__execute(LIB.modbus_write_register, address, value) def write_registers(self, address, values): - """ Write registers. + """Write registers. :param address: The starting address to write to :param values: The values to write to the specified address @@ -292,7 +292,7 @@ def write_registers(self, address, values): return self.__execute(LIB.modbus_write_registers, address, count, values) def read_registers(self, address, count=1): - """ Read registers. + """Read registers. :param address: The starting address to read from :param count: The number of registers to read @@ -303,7 +303,7 @@ def read_registers(self, address, count=1): return result def read_input_registers(self, address, count=1): - """ Read input registers. + """Read input registers. :param address: The starting address to read from :param count: The number of registers to read @@ -314,7 +314,7 @@ def read_input_registers(self, address, count=1): return result def read_and_write_registers(self, read_address, read_count, write_address, write_registers): - """ Read/write registers. + """Read/write registers. :param read_address: The address to start reading from :param read_count: The number of registers to read from address @@ -335,9 +335,9 @@ def read_and_write_registers(self, read_address, read_count, write_address, writ class LibmodbusClient(ModbusClientMixin): - """ A facade around the raw level 1 libmodbus client - that implements the pymodbus protocol on top of the lower level - client. + """A facade around the raw level 1 libmodbus client. + + that implements the pymodbus protocol on top of the lower level client. """ # ----------------------------------------------------------------------- # @@ -395,8 +395,9 @@ class LibmodbusClient(ModbusClientMixin): } def __init__(self, my_client): - """ Initialize a new instance of the LibmodbusClient. This should - be initialized with one of the LibmodbusLevel1Client instances: + """Initialize a new instance of the LibmodbusClient. + + This should be initialized with one of the LibmodbusLevel1Client instances: * LibmodbusLevel1Client.create_rtu_client(...) * LibmodbusLevel1Client.create_tcp_client(...) @@ -411,7 +412,7 @@ def __init__(self, my_client): # ----------------------------------------------------------------------- # def execute(self, request): - """ Execute the supplied request against the server. + """Execute the supplied request against the server. :param request: The request to process :returns: The result of the request execution @@ -435,11 +436,11 @@ def execute(self, request): # ----------------------------------------------------------------------- # def connect(self): - """ Connect. """ + """Connect.""" return self.client.connect() def close(self): - """ Close. """ + """Close.""" return self.client.close() # ----------------------------------------------------------------------- # @@ -447,7 +448,7 @@ def close(self): # ----------------------------------------------------------------------- # def __enter__(self): - """ Implement the client with enter block + """Implement the client with enter block :returns: The current instance of the client """ @@ -455,7 +456,7 @@ def __enter__(self): return self def __exit__(self, klass, value, traceback): - """ Implement the client with exit block """ + """Implement the client with exit block""" self.client.close() # -------------------------------------------------------------------------- # @@ -466,8 +467,8 @@ def __exit__(self, klass, value, traceback): if __name__ == '__main__': # create our low level client - host = '127.0.0.1' # pylint: disable=invalid-name - port = 502 # pylint: disable=invalid-name + host = '127.0.0.1' # pylint: disable=invalid-name + port = 502 # pylint: disable=invalid-name protocol = LibmodbusLevel1Client.create_tcp_client(host, port) # operate with our high level client diff --git a/examples/contrib/message_generator.py b/examples/contrib/message_generator.py index 1d22511b4..439366640 100755 --- a/examples/contrib/message_generator.py +++ b/examples/contrib/message_generator.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Modbus Message Generator --------------------------------------------------------------------------- +"""Modbus Message Generator. The following is an example of how to generate example encoded messages for the supplied modbus format: @@ -11,7 +10,7 @@ * binary - `./generate-messages.py -f binary -m tx -b` """ import logging -from optparse import OptionParser # pylint: disable=deprecated-module +from optparse import OptionParser # pylint: disable=deprecated-module import codecs as c # -------------------------------------------------------------------------- # # import all the available framers @@ -194,7 +193,7 @@ # generate all the requested messages # -------------------------------------------------------------------------- # def generate_messages(framer, options): - """ A helper method to parse the command line options + """Parse the command line options :param framer: The framer to encode the messages with :param options: The message options to use @@ -205,18 +204,18 @@ def generate_messages(framer, options): messages = _response_messages for message in messages: message = message(**_arguments) - print("%-44s = " % message.__class__.__name__) # pylint: disable=consider-using-f-string + print("%-44s = " % message.__class__.__name__) # pylint: disable=consider-using-f-string packet = framer.buildPacket(message) if not options.ascii: packet = c.encode(packet, 'hex_codec').decode('utf-8') - print (f"{packet}\n") # because ascii ends with a \r\n + print(f"{packet}\n") # because ascii ends with a \r\n # -------------------------------------------------------------------------- # # initialize our program settings # -------------------------------------------------------------------------- # def get_options(): - """ A helper method to parse the command line options + """Parse the command line options :returns: The options manager """ @@ -248,21 +247,20 @@ def get_options(): def main(): - """ The main runner function - """ + """Run main runner function""" option = get_options() if option.debug: try: modbus_log.setLevel(logging.DEBUG) - except Exception: # pylint: disable=broad-except + except Exception: # pylint: disable=broad-except print("Logging is not supported on this system") framer = { - 'tcp': ModbusSocketFramer, # noqa E221 - 'rtu': ModbusRtuFramer, # noqa E221 + 'tcp': ModbusSocketFramer, # noqa E221 + 'rtu': ModbusRtuFramer, # noqa E221 'binary': ModbusBinaryFramer, - 'ascii': ModbusAsciiFramer, # noqa E221 + 'ascii': ModbusAsciiFramer, # noqa E221 }.get(option.framer, ModbusSocketFramer)(None) generate_messages(framer, option) diff --git a/examples/contrib/message_parser.py b/examples/contrib/message_parser.py index da5187571..6978e2c82 100755 --- a/examples/contrib/message_parser.py +++ b/examples/contrib/message_parser.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Modbus Message Parser --------------------------------------------------------------------------- +"""Modbus Message Parser. The following is an example of how to parse modbus messages using the supplied framers for a number of protocols: @@ -17,7 +16,7 @@ import logging import collections import textwrap -from optparse import OptionParser # pylint: disable=deprecated-module +from optparse import OptionParser # pylint: disable=deprecated-module import codecs as c from pymodbus.factory import ClientDecoder, ServerDecoder @@ -29,7 +28,7 @@ # -------------------------------------------------------------------------- # FORMAT = ('%(asctime)-15s %(threadName)-15s' ' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s') -logging.basicConfig(format=FORMAT) #NOSONAR +logging.basicConfig(format=FORMAT) # NOSONAR log = logging.getLogger() @@ -38,10 +37,10 @@ # -------------------------------------------------------------------------- # class Decoder: - """ Decoder. """ + """Decoder.""" def __init__(self, framer, encode=False): - """ Initialize a new instance of the decoder + """Initialize a new instance of the decoder :param framer: The framer to use :param encode: If the message needs to be encoded @@ -50,12 +49,12 @@ def __init__(self, framer, encode=False): self.encode = encode def decode(self, message): - """ Attempt to decode the supplied message + """Attempt to decode the supplied message :param message: The message to decode """ value = message if self.encode else c.encode(message, 'hex_codec') - print("="*80) + print("=" * 80) print(f"Decoding Message {value}") print("=" * 80) decoders = [ @@ -68,49 +67,49 @@ def decode(self, message): try: decoder.addToFrame(message) if decoder.checkFrame(): - unit = decoder._header.get("uid", 0x00) # pylint: disable=protected-access + unit = decoder._header.get("uid", 0x00) # pylint: disable=protected-access decoder.advanceFrame() decoder.processIncomingPacket(message, self.report, unit) else: self.check_errors(decoder, message) - except Exception: # pylint: disable=broad-except + except Exception: # pylint: disable=broad-except self.check_errors(decoder, message) - def check_errors(self, decoder, message): # pylint: disable=no-self-use - """ Attempt to find message errors + def check_errors(self, decoder, message): # pylint: disable=no-self-use + """Attempt to find message errors :param message: The message to find errors in """ txt = f"Unable to parse message - {message} with {decoder}" log.error(txt) - def report(self, message): # pylint: disable=no-self-use - """ The callback to print the message information + def report(self, message): # pylint: disable=no-self-use + """Print the message information :param message: The message to print """ - print("%-15s = %s" % ('name', message.__class__.__name__)) #NOSONAR pylint: disable=consider-using-f-string + print("%-15s = %s" % ('name', message.__class__.__name__)) # NOSONAR pylint: disable=consider-using-f-string for (k_dict, v_dict) in message.__dict__.items(): if isinstance(v_dict, dict): - print("%-15s =" % k_dict) # pylint: disable=consider-using-f-string + print("%-15s =" % k_dict) # pylint: disable=consider-using-f-string for k_item, v_item in v_dict.items(): - print(" %-12s => %s" % (k_item, v_item)) # pylint: disable=consider-using-f-string + print(" %-12s => %s" % (k_item, v_item)) # pylint: disable=consider-using-f-string - elif isinstance(v_dict, collections.Iterable): # pylint: disable=no-member - print("%-15s =" % k_dict) # pylint: disable=consider-using-f-string + elif isinstance(v_dict, collections.Iterable): # pylint: disable=no-member + print("%-15s =" % k_dict) # pylint: disable=consider-using-f-string value = str([int(x) for x in v_dict]) for line in textwrap.wrap(value, 60): - print("%-15s . %s" % ("", line)) # pylint: disable=consider-using-f-string + print("%-15s . %s" % ("", line)) # pylint: disable=consider-using-f-string else: - print("%-15s = %s" % (k_dict, hex(v_dict))) # pylint: disable=consider-using-f-string - print("%-15s = %s" % ('documentation', message.__doc__)) # pylint: disable=consider-using-f-string + print("%-15s = %s" % (k_dict, hex(v_dict))) # pylint: disable=consider-using-f-string + print("%-15s = %s" % ('documentation', message.__doc__)) # pylint: disable=consider-using-f-string # -------------------------------------------------------------------------- # # and decode our message # -------------------------------------------------------------------------- # def get_options(): - """ A helper method to parse the command line options + """Parse the command line options :returns: The options manager """ @@ -157,7 +156,7 @@ def get_options(): def get_messages(option): - """ A helper method to generate the messages to parse + """Do a helper method to generate the messages to parse :param options: The option manager :returns: The message iterator to parse @@ -175,7 +174,7 @@ def get_messages(option): option.message = c.decode(option.message.encode(), 'hex_codec') yield option.message elif option.file: - with open(option.file, "r") as handle: # pylint: disable=unspecified-encoding + with open(option.file, "r") as handle: # pylint: disable=unspecified-encoding for line in handle: if line.startswith('#'): continue @@ -186,21 +185,20 @@ def get_messages(option): def main(): - """ The main runner function - """ + """Run main runner function""" option = get_options() if option.debug: try: log.setLevel(logging.DEBUG) - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except print(f"Logging is not supported on this system- {exc}") framer = { - 'tcp': ModbusSocketFramer, # noqa E221 - 'rtu': ModbusRtuFramer, # noqa E221 + 'tcp': ModbusSocketFramer, # noqa E221 + 'rtu': ModbusRtuFramer, # noqa E221 'binary': ModbusBinaryFramer, - 'ascii': ModbusAsciiFramer, # noqa E221 + 'ascii': ModbusAsciiFramer, # noqa E221 }.get(option.framer or option.parser, ModbusSocketFramer) decoder = Decoder(framer, option.ascii) diff --git a/examples/contrib/modbus_mapper.py b/examples/contrib/modbus_mapper.py index 7fa6dc792..0b2b99006 100644 --- a/examples/contrib/modbus_mapper.py +++ b/examples/contrib/modbus_mapper.py @@ -1,5 +1,6 @@ -""" Given a modbus mapping file, this is used to generate -decoder blocks so that non-programmers can define the +r"""This is used to generate decoder blocks. + +so that non-programmers can define the register values and then decode a modbus device all without having to write a line of code for decoding. @@ -64,9 +65,9 @@ def csv_mapping_parser(path, template): - """ Given a csv file of the the mapping data for - a modbus device, return a mapping layout that can - be used to decode an new block. + """Given a csv file of the the mapping data for a modbus device, + + return a mapping layout that can be used to decode an new block. .. note:: For the template, a few values are required to be defined: address, size, function, and type. All the remaining @@ -81,7 +82,7 @@ def csv_mapping_parser(path, template): :returns: The decoded csv dictionary """ mapping_blocks = defaultdict(dict) - with open(path, 'r') as handle: # pylint: disable=unspecified-encoding + with open(path, 'r') as handle: # pylint: disable=unspecified-encoding reader = csv.reader(handle) reader.next() # skip the csv header for row in reader: @@ -93,8 +94,9 @@ def csv_mapping_parser(path, template): def json_mapping_parser(path, template): - """ Given a json file of the the mapping data for - a modbus device, return a mapping layout that can + """Given a json file of the the mapping data for a modbus device, + + return a mapping layout that can be used to decode an new block. .. note:: For the template, a few values are required @@ -115,7 +117,7 @@ def json_mapping_parser(path, template): :returns: The decoded csv dictionary """ mapping_blocks = {} - with open(path, 'r') as handle: # pylint: disable=unspecified-encoding + with open(path, 'r') as handle: # pylint: disable=unspecified-encoding for tid, rows in json.load(handle).iteritems(): mappings = {} for key, values in rows.iteritems(): @@ -126,9 +128,9 @@ def json_mapping_parser(path, template): def xml_mapping_parser(): - """ Given an xml file of the the mapping data for - a modbus device, return a mapping layout that can - be used to decode an new block. + """Given an xml file of the the mapping data for a modbus device, + + return a mapping layout that can be used to decode an new block. .. note:: The input of the xml file is defined as follows:: @@ -145,8 +147,7 @@ def xml_mapping_parser(): # populated function data blocks. # --------------------------------------------------------------------------- # def modbus_context_decoder(mapping_blocks): - """ Given a mapping block input, generate a backing - slave context with initialized data blocks. + """Generate a backing slave context with initialized data blocks. .. note:: This expects the following for each block: address, value, and function where function is one of @@ -174,9 +175,9 @@ def modbus_context_decoder(mapping_blocks): # pass them to this decoder which will do the rest. # --------------------------------------------------------------------------- # class ModbusTypeDecoder: - """ This is a utility to determine the correct - decoder to use given a type name. By default this - supports all the types available in the default modbus + """This is a utility to determine the correct decoder to use given a type name. + + By default this supports all the types available in the default modbus decoder, however this can easily be extended this class and adding new types to the mapper:: @@ -189,26 +190,26 @@ def parse_my_bitfield(self, tokens): return lambda d: d.decode_my_type() """ + def __init__(self): - """ Initializes a new instance of the decoder - """ + """Initialize a new instance of the decoder""" self.default = lambda m: self.parse_16bit_uint self.parsers = { - 'uint': self.parse_16bit_uint, # noqa E221 - 'uint8': self.parse_8bit_uint, # noqa E221 - 'uint16': self.parse_16bit_uint, # noqa E221 - 'uint32': self.parse_32bit_uint, # noqa E221 - 'uint64': self.parse_64bit_uint, # noqa E221 - 'int': self.parse_16bit_int, # noqa E221 - 'int8': self.parse_8bit_int, # noqa E221 - 'int16': self.parse_16bit_int, # noqa E221 - 'int32': self.parse_32bit_int, # noqa E221 - 'int64': self.parse_64bit_int, # noqa E221 - 'float': self.parse_32bit_float, # noqa E221 + 'uint': self.parse_16bit_uint, # noqa E221 + 'uint8': self.parse_8bit_uint, # noqa E221 + 'uint16': self.parse_16bit_uint, # noqa E221 + 'uint32': self.parse_32bit_uint, # noqa E221 + 'uint64': self.parse_64bit_uint, # noqa E221 + 'int': self.parse_16bit_int, # noqa E221 + 'int8': self.parse_8bit_int, # noqa E221 + 'int16': self.parse_16bit_int, # noqa E221 + 'int32': self.parse_32bit_int, # noqa E221 + 'int64': self.parse_64bit_int, # noqa E221 + 'float': self.parse_32bit_float, # noqa E221 'float32': self.parse_32bit_float, # noqa E221 'float64': self.parse_64bit_float, # noqa E221 - 'string': self.parse_32bit_int, # noqa E221 - 'bits': self.parse_bits, # noqa E221 + 'string': self.parse_32bit_int, # noqa E221 + 'bits': self.parse_bits, # noqa E221 } # ------------------------------------------------------------ # @@ -216,71 +217,71 @@ def __init__(self): # ------------------------------------------------------------ # @staticmethod def parse_string(tokens): - """ Parse value. """ + """Parse value.""" _ = tokens.next() size = int(tokens.next()) return lambda d: d.decode_string(size=size) @staticmethod def parse_bits(): - """ Parse value. """ + """Parse value.""" return lambda d: d.decode_bits() @staticmethod def parse_8bit_uint(): - """ Parse value. """ + """Parse value.""" return lambda d: d.decode_8bit_uint() @staticmethod def parse_16bit_uint(): - """ Parse value. """ + """Parse value.""" return lambda d: d.decode_16bit_uint() @staticmethod def parse_32bit_uint(): - """ Parse value. """ + """Parse value.""" return lambda d: d.decode_32bit_uint() @staticmethod def parse_64bit_uint(): - """ Parse value. """ + """Parse value.""" return lambda d: d.decode_64bit_uint() @staticmethod def parse_8bit_int(): - """ Parse value. """ + """Parse value.""" return lambda d: d.decode_8bit_int() @staticmethod def parse_16bit_int(): - """ Parse value. """ + """Parse value.""" return lambda d: d.decode_16bit_int() @staticmethod def parse_32bit_int(): - """ Parse value. """ + """Parse value.""" return lambda d: d.decode_32bit_int() @staticmethod def parse_64bit_int(): - """ Parse value. """ + """Parse value.""" return lambda d: d.decode_64bit_int() @staticmethod def parse_32bit_float(): - """ Parse value. """ + """Parse value.""" return lambda d: d.decode_32bit_float() @staticmethod def parse_64bit_float(): - """ Parse value. """ + """Parse value.""" return lambda d: d.decode_64bit_float() # ------------------------------------------------------------ # Public Interface # ------------------------------------------------------------ - def tokenize(self, value): # pylint: disable=no-self-use - """ Given a value, return the tokens + def tokenize(self, value): # pylint: disable=no-self-use + """Return the tokens :param value: The value to tokenize :returns: A token generator @@ -290,22 +291,21 @@ def tokenize(self, value): # pylint: disable=no-self-use yield tokval def parse(self, value): - """ Given a type value, return a function - that supplied with a decoder, will decode - the correct value. + """Return a function that supplied with a decoder, + + will decode the correct value. :param value: The type of value to parse :returns: The decoder method to use """ tokens = self.tokenize(value) - token = tokens.next().lower() # pylint: disable=no-member + token = tokens.next().lower() # pylint: disable=no-member parser = self.parsers.get(token, self.default) return parser(tokens) def mapping_decoder(mapping_blocks, decoder=None): - """ Given the raw mapping blocks, convert - them into modbus value decoder map. + """Convert them into modbus value decoder map. :param mapping_blocks: The mapping blocks :param decoder: The type decoder to use diff --git a/examples/contrib/modbus_saver.py b/examples/contrib/modbus_saver.py index 7e384ec29..6d42d2cc3 100644 --- a/examples/contrib/modbus_saver.py +++ b/examples/contrib/modbus_saver.py @@ -1,5 +1,6 @@ -""" These are a collection of helper methods that can be -used to save a modbus server context to file for backup, +"""These are a collection of helper methods. + +that can be used to save a modbus server context to file for backup, checkpointing, or any other purpose. There use is very simple:: @@ -26,18 +27,20 @@ * handle_save_end(self) """ import json -import xml.etree.ElementTree as xml #nosec +import xml.etree.ElementTree as xml # nosec class ModbusDatastoreSaver: - """ An abstract base class that can be used to implement + """An abstract base class. + + that can be used to implement a persistence format for the modbus server context. In order to use it, just complete the necessary callbacks (SAX style) that your persistence format needs. """ def __init__(self, context, path=None): - """ Initialize a new instance of the saver. + """Initialize a new instance of the saver. :param context: The modbus server context :param path: The output path to save to @@ -46,18 +49,17 @@ def __init__(self, context, path=None): self.path = path or 'modbus-context-dump' def save(self): - """ The main runner method to save the - context to file which calls the various - callbacks which the sub classes will - implement. + """Save the context to file. + + which calls the various callbacks which the sub classes will implement. """ - with open(self.path, 'w') as self.file_handle: # pylint: disable=attribute-defined-outside-init,unspecified-encoding + with open(self.path, 'w') as self.file_handle: # noqa E501 pylint: disable=attribute-defined-outside-init,unspecified-encoding self.handle_save_start() for slave_name, slave in self.context: self.handle_slave_start(slave_name) for store_name, store in slave.store.iteritems(): self.handle_store_start(store_name) - self.handle_store_values(iter(store)) # pylint: disable=no-member + self.handle_store_values(iter(store)) # pylint: disable=no-member self.handle_store_end(store_name) self.handle_slave_end(slave_name) self.handle_save_end() @@ -66,31 +68,33 @@ def save(self): # predefined state machine callbacks # ------------------------------------------------------------ def handle_save_start(self): - """ Handle save start. """ + """Handle save start.""" def handle_store_start(self, store): - """ Handle store start. """ + """Handle store start.""" def handle_store_end(self, store): - """ Handle store end. """ + """Handle store end.""" def handle_slave_start(self, slave): - """ Handle slave start. """ + """Handle slave start.""" def handle_slave_end(self, slave): - """ handle slave end. """ + """Handle slave end.""" def handle_save_end(self): - """ Handle save end. """ + """Handle save end.""" # ---------------------------------------------------------------- # # Implementations of the data store savers # ---------------------------------------------------------------- # class JsonDatastoreSaver(ModbusDatastoreSaver): - """ An implementation of the modbus datastore saver + """An implementation of the modbus datastore saver. + that persists the context as a json document. """ + _context = None _store = None _slave = None @@ -103,30 +107,32 @@ class JsonDatastoreSaver(ModbusDatastoreSaver): } def handle_save_start(self): - """ Handle save start. """ + """Handle save start.""" self._context = {} def handle_slave_start(self, slave): - """ Handle slave start. """ + """Handle slave start.""" self._context[hex(slave)] = self._slave = {} def handle_store_start(self, store): - """ Handle store start. """ + """Handle store start.""" self._store = self.STORE_NAMES[store] def handle_store_values(self, values): - """ Handle store values. """ + """Handle store values.""" self._slave[self._store] = dict(values) def handle_save_end(self): - """ Handle save end. """ + """Handle save end.""" json.dump(self._context, self.file_handle) class CsvDatastoreSaver(ModbusDatastoreSaver): - """ An implementation of the modbus datastore saver + """An implementation of the modbus datastore saver. + that persists the context as a csv document. """ + _context = None _store = None _line = None @@ -140,35 +146,37 @@ class CsvDatastoreSaver(ModbusDatastoreSaver): } def handle_save_start(self): - """ Handle save start. """ + """Handle save start.""" self.file_handle.write(self.HEADER) def handle_slave_start(self, slave): - """ Handle slave start. """ + """Handle slave start.""" self._line = [str(slave)] def handle_store_start(self, store): - """ Handle store start. """ + """Handle store start.""" self._line.append(self.STORE_NAMES[store]) def handle_store_values(self, values): - """ Handle store values. """ + """Handle store values.""" self.file_handle.writelines(self.handle_store_value(values)) def handle_store_end(self, store): - """ Handle store end. """ + """Handle store end.""" self._line.pop() def handle_store_value(self, values): - """ Handle store value. """ + """Handle store value.""" for val_a, val_v in values: yield ','.join(self._line + [str(val_a), str(val_v)]) + self.NEWLINE class XmlDatastoreSaver(ModbusDatastoreSaver): - """ An implementation of the modbus datastore saver + """An implementation of the modbus datastore saver. + that persists the context as a XML document. """ + _context = None _store = None @@ -180,26 +188,27 @@ class XmlDatastoreSaver(ModbusDatastoreSaver): } def handle_save_start(self): - """ Handle save start. """ + """Handle save start.""" self._context = xml.Element("context") - self._root = xml.ElementTree(self._context) # pylint: disable=attribute-defined-outside-init + self._root = xml.ElementTree(self._context) # pylint: disable=attribute-defined-outside-init def handle_slave_start(self, slave): - """ Handle slave start. """ - self._slave = xml.SubElement(self._context, "slave") # pylint: disable=attribute-defined-outside-init + """Handle slave start.""" + self._slave = xml.SubElement(self._context, "slave") # pylint: disable=attribute-defined-outside-init self._slave.set("id", str(slave)) def handle_store_start(self, store): - """ Handle store start. """ + """Handle store start.""" self._store = xml.SubElement(self._slave, "store") self._store.set("function", self.STORE_NAMES[store]) def handle_store_values(self, values): - """ Handle store values. """ + """Handle store values.""" for address, value in values: entry = xml.SubElement(self._store, "entry") entry.text = str(value) entry.set("address", str(address)) def handle_save_end(self): + """Handle save end.""" self._root.write(self.file_handle) diff --git a/examples/contrib/modbus_scraper.py b/examples/contrib/modbus_scraper.py index 247f2490f..107a3c18b 100755 --- a/examples/contrib/modbus_scraper.py +++ b/examples/contrib/modbus_scraper.py @@ -1,11 +1,12 @@ #!/usr/bin/env python3 -""" This is a simple scraper that can be pointed at a -modbus device to pull down all its values and store +"""This is a simple scraper. + +that can be pointed at a modbus device to pull down all its values and store them as a collection of sequential data blocks. """ import logging -import pickle #nosec -from optparse import OptionParser # pylint: disable=deprecated-module +import pickle # nosec +from optparse import OptionParser # pylint: disable=deprecated-module from twisted.internet import serialport, reactor from twisted.internet.protocol import ClientFactory @@ -44,12 +45,12 @@ class ScraperProtocol(ModbusClientProtocol): - """ Scraper protocol. """ + """Scraper protocol.""" address = None def __init__(self, framer, endpoint): - """ Initializes our custom protocol + """Initialize our custom protocol :param framer: The decoder to use to process messages :param endpoint: The endpoint to send results to @@ -58,33 +59,28 @@ def __init__(self, framer, endpoint): self.endpoint = endpoint def connection_made(self): - """ Callback for when the client has connected - to the remote server. - """ + """Call when the client has connected to the remote server.""" super().connectionMade() log.debug("Beginning the processing loop") self.address = self.factory.starting - reactor.callLater(DELAY, self.scrape_holding_registers) # pylint: disable=no-member + reactor.callLater(DELAY, self.scrape_holding_registers) # pylint: disable=no-member - def connection_lost(self, reason): # pylint: disable=no-self-use,unused-argument - """ Callback for when the client disconnects from the - server. + def connection_lost(self, reason): # pylint: disable=no-self-use,unused-argument + """Call when the client disconnects from the server. :param reason: The reason for the disconnection """ - reactor.callLater(DELAY, reactor.stop) # pylint: disable=no-member + reactor.callLater(DELAY, reactor.stop) # pylint: disable=no-member def scrape_holding_registers(self): - """ Defer fetching holding registers - """ + """Defer fetching holding registers""" txt = f"reading holding registers: {self.address}" log.debug(txt) data = self.read_holding_registers(self.address, count=COUNT, unit=SLAVE) data.addCallbacks(self.scrape_discrete_inputs, self.error_handler) def scrape_discrete_inputs(self, response): - """ Defer fetching holding registers - """ + """Defer fetching holding registers""" txt = f"reading discrete inputs: {self.address}" log.debug(txt) self.endpoint.write((3, self.address, response.registers)) @@ -92,8 +88,7 @@ def scrape_discrete_inputs(self, response): data.addCallbacks(self.scrape_input_registers, self.error_handler) def scrape_input_registers(self, response): - """ Defer fetching holding registers - """ + """Defer fetching holding registers""" txt = f"reading discrete inputs: {self.address}" log.debug(txt) self.endpoint.write((2, self.address, response.bits)) @@ -101,7 +96,7 @@ def scrape_input_registers(self, response): data.addCallbacks(self.scrape_coils, self.error_handler) def scrape_coils(self, response): - """ Write values of holding registers, defer fetching coils + """Write values of holding registers, defer fetching coils :param response: The response to process """ @@ -112,7 +107,7 @@ def scrape_coils(self, response): data.addCallbacks(self.start_next_cycle, self.error_handler) def start_next_cycle(self, response): - """ Write values of coils, trigger next cycle + """Write values of coils, trigger next cycle :param response: The response to process """ @@ -124,10 +119,10 @@ def start_next_cycle(self, response): self.endpoint.finalize() self.transport.loseConnection() else: - reactor.callLater(DELAY, self.scrape_holding_registers) # pylint: disable=no-member + reactor.callLater(DELAY, self.scrape_holding_registers) # pylint: disable=no-member - def error_handler(self, failure): # pylint: disable=no-self-use - """ Handle any twisted errors + def error_handler(self, failure): # pylint: disable=no-self-use + """Handle any twisted errors :param failure: The error to handle """ @@ -146,18 +141,18 @@ def error_handler(self, failure): # pylint: disable=no-self-use # It also persists data between client instances (think protocol singleton). # --------------------------------------------------------------------------- # class ScraperFactory(ClientFactory): - """ Scraper factory. """ + """Scraper factory.""" protocol = ScraperProtocol def __init__(self, framer, endpoint, query): - """ Remember things necessary for building a protocols """ + """Remember things necessary for building a protocols""" self.framer = framer self.endpoint = endpoint self.starting, self.ending = query def buildProtocol(self, _): - """ Create a protocol and start the reading cycle """ + """Create a protocol and start the reading cycle""" protocol = self.protocol(self.framer, self.endpoint) protocol.factory = self return protocol @@ -173,11 +168,11 @@ def buildProtocol(self, _): # # How you start your client is really up to you. # --------------------------------------------------------------------------- # -class SerialModbusClient(serialport.SerialPort): # pylint: disable=abstract-method - """ Serial modbus client. """ +class SerialModbusClient(serialport.SerialPort): # pylint: disable=abstract-method + """Serial modbus client.""" def __init__(self, factory, *args, **kwargs): - """ Setup the client and start listening on the serial port + """Do setup the client and start listening on the serial port :param factory: The factory to build clients with """ @@ -195,10 +190,10 @@ def __init__(self, factory, *args, **kwargs): # - a database or file recorder # --------------------------------------------------------------------------- # class LoggingContextReader: - """ Logging context reader. """ + """Logging context reader.""" def __init__(self, output): - """ Initialize a new instance of the logger + """Initialize a new instance of the logger :param output: The output file to save to """ @@ -210,7 +205,7 @@ def __init__(self, output): ir=ModbusSequentialDataBlock.create()) def write(self, response): - """ Handle the next modbus response + """Handle the next modbus response :param response: The response to process """ @@ -220,8 +215,8 @@ def write(self, response): self.context.setValues(file_ptr, address, values) def finalize(self): - """ Finalize. """ - with open(self.output, "w") as handle: # pylint: disable=unspecified-encoding + """Finalize.""" + with open(self.output, "w") as handle: # pylint: disable=unspecified-encoding pickle.dump(self.context, handle) @@ -229,7 +224,7 @@ def finalize(self): # Main start point # -------------------------------------------------------------------------- # def get_options(): - """ A helper method to parse the command line options + """Parse the command line options :returns: The options manager """ @@ -260,13 +255,13 @@ def get_options(): def main(): - """ The main runner function """ + """Run main runner function""" options = get_options() if options.debug: try: log.setLevel(logging.DEBUG) - except Exception: # pylint: disable=broad-except + except Exception: # pylint: disable=broad-except print("Logging is not supported on this system") # split the query into a starting and ending range @@ -280,14 +275,14 @@ def main(): # how to connect based on TCP vs Serial clients if isinstance(framer, ModbusSocketFramer): - reactor.connectTCP(options.host, options.port, factory) # pylint: disable=no-member + reactor.connectTCP(options.host, options.port, factory) # pylint: disable=no-member else: SerialModbusClient(factory, options.port, reactor) log.debug("Starting the client") - reactor.run() # pylint: disable=no-member + reactor.run() # pylint: disable=no-member log.debug("Finished scraping the client") - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except print(exc) # --------------------------------------------------------------------------- # diff --git a/examples/contrib/modbus_simulator.py b/examples/contrib/modbus_simulator.py index cce0ac50c..69f927f21 100644 --- a/examples/contrib/modbus_simulator.py +++ b/examples/contrib/modbus_simulator.py @@ -1,10 +1,11 @@ #!/usr/bin/env python3 -""" An example of creating a fully implemented modbus server +"""An example of creating a fully implemented modbus server. + with read/write data as well as user configurable base data """ import logging -import pickle #nosec -from optparse import OptionParser # pylint: disable=deprecated-module +import pickle # nosec +from optparse import OptionParser # pylint: disable=deprecated-module from pymodbus.server.asynchronous import StartTcpServer from pymodbus.datastore import ModbusServerContext, ModbusSlaveContext @@ -25,7 +26,7 @@ def root_test(): - """ Simple test to see if we are running as root """ + """Check to see if we are running as root""" return True # removed for the time being as it isn't portable # return getpass.getuser() == "root" @@ -35,10 +36,10 @@ def root_test(): class ConfigurationException(Exception): - """ Exception for configuration error """ + """Exception for configuration error""" def __init__(self, string): - """ Initializes the ConfigurationException instance + """Initialize the ConfigurationException instance :param string: The message to append to the exception """ @@ -46,16 +47,15 @@ def __init__(self, string): self.string = string def __str__(self): - """ Builds a representation of the object + """Build a representation of the object :returns: A string representation of the object """ return f'Configuration Error: {self.string}' -class Configuration: # pylint: disable=too-few-public-methods - """ Class used to parse configuration file and create and modbus - datastore. +class Configuration: # pylint: disable=too-few-public-methods + """Class used to parse configuration file and create and modbus datastore. The format of the configuration file is actually just a python pickle, which is a compressed memory dump from @@ -63,28 +63,28 @@ class Configuration: # pylint: disable=too-few-public-methods """ def __init__(self, config): - """ Tries to load a configuration file, lets the file not - found exception fall through + """Try to load a configuration file. + + lets the file not found exception fall through :param config: The pickled datastore """ try: - self.file = open(config, "rb") # pylint: disable=consider-using-with + self.file = open(config, "rb") # pylint: disable=consider-using-with except Exception as exc: _logger.critical(str(exc)) - raise ConfigurationException(f"File not found {config}") # pylint: disable=raise-missing-from + raise ConfigurationException(f"File not found {config}") # pylint: disable=raise-missing-from def parse(self): - """ Parses the config file and creates a server context - """ - handle = pickle.load(self.file) #nosec + """Parse the config file and creates a server context""" + handle = pickle.load(self.file) # nosec try: # test for existence, or bomb dsd = handle['di'] csd = handle['ci'] hsd = handle['hr'] isd = handle['ir'] except Exception: - raise ConfigurationException("Invalid Configuration") # pylint: disable=raise-missing-from + raise ConfigurationException("Invalid Configuration") # pylint: disable=raise-missing-from slave = ModbusSlaveContext(d=dsd, c=csd, h=hsd, i=isd) return ModbusServerContext(slaves=slave) @@ -94,7 +94,7 @@ def parse(self): def main(): - """ Server launcher """ + """Server launcher""" parser = OptionParser() parser.add_option("-c", "--conf", help="The configuration file to load", @@ -109,7 +109,7 @@ def main(): try: server_log.setLevel(logging.DEBUG) protocol_log.setLevel(logging.DEBUG) - except Exception: # pylint: disable=broad-except + except Exception: # pylint: disable=broad-except print("Logging is not supported on this system") # parse configuration file and run diff --git a/examples/contrib/modbus_tls_client.py b/examples/contrib/modbus_tls_client.py index 06e2091b1..0cbc9386e 100755 --- a/examples/contrib/modbus_tls_client.py +++ b/examples/contrib/modbus_tls_client.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Simple Modbus TCP over TLS client ---------------------------------------------------------------------------- +"""Simple Modbus TCP over TLS client. This is a simple example of writing a modbus TCP over TLS client that uses Python builtin module ssl - TLS/SSL wrapper for socket objects for the TLS diff --git a/examples/contrib/modicon_payload.py b/examples/contrib/modicon_payload.py index 4bfb7bee3..babd8dc7e 100644 --- a/examples/contrib/modicon_payload.py +++ b/examples/contrib/modicon_payload.py @@ -1,5 +1,4 @@ -""" Modbus Modicon Payload Builder ------------------------------------------------------------ +"""Modbus Modicon Payload Builder. This is an example of building a custom payload builder that can be used in the pymodbus library. Below is a @@ -14,8 +13,9 @@ class ModiconPayloadBuilder(IPayloadBuilder): - """ A utility that helps build modicon encoded payload - messages to be written with the various modbus messages. + """A utility that helps build modicon encoded payload messages. + + to be written with the various modbus messages. example:: builder = ModiconPayloadBuilder() @@ -25,7 +25,7 @@ class ModiconPayloadBuilder(IPayloadBuilder): """ def __init__(self, payload=None, endian=Endian.Little): - """ Initialize a new instance of the payload builder + """Initialize a new instance of the payload builder :param payload: Raw payload data to initialize with :param endian: The endianness of the payload @@ -34,19 +34,18 @@ def __init__(self, payload=None, endian=Endian.Little): self._endian = endian def __str__(self): - """ Return the payload buffer as a string + """Return the payload buffer as a string :returns: The payload buffer as a string """ return ''.join(self._payload) def reset(self): - """ Reset the payload buffer - """ + """Reset the payload buffer""" self._payload = [] def build(self): - """ Return the payload buffer as a list + """Return the payload buffer as a list This list is two bytes per element and can thus be treated as a list of registers. @@ -59,7 +58,7 @@ def build(self): return [string[i:i + 2] for i in range(0, length, 2)] def add_bits(self, values): - """ Adds a collection of bits to be encoded + """Add a collection of bits to be encoded If these are less than a multiple of eight, they will be left padded with 0 bits to make @@ -71,7 +70,7 @@ def add_bits(self, values): self._payload.append(value) def add_8bit_uint(self, value): - """ Adds a 8 bit unsigned int to the buffer + """Add a 8 bit unsigned int to the buffer :param value: The value to add to the buffer """ @@ -79,7 +78,7 @@ def add_8bit_uint(self, value): self._payload.append(pack(fstring, value)) def add_16bit_uint(self, value): - """ Adds a 16 bit unsigned int to the buffer + """Add a 16 bit unsigned int to the buffer :param value: The value to add to the buffer """ @@ -87,7 +86,7 @@ def add_16bit_uint(self, value): self._payload.append(pack(fstring, value)) def add_32bit_uint(self, value): - """ Adds a 32 bit unsigned int to the buffer + """Add a 32 bit unsigned int to the buffer :param value: The value to add to the buffer """ @@ -97,7 +96,7 @@ def add_32bit_uint(self, value): self._payload.append(handle) def add_8bit_int(self, value): - """ Adds a 8 bit signed int to the buffer + """Add a 8 bit signed int to the buffer :param value: The value to add to the buffer """ @@ -105,7 +104,7 @@ def add_8bit_int(self, value): self._payload.append(pack(fstring, value)) def add_16bit_int(self, value): - """ Adds a 16 bit signed int to the buffer + """Add a 16 bit signed int to the buffer :param value: The value to add to the buffer """ @@ -113,7 +112,7 @@ def add_16bit_int(self, value): self._payload.append(pack(fstring, value)) def add_32bit_int(self, value): - """ Adds a 32 bit signed int to the buffer + """Add a 32 bit signed int to the buffer :param value: The value to add to the buffer """ @@ -123,7 +122,7 @@ def add_32bit_int(self, value): self._payload.append(handle) def add_32bit_float(self, value): - """ Adds a 32 bit float to the buffer + """Add a 32 bit float to the buffer :param value: The value to add to the buffer """ @@ -133,7 +132,7 @@ def add_32bit_float(self, value): self._payload.append(handle) def add_string(self, value): - """ Adds a string to the buffer + """Add a string to the buffer :param value: The value to add to the buffer """ @@ -143,9 +142,9 @@ def add_string(self, value): class ModiconPayloadDecoder: - """ A utility that helps decode modicon encoded payload - messages from a modbus response message. What follows is - a simple example:: + """A utility that helps decode modicon encoded payload messages from a modbus response message. + + What follows is a simple example:: decoder = ModiconPayloadDecoder(payload) first = decoder.decode_8bit_uint() @@ -153,8 +152,7 @@ class ModiconPayloadDecoder: """ def __init__(self, payload, endian): - - """ Initialize a new payload decoder + """Initialize a new payload decoder :param payload: The payload to decode with """ @@ -164,8 +162,9 @@ def __init__(self, payload, endian): @staticmethod def from_registers(registers, endian=Endian.Little): - """ Initialize a payload decoder with the result of - reading a collection of registers from a modbus device. + """Initialize a payload decoder. + + with the result of reading a collection of registers from a modbus device. The registers are treated as a list of 2 byte values. We have to do this because of how the data has already @@ -182,8 +181,9 @@ def from_registers(registers, endian=Endian.Little): @staticmethod def from_coils(coils, endian=Endian.Little): - """ Initialize a payload decoder with the result of - reading a collection of coils from a modbus device. + """Initialize a payload decoder. + + with the result of reading a collection of coils from a modbus device. The coils are treated as a list of bit(boolean) values. @@ -197,29 +197,25 @@ def from_coils(coils, endian=Endian.Little): raise ParameterException('Invalid collection of coils supplied') def reset(self): - """ Reset the decoder pointer back to the start - """ + """Reset the decoder pointer back to the start""" self._pointer = 0x00 def decode_8bit_uint(self): - """ Decodes a 8 bit unsigned int from the buffer - """ + """Decode a 8 bit unsigned int from the buffer""" self._pointer += 1 fstring = self._endian + 'B' handle = self._payload[self._pointer - 1:self._pointer] return unpack(fstring, handle)[0] def decode_16bit_uint(self): - """ Decodes a 16 bit unsigned int from the buffer - """ + """Decode a 16 bit unsigned int from the buffer""" self._pointer += 2 fstring = self._endian + 'H' handle = self._payload[self._pointer - 2:self._pointer] return unpack(fstring, handle)[0] def decode_32bit_uint(self): - """ Decodes a 32 bit unsigned int from the buffer - """ + """Decode a 32 bit unsigned int from the buffer""" self._pointer += 4 fstring = self._endian + 'I' handle = self._payload[self._pointer - 4:self._pointer] @@ -227,24 +223,21 @@ def decode_32bit_uint(self): return unpack(fstring, handle)[0] def decode_8bit_int(self): - """ Decodes a 8 bit signed int from the buffer - """ + """Decode a 8 bit signed int from the buffer""" self._pointer += 1 fstring = self._endian + 'b' handle = self._payload[self._pointer - 1:self._pointer] return unpack(fstring, handle)[0] def decode_16bit_int(self): - """ Decodes a 16 bit signed int from the buffer - """ + """Decode a 16 bit signed int from the buffer""" self._pointer += 2 fstring = self._endian + 'h' handle = self._payload[self._pointer - 2:self._pointer] return unpack(fstring, handle)[0] def decode_32bit_int(self): - """ Decodes a 32 bit signed int from the buffer - """ + """Decode a 32 bit signed int from the buffer""" self._pointer += 4 fstring = self._endian + 'i' handle = self._payload[self._pointer - 4:self._pointer] @@ -252,8 +245,7 @@ def decode_32bit_int(self): return unpack(fstring, handle)[0] def decode_32bit_float(self): - """ Decodes a float from the buffer - """ + """Decode a float from the buffer""" self._pointer += 4 fstring = self._endian + 'f' handle = self._payload[self._pointer - 4:self._pointer] @@ -261,14 +253,13 @@ def decode_32bit_float(self): return unpack(fstring, handle)[0] def decode_bits(self): - """ Decodes a byte worth of bits from the buffer - """ + """Decode a byte worth of bits from the buffer""" self._pointer += 1 handle = self._payload[self._pointer - 1:self._pointer] return unpack_bitstring(handle) def decode_string(self, size=1): - """ Decodes a string from the buffer + """Decode a string from the buffer :param size: The size of the string to decode """ diff --git a/examples/contrib/remote_server_context.py b/examples/contrib/remote_server_context.py index 220563633..4558ab18d 100644 --- a/examples/contrib/remote_server_context.py +++ b/examples/contrib/remote_server_context.py @@ -1,4 +1,5 @@ -""" Although there is a remote server context already in the main library, +"""Although there is a remote server context already in the main library, + it works under the assumption that users would have a server context of the following form:: @@ -38,14 +39,15 @@ class RemoteSingleSlaveContext(IModbusSlaveContext): - """ This is a remote server context that allows one - to create a server context backed by a single client that + """This is a remote server context, + + that allows one to create a server context backed by a single client that may be attached to many slave units. This can be used to effectively create a modbus forwarding server. """ def __init__(self, context, unit_id): - """ Initializes the datastores + """Initialize the datastores :param context: The underlying context to operate with :param unit_id: The slave that this context will contact @@ -54,11 +56,11 @@ def __init__(self, context, unit_id): self.unit_id = unit_id def reset(self): - """ Resets all the datastores to their default values """ + """Reset all the datastores to their default values""" raise NotImplementedException() def validate(self, fx, address, count=1): - """ Validates the request to make sure it is in range + """Validate the request to make sure it is in range :param fx: The function we are working with :param address: The starting address @@ -73,7 +75,7 @@ def validate(self, fx, address, count=1): return not result.isError() def getValues(self, fx, address, count=1): - """ Get `count` values from datastore + """Get `count` values from datastore :param fx: The function we are working with :param address: The starting address @@ -88,7 +90,7 @@ def getValues(self, fx, address, count=1): return self.__extract_result(self.decode(fx), result) def setValues(self, fx, address, values): - """ Sets the datastore with the supplied values + """Set the datastore with the supplied values :param fx: The function we are working with :param address: The starting address @@ -101,16 +103,16 @@ def setValues(self, fx, address, values): self.unit_id) def __str__(self): - """ Returns a string representation of the context + """Return a string representation of the context :returns: A string representation of the context """ return f"Remote Single Slave Context({self.unit_id})" - def __extract_result(self, f_code, result): # pylint: disable=no-self-use - """ A helper method to extract the values out of - a response. The future api should make the result - consistent so we can just call `result.getValues()`. + def __extract_result(self, f_code, result): # pylint: disable=no-self-use + """Extract the values out of a response. + + The future api should make the result consistent so we can just call `result.getValues()`. :param fx: The function to call :param result: The resulting data @@ -131,42 +133,42 @@ def __extract_result(self, f_code, result): # pylint: disable=no-self-use class RemoteServerContext: - """ This is a remote server context that allows one - to create a server context backed by a single client that + """This is a remote server context, + + that allows one to create a server context backed by a single client that may be attached to many slave units. This can be used to effectively create a modbus forwarding server. """ def __init__(self, client): - """ Initializes the datastores + """Initialize the datastores :param client: The client to retrieve values with """ self.get_callbacks = { - 'd': lambda a, c, s: client.read_discrete_inputs(a, c, s), # pylint: disable=unnecessary-lambda - 'c': lambda a, c, s: client.read_coils(a, c, s), # pylint: disable=unnecessary-lambda - 'h': lambda a, c, s: client.read_holding_registers(a, c, s), # pylint: disable=unnecessary-lambda - 'i': lambda a, c, s: client.read_input_registers(a, c, s), # pylint: disable=unnecessary-lambda + 'd': lambda a, c, s: client.read_discrete_inputs(a, c, s), # pylint: disable=unnecessary-lambda + 'c': lambda a, c, s: client.read_coils(a, c, s), # pylint: disable=unnecessary-lambda + 'h': lambda a, c, s: client.read_holding_registers(a, c, s), # pylint: disable=unnecessary-lambda + 'i': lambda a, c, s: client.read_input_registers(a, c, s), # pylint: disable=unnecessary-lambda } self.set_callbacks = { - 'd': lambda a, v, s: client.write_coils(a, v, s), # pylint: disable=unnecessary-lambda - 'c': lambda a, v, s: client.write_coils(a, v, s), # pylint: disable=unnecessary-lambda - 'h': lambda a, v, s: client.write_registers(a, v, s), # pylint: disable=unnecessary-lambda - 'i': lambda a, v, s: client.write_registers(a, v, s), # pylint: disable=unnecessary-lambda + 'd': lambda a, v, s: client.write_coils(a, v, s), # pylint: disable=unnecessary-lambda + 'c': lambda a, v, s: client.write_coils(a, v, s), # pylint: disable=unnecessary-lambda + 'h': lambda a, v, s: client.write_registers(a, v, s), # pylint: disable=unnecessary-lambda + 'i': lambda a, v, s: client.write_registers(a, v, s), # pylint: disable=unnecessary-lambda } self._client = client self.slaves = {} # simply a cache def __str__(self): - """ Returns a string representation of the context + """Return a string representation of the context :returns: A string representation of the context """ return f"Remote Server Context{self._client}" def __iter__(self): - """ Iterator over the current collection of slave - contexts. + """Iterate over the current collection of slave contexts. :returns: An iterator over the slave contexts """ @@ -174,7 +176,7 @@ def __iter__(self): return iter(self.slaves.items()) def __contains__(self, slave): - """ Check if the given slave is in this list + """Check if the given slave is in this list :param slave: slave The slave to check for existence :returns: True if the slave exists, False otherwise @@ -185,7 +187,7 @@ def __contains__(self, slave): return True def __setitem__(self, slave, context): - """ Used to set a new slave context + """Use to set a new slave context :param slave: The slave context to set :param context: The new context to set for this slave @@ -193,14 +195,14 @@ def __setitem__(self, slave, context): raise NotImplementedException() # doesn't make sense here def __delitem__(self, slave): - """ Wrapper used to access the slave context + """Use to access the slave context :param slave: The slave context to remove """ raise NotImplementedException() # doesn't make sense here def __getitem__(self, slave): - """ Used to get access to a slave context + """Use to get access to a slave context :param slave: The slave context to get :returns: The requested slave context diff --git a/examples/contrib/serial_forwarder.py b/examples/contrib/serial_forwarder.py index 8b91e8408..0d0e22694 100755 --- a/examples/contrib/serial_forwarder.py +++ b/examples/contrib/serial_forwarder.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -""" Pymodbus Synchronous Serial Forwarder --------------------------------------------------------------------------- +"""Pymodbus Synchronous Serial Forwarder. We basically set the context for the tcp serial server to be that of a serial client! This is just an example of how clever you can be with @@ -25,13 +24,13 @@ def run_serial_forwarder(): - """ Run serial forwarder. """ + """Run serial forwarder.""" # ----------------------------------------------------------------------- # # initialize the datastore(serial client) # Note this would send the requests on the serial client with address = 0 # ----------------------------------------------------------------------- # - client = ModbusClient(method='rtu', port='/tmp/ptyp0') # nosec NOSONAR + client = ModbusClient(method='rtu', port='/tmp/ptyp0') # nosec NOSONAR # If required to communicate with a specified client use unit= # in RemoteSlaveContext # For e.g to forward the requests to slave with unit address 1 use diff --git a/examples/contrib/sunspec_client.py b/examples/contrib/sunspec_client.py index 2043e0af3..87a1c2e3d 100644 --- a/examples/contrib/sunspec_client.py +++ b/examples/contrib/sunspec_client.py @@ -1,4 +1,4 @@ -""" Sunspec client. """ +"""Sunspec client.""" import logging from twisted.internet.defer import Deferred @@ -17,139 +17,134 @@ # --------------------------------------------------------------------------- # # Sunspec Common Constants # --------------------------------------------------------------------------- # -class SunspecDefaultValue: # pylint: disable=too-few-public-methods - """ A collection of constants to indicate if - a value is not implemented. - """ - Signed16 = 0x8000 # noqa E221 - Unsigned16 = 0xffff # noqa E221 - Accumulator16 = 0x0000 # noqa E221 - Scale = 0x8000 # noqa E221 - Signed32 = 0x80000000 # noqa E221 - Float32 = 0x7fc00000 # noqa E221 - Unsigned32 = 0xffffffff # noqa E221 - Accumulator32 = 0x00000000 # noqa E221 - Signed64 = 0x8000000000000000 # noqa E221 - Unsigned64 = 0xffffffffffffffff # noqa E221 - Accumulator64 = 0x0000000000000000 # noqa E221 - String = '\x00' # noqa E221 - - -class SunspecStatus: # pylint: disable=too-few-public-methods - """ Indicators of the current status of a - sunspec device - """ - Normal = 0x00000000 # noqa E221 - Error = 0xfffffffe # noqa E221 +class SunspecDefaultValue: # pylint: disable=too-few-public-methods + """A collection of constants to indicate if a value is not implemented.""" + + Signed16 = 0x8000 # noqa E221 + Unsigned16 = 0xffff # noqa E221 + Accumulator16 = 0x0000 # noqa E221 + Scale = 0x8000 # noqa E221 + Signed32 = 0x80000000 # noqa E221 + Float32 = 0x7fc00000 # noqa E221 + Unsigned32 = 0xffffffff # noqa E221 + Accumulator32 = 0x00000000 # noqa E221 + Signed64 = 0x8000000000000000 # noqa E221 + Unsigned64 = 0xffffffffffffffff # noqa E221 + Accumulator64 = 0x0000000000000000 # noqa E221 + String = '\x00' # noqa E221 + + +class SunspecStatus: # pylint: disable=too-few-public-methods + """Indicators of the current status of a sunspec device""" + + Normal = 0x00000000 # noqa E221 + Error = 0xfffffffe # noqa E221 Unknown = 0xffffffff -class SunspecIdentifier: # pylint: disable=too-few-public-methods - """ Assigned identifiers that are pre-assigned - by the sunspec protocol. - """ +class SunspecIdentifier: # pylint: disable=too-few-public-methods + """Assigned identifiers that are pre-assigned by the sunspec protocol.""" + Sunspec = 0x53756e53 -class SunspecModel: # pylint: disable=too-few-public-methods - """ Assigned device indentifiers that are pre-assigned - by the sunspec protocol. - """ +class SunspecModel: # pylint: disable=too-few-public-methods + """Assigned device indentifiers that are pre-assigned by the sunspec protocol.""" + # --------------------------------------------- # 0xx Common Models # --------------------------------------------- - CommonBlock = 1 # noqa E221 - AggregatorBlock = 2 # noqa E221 + CommonBlock = 1 # noqa E221 + AggregatorBlock = 2 # noqa E221 # --------------------------------------------- # 1xx Inverter Models # --------------------------------------------- - SinglePhaseIntegerInverter = 101 # noqa E221 - SplitPhaseIntegerInverter = 102 # noqa E221 - ThreePhaseIntegerInverter = 103 # noqa E221 - SinglePhaseFloatsInverter = 103 # noqa E221 - SplitPhaseFloatsInverter = 102 # noqa E221 - ThreePhaseFloatsInverter = 103 # noqa E221 + SinglePhaseIntegerInverter = 101 # noqa E221 + SplitPhaseIntegerInverter = 102 # noqa E221 + ThreePhaseIntegerInverter = 103 # noqa E221 + SinglePhaseFloatsInverter = 103 # noqa E221 + SplitPhaseFloatsInverter = 102 # noqa E221 + ThreePhaseFloatsInverter = 103 # noqa E221 # --------------------------------------------- # 2xx Meter Models # --------------------------------------------- - SinglePhaseMeter = 201 # noqa E221 - SplitPhaseMeter = 201 # noqa E221 - WyeConnectMeter = 201 # noqa E221 - DeltaConnectMeter = 201 # noqa E221 + SinglePhaseMeter = 201 # noqa E221 + SplitPhaseMeter = 201 # noqa E221 + WyeConnectMeter = 201 # noqa E221 + DeltaConnectMeter = 201 # noqa E221 # --------------------------------------------- # 3xx Environmental Models # --------------------------------------------- - BaseMeteorological = 301 # noqa E221 - Irradiance = 302 # noqa E221 - BackOfModuleTemperature = 303 # noqa E221 - Inclinometer = 304 # noqa E221 - Location = 305 # noqa E221 - ReferencePoint = 306 # noqa E221 - BaseMeteorological = 307 # noqa E221 - MiniMeteorological = 308 # noqa E221 + BaseMeteorological = 301 # noqa E221 + Irradiance = 302 # noqa E221 + BackOfModuleTemperature = 303 # noqa E221 + Inclinometer = 304 # noqa E221 + Location = 305 # noqa E221 + ReferencePoint = 306 # noqa E221 + BaseMeteorological = 307 # noqa E221 + MiniMeteorological = 308 # noqa E221 # --------------------------------------------- # 4xx String Combiner Models # --------------------------------------------- - BasicStringCombiner = 401 # noqa E221 - AdvancedStringCombiner = 402 # noqa E221 + BasicStringCombiner = 401 # noqa E221 + AdvancedStringCombiner = 402 # noqa E221 # --------------------------------------------- # 5xx Panel Models # --------------------------------------------- - PanelFloat = 501 # noqa E221 - PanelInteger = 502 # noqa E221 + PanelFloat = 501 # noqa E221 + PanelInteger = 502 # noqa E221 # --------------------------------------------- # 641xx outback_ Blocks # --------------------------------------------- - outback_device_identifier = 64110 # noqa E221 - outback_charge_controller = 64111 # noqa E221 - outback_fm_charge_controller = 64112 # noqa E221 - outback_fx_inv_realtime = 64113 # noqa E221 - outback_fx_inv_conf = 64114 # noqa E221 - outback_split_phase_rad_inv = 64115 # noqa E221 - outback_radian_inv_conf = 64116 # noqa E221 + outback_device_identifier = 64110 # noqa E221 + outback_charge_controller = 64111 # noqa E221 + outback_fm_charge_controller = 64112 # noqa E221 + outback_fx_inv_realtime = 64113 # noqa E221 + outback_fx_inv_conf = 64114 # noqa E221 + outback_split_phase_rad_inv = 64115 # noqa E221 + outback_radian_inv_conf = 64116 # noqa E221 outback_single_phase_rad_inv_rt = 64117 # noqa E221 - outback_flexnet_dc_realtime = 64118 # noqa E221 - outback_flexnet_dc_conf = 64119 # noqa E221 - outback_system_control = 64120 # noqa E221 + outback_flexnet_dc_realtime = 64118 # noqa E221 + outback_flexnet_dc_conf = 64119 # noqa E221 + outback_system_control = 64120 # noqa E221 # --------------------------------------------- # 64xxx Vendor Extension Block # --------------------------------------------- - EndOfSunSpecMap = 65535 # noqa E221 + EndOfSunSpecMap = 65535 # noqa E221 @classmethod def lookup(cls, code): - """ Given a device identifier, return the - device model name for that identifier + """Return the device model name for that identifier :param code: The device code to lookup :returns: The device model name, or None if none available """ - values = dict((v, k) for k, v in cls.__dict__.iteritems() # pylint: disable=no-member + values = dict((v, k) for k, v in cls.__dict__.iteritems() # pylint: disable=no-member if not callable(v)) return values.get(code, None) -class SunspecOffsets: # pylint: disable=too-few-public-methods - """ Well known offsets that are used throughout - the sunspec protocol - """ - CommonBlock = 40000 # noqa E221 - CommonBlockLength = 69 # noqa E221 - AlternateCommonBlock = 50000 # noqa E221 +class SunspecOffsets: # pylint: disable=too-few-public-methods + """Well known offsets that are used throughout the sunspec protocol""" + + CommonBlock = 40000 # noqa E221 + CommonBlockLength = 69 # noqa E221 + AlternateCommonBlock = 50000 # noqa E221 # --------------------------------------------------------------------------- # # Common Functions # --------------------------------------------------------------------------- # -def defer_or_apply(func): #NOSONAR pylint: disable=unused-argument - """ Decorator to apply an adapter method +def defer_or_apply(func): # NOSONAR pylint: disable=unused-argument + """Apply an adapter method. + to a result regardless if it is a deferred or a concrete response. @@ -165,8 +160,7 @@ def closure(future, adapt): def create_sunspec_sync_client(host): - """ A quick helper method to create a sunspec - client. + """Create a sunspec client. :param host: The host to connect to :returns: an initialized SunspecClient @@ -182,12 +176,10 @@ def create_sunspec_sync_client(host): # Sunspec Client # --------------------------------------------------------------------------- # class SunspecDecoder(BinaryPayloadDecoder): - """ A decoder that deals correctly with the sunspec - binary format. - """ + """A decoder that deals correctly with the sunspec binary format.""" def __init__(self, payload, byteorder): - """ Initialize a new instance of the SunspecDecoder + """Initialize a new instance of the SunspecDecoder .. note:: This is always set to big endian byte order as specified in the protocol. @@ -196,7 +188,7 @@ def __init__(self, payload, byteorder): BinaryPayloadDecoder.__init__(self, payload, my_byteorder) def decode_string(self, size=1): - """ Decodes a string from the buffer + """Decode a string from the buffer :param size: The size of the string to decode """ @@ -206,10 +198,10 @@ def decode_string(self, size=1): class SunspecClient: - """ SunSpec client. """ + """SunSpec client.""" - def __init__(self, client): # pylint: disable=redefined-outer-name - """ Initialize a new instance of the client + def __init__(self, client): # pylint: disable=redefined-outer-name + """Initialize a new instance of the client :param client: The modbus client to use """ @@ -217,7 +209,7 @@ def __init__(self, client): # pylint: disable=redefined-outer-name self.offset = SunspecOffsets.CommonBlock def initialize(self): - """ Initialize the underlying client values + """Initialize the underlying client values :returns: True if successful, false otherwise """ @@ -229,29 +221,28 @@ def initialize(self): return decoder.decode_32bit_uint() == SunspecIdentifier.Sunspec def get_common_block(self): - """ Read and return the sunspec common information - block. + """Read and return the sunspec common information block. :returns: A dictionary of the common block information """ length = SunspecOffsets.CommonBlockLength decoder = self.get_device_block(self.offset, length) return { - 'SunSpec_ID': decoder.decode_32bit_uint(), # noqa E221 - 'SunSpec_DID': decoder.decode_16bit_uint(), # noqa E221 - 'SunSpec_Length': decoder.decode_16bit_uint(), # noqa E221 - 'Manufacturer': decoder.decode_string(size=32), # noqa E221 - 'Model': decoder.decode_string(size=32), # noqa E221 - 'Options': decoder.decode_string(size=16), # noqa E221 - 'Version': decoder.decode_string(size=16), # noqa E221 - 'SerialNumber': decoder.decode_string(size=32), # noqa E221 - 'DeviceAddress': decoder.decode_16bit_uint(), # noqa E221 - 'Next_DID': decoder.decode_16bit_uint(), # noqa E221 - 'Next_DID_Length': decoder.decode_16bit_uint(), # noqa E221 + 'SunSpec_ID': decoder.decode_32bit_uint(), # noqa E221 + 'SunSpec_DID': decoder.decode_16bit_uint(), # noqa E221 + 'SunSpec_Length': decoder.decode_16bit_uint(), # noqa E221 + 'Manufacturer': decoder.decode_string(size=32), # noqa E221 + 'Model': decoder.decode_string(size=32), # noqa E221 + 'Options': decoder.decode_string(size=16), # noqa E221 + 'Version': decoder.decode_string(size=16), # noqa E221 + 'SerialNumber': decoder.decode_string(size=32), # noqa E221 + 'DeviceAddress': decoder.decode_16bit_uint(), # noqa E221 + 'Next_DID': decoder.decode_16bit_uint(), # noqa E221 + 'Next_DID_Length': decoder.decode_16bit_uint(), # noqa E221 } def get_device_block(self, offset, size): - """ A helper method to retrieve the next device block + """Retrieve the next device block .. note:: We will read 2 more registers so that we have the information for the next block. @@ -266,8 +257,7 @@ def get_device_block(self, offset, size): return SunspecDecoder.fromRegisters(response.registers) def get_all_device_blocks(self): - """ Retrieve all the available blocks in the supplied - sunspec device. + """Retrieve all the available blocks in the supplied sunspec device. .. note:: Since we do not know how to decode the available blocks, this returns a list of dictionaries of the form: @@ -305,7 +295,7 @@ def get_all_device_blocks(self): for key, value in common.iteritems(): if key == "SunSpec_DID": value = SunspecModel.lookup(value) - print("{:<20}: {}".format(key, value)) # pylint: disable=consider-using-f-string + print("{:<20}: {}".format(key, value)) # pylint: disable=consider-using-f-string # print out all the available device blocks blocks = client.get_all_device_blocks() diff --git a/examples/contrib/thread_safe_datastore.py b/examples/contrib/thread_safe_datastore.py index f74cad64f..cb903d6a1 100644 --- a/examples/contrib/thread_safe_datastore.py +++ b/examples/contrib/thread_safe_datastore.py @@ -1,40 +1,42 @@ -""" Thread safe datastore. """ +"""Thread safe datastore.""" import threading from contextlib import contextmanager from pymodbus.datastore.store import BaseModbusDataBlock class ContextWrapper: - """ This is a simple wrapper around enter - and exit functions that conforms to the python - context manager protocol: + """This is a simple wrapper around enter and exit functions + + that conforms to the python context manager protocol: with ContextWrapper(enter, leave): do_something() """ def __init__(self, enter=None, leave=None, factory=None): + """Initialize.""" self._enter = enter self._leave = leave self._factory = factory def __enter__(self): - if self.enter: # pylint: disable=no-member + """Do on enter.""" + if self.enter: # pylint: disable=no-member self._enter() return self if not self._factory else self._factory() def __exit__(self, *args): + """Do on exit.""" if self._leave: self._leave() class ReadWriteLock: - """ This reader writer lock guarantees write order, but not - read order and is generally biased towards allowing writes - if they are available to prevent starvation. + """This reader writer lock guarantees write order, + but not read order and is generally biased towards allowing writes + if they are available to prevent starvation. TODO: - * allow user to choose between read/write/random biasing - currently write biased - read biased allow N readers in queue @@ -42,8 +44,7 @@ class ReadWriteLock: """ def __init__(self): - """ Initializes a new instance of the ReadWriteLock - """ + """Initialize a new instance of the ReadWriteLock""" self.queue = [] # the current writer queue self.lock = threading.Lock() # the underlying condition lock self.read_condition = threading.Condition(self.lock) # the single reader condition @@ -51,15 +52,13 @@ def __init__(self): self.writer = False # is there a current writer def __is_pending_writer(self): - """ Internal is pending writer. """ + """Check is pending writer.""" return (self.writer # if there is a current writer or (self.queue # or if there is a waiting writer and (self.queue[0] != self.read_condition))) def acquire_reader(self): - """ Notifies the lock that a new reader is requesting - the underlying resource. - """ + """Notify the lock that a new reader is requesting the underlying resource.""" with self.lock: if self.__is_pending_writer(): # if there are existing writers waiting if self.read_condition not in self.queue: # do not pollute the queue with readers @@ -71,13 +70,11 @@ def acquire_reader(self): self.readers += 1 # update the current number of readers def acquire_writer(self): - """ Notifies the lock that a new writer is requesting - the underlying resource. - """ + """Notify the lock that a new writer is requesting the underlying resource.""" with self.lock: if self.writer or self.readers: condition = threading.Condition(self.lock) - # create a condition just for this writer + # create a condition just for this writer self.queue.append(condition) # and put it on the waiting queue while self.writer or self.readers: # until the write lock is free condition.wait(1) @@ -85,18 +82,14 @@ def acquire_writer(self): self.writer = True # stop other writers from operating def release_reader(self): - """ Notifies the lock that an existing reader is - finished with the underlying resource. - """ + """Notify the lock that an existing reader is finished with the underlying resource.""" with self.lock: self.readers = max(0, self.readers - 1) # readers should never go below 0 if not self.readers and self.queue: # if there are no active readers self.queue[0].notify_all() # then notify any waiting writers def release_writer(self): - """ Notifies the lock that an existing writer is - finished with the underlying resource. - """ + """Notify the lock that an existing writer is finished with the underlying resource.""" with self.lock: self.writer = False # give up current writing handle if self.queue: # if someone is waiting in the queue @@ -106,11 +99,10 @@ def release_writer(self): @contextmanager def get_reader_lock(self): - """ Wrap some code with a reader lock using the - python context manager protocol:: + """Wrap some code with a reader lock using the python context manager protocol:: - with rwlock.get_reader_lock(): - do_read_operation() + with rwlock.get_reader_lock(): + do_read_operation() """ try: self.acquire_reader() @@ -120,11 +112,10 @@ def get_reader_lock(self): @contextmanager def get_writer_lock(self): - """ Wrap some code with a writer lock using the - python context manager protocol:: + """Wrap some code with a writer lock using the python context manager protocol:: - with rwlock.get_writer_lock(): - do_read_operation() + with rwlock.get_writer_lock(): + do_read_operation() """ try: self.acquire_writer() @@ -134,8 +125,9 @@ def get_writer_lock(self): class ThreadSafeDataBlock(BaseModbusDataBlock): - """ This is a simple decorator for a data block. This allows - a user to inject an existing data block which can then be + """This is a simple decorator for a data block. + + This allows a user to inject an existing data block which can then be safely operated on from multiple cocurrent threads. It should be noted that the choice was made to lock around the @@ -145,7 +137,7 @@ class ThreadSafeDataBlock(BaseModbusDataBlock): """ def __init__(self, block): - """ Initialize a new thread safe decorator + """Initialize a new thread safe decorator :param block: The block to decorate """ @@ -153,7 +145,7 @@ def __init__(self, block): self.block = block def validate(self, address, count=1): - """ Checks to see if the request is in range + """Check to see if the request is in range :param address: The starting address :param count: The number of values to test for @@ -163,7 +155,7 @@ def validate(self, address, count=1): return self.block.validate(address, count) def getValues(self, address, count=1): - """ Returns the requested values of the datastore + """Return the requested values of the datastore :param address: The starting address :param count: The number of values to retrieve @@ -173,7 +165,7 @@ def getValues(self, address, count=1): return self.block.getValues(address, count) def setValues(self, address, values): - """ Sets the requested values of the datastore + """Set the requested values of the datastore :param address: The starting address :param values: The new values to be set @@ -182,37 +174,37 @@ def setValues(self, address, values): return self.block.setValues(address, values) -if __name__ == "__main__": # pylint: disable=too-complex +if __name__ == "__main__": # pylint: disable=too-complex class AtomicCounter: - """ Atomic counter. """ + """Atomic counter.""" def __init__(self, **kwargs): - """ Init. """ + """Init.""" self.counter = kwargs.get('start', 0) self.finish = kwargs.get('finish', 1000) self.lock = threading.Lock() def increment(self, count=1): - """ Increment. """ + """Increment.""" with self.lock: self.counter += count def is_running(self): - """ Is running. """ + """Is running.""" return self.counter <= self.finish locker = ReadWriteLock() readers, writers = AtomicCounter(), AtomicCounter() def read(): - """ Read. """ + """Read.""" while writers.is_running() and readers.is_running(): with locker.get_reader_lock(): readers.increment() def write(): - """ Write. """ + """Write.""" while writers.is_running() and readers.is_running(): with locker.get_writer_lock(): writers.increment() diff --git a/ez_setup.py b/ez_setup.py index 25c103123..0a1b79d64 100755 --- a/ez_setup.py +++ b/ez_setup.py @@ -1,5 +1,8 @@ #!python +"""Ez_setup""" from __future__ import print_function +import os +import sys """Bootstrap setuptools installation If you want to use setuptools in your package's setup.py, just include this @@ -14,10 +17,9 @@ This file can also be run as a script to install or upgrade setuptools. """ -import sys DEFAULT_VERSION = "0.6c11" -DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] #NOSONAR +DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] # NOSONAR md5_data = { 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', @@ -64,12 +66,14 @@ 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a', } -import sys, os -try: from hashlib import md5 -except ImportError: from md5 import md5 +try: + from hashlib import md5 +except ImportError: + from md5 import md5 def print_error(msg, **kwargs): + """Print error.""" print(msg, file=sys.stderr, **kwargs) @@ -81,6 +85,7 @@ def _validate_md5(egg_name, data): sys.exit(2) return data + def use_setuptools( version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, download_delay=15 @@ -97,23 +102,26 @@ def use_setuptools( an attempt to abort the calling script. """ was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules + def do_download(): egg = download_setuptools(version, download_base, to_dir, download_delay) sys.path.insert(0, egg) - import setuptools; setuptools.bootstrap_install_from = egg + import setuptools + setuptools.bootstrap_install_from = egg try: import pkg_resources except ImportError: - return do_download() + return do_download() try: - pkg_resources.require("setuptools>="+version); return + pkg_resources.require("setuptools>=" + version) + return except pkg_resources.VersionConflict as e: if was_imported: print_error(( - "The required version of setuptools (>=%s) is not available, and\n" - "can't be installed while this script is running. Please install\n" - " a more recent version first, using 'easy_install -U setuptools'." - "\n\n(Currently using %r)" + "The required version of setuptools (>=%s) is not available, and\n" + "can't be installed while this script is running. Please install\n" + " a more recent version first, using 'easy_install -U setuptools'." + "\n\n(Currently using %r)" ) % (version, e.args[0])) sys.exit(2) except pkg_resources.DistributionNotFound: @@ -122,6 +130,7 @@ def do_download(): del pkg_resources, sys.modules['pkg_resources'] # reload ok return do_download() + def download_setuptools( version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, delay = 15 @@ -133,8 +142,10 @@ def download_setuptools( with a '/'). `to_dir` is the directory where the egg will be downloaded. `delay` is the number of seconds to pause before an actual download attempt. """ - import urllib.request, urllib.error, urllib.parse, shutil - egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) + import urllib.request + import urllib.error + import urllib.parse + egg_name = "setuptools-%s-py%s.egg" % (version, sys.version[:3]) url = download_base + egg_name saveto = os.path.join(to_dir, egg_name) src = dst = None @@ -156,54 +167,25 @@ def download_setuptools( and place it in this directory before rerunning this script.) ---------------------------------------------------------------------------""", - version, download_base, delay, url - ); from time import sleep; sleep(delay) + version, download_base, delay, url + ) + from time import sleep + sleep(delay) log.warn("Downloading %s", url) src = urllib.request.urlopen(url) # Read/write all in one block, so we don't create a corrupt file # if the download is interrupted. data = _validate_md5(egg_name, src.read()) - dst = open(saveto,"wb"); dst.write(data) + dst = open(saveto, "wb") + dst.write(data) finally: - if src: src.close() - if dst: dst.close() + if src: + src.close() + if dst: + dst.close() return os.path.realpath(saveto) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def main(argv, version=DEFAULT_VERSION): """Install or upgrade setuptools and EasyInstall""" try: @@ -212,21 +194,21 @@ def main(argv, version=DEFAULT_VERSION): egg = None try: egg = download_setuptools(version, delay=0) - sys.path.insert(0,egg) + sys.path.insert(0, egg) from setuptools.command.easy_install import main - return main(list(argv)+[egg]) # we're done here + return main(list(argv) + [egg]) # we're done here finally: if egg and os.path.exists(egg): os.unlink(egg) else: if setuptools.__version__ == '0.0.1': print(( - "You have an obsolete version of setuptools installed. Please\n" - "remove it from your system entirely before rerunning this script." + "You have an obsolete version of setuptools installed. Please\n" + "remove it from your system entirely before rerunning this script." ), file=sys.stderr) sys.exit(2) - req = "setuptools>="+version + req = "setuptools>=" + version import pkg_resources try: pkg_resources.require(req) @@ -235,24 +217,24 @@ def main(argv, version=DEFAULT_VERSION): from setuptools.command.easy_install import main except ImportError: from easy_install import main - main(list(argv)+[download_setuptools(delay=0)]) - sys.exit(0) # try to force an exit + main(list(argv) + [download_setuptools(delay=0)]) + sys.exit(0) # try to force an exit else: if argv: from setuptools.command.easy_install import main main(argv) else: - print("Setuptools version",version,"or greater has been installed.") + print("Setuptools version", version, "or greater has been installed.") print('(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)') + def update_md5(filenames): """Update our built-in md5 registry""" - import re for name in filenames: base = os.path.basename(name) - f = open(name,'rb') + f = open(name, 'rb') md5_data[base] = md5(f.read()).hexdigest() f.close() @@ -262,7 +244,9 @@ def update_md5(filenames): import inspect srcfile = inspect.getsourcefile(sys.modules[__name__]) - f = open(srcfile, 'rb'); src = f.read(); f.close() + f = open(srcfile, 'rb') + src = f.read() + f.close() match = re.search("\nmd5_data = {\n([^}]+)}", src) if not match: @@ -270,19 +254,13 @@ def update_md5(filenames): sys.exit(2) src = src[:match.start(1)] + repl + src[match.end(1):] - f = open(srcfile,'w') + f = open(srcfile, 'w') f.write(src) f.close() -if __name__=='__main__': - if len(sys.argv)>2 and sys.argv[1]=='--md5update': +if __name__ == '__main__': + if len(sys.argv) > 2 and sys.argv[1] == '--md5update': update_md5(sys.argv[2:]) else: main(sys.argv[1:]) - - - - - - diff --git a/pymodbus/__init__.py b/pymodbus/__init__.py index d3e62134f..6d987bbf0 100644 --- a/pymodbus/__init__.py +++ b/pymodbus/__init__.py @@ -1,5 +1,4 @@ -""" Pymodbus: Modbus Protocol Implementation ------------------------------------------ +"""Pymodbus: Modbus Protocol Implementation. TwistedModbus is built on top of the code developed by: @@ -14,10 +13,10 @@ from logging import NullHandler as __null import pymodbus.version as __version __version__ = __version.version.short() -__author__ = 'Galen Collins' +__author__ = 'Galen Collins' __maintainer__ = 'dhoomakethu' -#---------------------------------------------------------------------------# -# Block unhandled logging -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Block unhandled logging +# ---------------------------------------------------------------------------# __logging.getLogger(__name__).addHandler(__null()) diff --git a/pymodbus/bit_read_message.py b/pymodbus/bit_read_message.py index 4dcab533b..27d14bd1f 100644 --- a/pymodbus/bit_read_message.py +++ b/pymodbus/bit_read_message.py @@ -1,7 +1,4 @@ -""" Bit Reading Request/Response messages --------------------------------------- - -""" +"""Bit Reading Request/Response messages.""" import struct from pymodbus.pdu import ModbusRequest from pymodbus.pdu import ModbusResponse @@ -10,12 +7,12 @@ class ReadBitsRequestBase(ModbusRequest): - """ Base class for Messages Requesting bit values """ + """Base class for Messages Requesting bit values.""" _rtu_frame_size = 8 def __init__(self, address, count, **kwargs): - """ Initializes the read request data + """Initialize the read request data. :param address: The start address to read from :param count: The number of bits after 'address' to read @@ -25,32 +22,34 @@ def __init__(self, address, count, **kwargs): self.count = count def encode(self): - """ Encodes a request pdu + """Encode a request pdu. :returns: The encoded pdu """ return struct.pack('>HH', self.address, self.count) def decode(self, data): - """ Decodes a request pdu + """Decode a request pdu. :param data: The packet data to decode """ self.address, self.count = struct.unpack('>HH', data) def get_response_pdu_size(self): - """ Func_code (1 byte) + Byte Count(1 byte) + Quantity of Coils (n Bytes)/8, + """Get response pdu size. + + Func_code (1 byte) + Byte Count(1 byte) + Quantity of Coils (n Bytes)/8, if the remainder is different of 0 then N = N+1 :return: """ - count = self.count//8 + count = self.count // 8 if self.count % 8: count += 1 return 1 + 1 + count def __str__(self): - """ Returns a string representation of the instance + """Return a string representation of the instance. :returns: A string representation of the instance """ @@ -58,12 +57,12 @@ def __str__(self): class ReadBitsResponseBase(ModbusResponse): - """ Base class for Messages responding to bit-reading values """ + """Base class for Messages responding to bit-reading values.""" _rtu_byte_count_pos = 2 def __init__(self, values, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param values: The requested values to be returned """ @@ -71,7 +70,7 @@ def __init__(self, values, **kwargs): self.bits = values or [] def encode(self): - """ Encodes response pdu + """Encode response pdu. :returns: The encoded packet message """ @@ -80,30 +79,30 @@ def encode(self): return packet def decode(self, data): - """ Decodes response pdu + """Decode response pdu. :param data: The packet data to decode """ - self.byte_count = int(data[0]) # pylint: disable=attribute-defined-outside-init + self.byte_count = int(data[0]) # pylint: disable=attribute-defined-outside-init self.bits = unpack_bitstring(data[1:]) - def setBit(self, address, value=1): # pylint: disable=invalid-name - """ Helper function to set the specified bit + def setBit(self, address, value=1): # pylint: disable=invalid-name + """Set the specified bit. :param address: The bit to set :param value: The value to set the bit to """ self.bits[address] = bool(value) - def resetBit(self, address): # pylint: disable=invalid-name - """ Helper function to set the specified bit to 0 + def resetBit(self, address): # pylint: disable=invalid-name + """Set the specified bit to 0. :param address: The bit to reset """ self.setBit(address, 0) - def getBit(self, address): # pylint: disable=invalid-name - """ Helper function to get the specified bit's value + def getBit(self, address): # pylint: disable=invalid-name + """Get the specified bit's value. :param address: The bit to query :returns: The value of the requested bit @@ -111,7 +110,7 @@ def getBit(self, address): # pylint: disable=invalid-name return self.bits[address] def __str__(self): - """ Returns a string representation of the instance + """Return a string representation of the instance. :returns: A string representation of the instance """ @@ -119,16 +118,18 @@ def __str__(self): class ReadCoilsRequest(ReadBitsRequestBase): - """ This function code is used to read from 1 to 2000(0x7d0) contiguous status - of coils in a remote device. The Request PDU specifies the starting + """This function code is used to read from 1 to 2000(0x7d0) contiguous status of coils in a remote device. + + The Request PDU specifies the starting address, ie the address of the first coil specified, and the number of coils. In the PDU Coils are addressed starting at zero. Therefore coils numbered 1-16 are addressed as 0-15. """ + function_code = 1 def __init__(self, address=None, count=None, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param address: The address to start reading from :param count: The number of bits to read @@ -136,7 +137,7 @@ def __init__(self, address=None, count=None, **kwargs): ReadBitsRequestBase.__init__(self, address, count, **kwargs) def execute(self, context): - """ Run a read coils request against a datastore + """Run a read coils request against a datastore. Before running the request, we make sure that the request is in the max valid range (0x001-0x7d0). Next we make sure that the @@ -154,8 +155,9 @@ def execute(self, context): class ReadCoilsResponse(ReadBitsResponseBase): - """ The coils in the response message are packed as one coil per bit of - the data field. Status is indicated as 1= ON and 0= OFF. The LSB of the + """The coils in the response message are packed as one coil per bit of the data field. + + Status is indicated as 1= ON and 0= OFF. The LSB of the first data byte contains the output addressed in the query. The other coils follow toward the high order end of this byte, and from low order to high order in subsequent bytes. @@ -165,10 +167,11 @@ class ReadCoilsResponse(ReadBitsResponseBase): (toward the high order end of the byte). The Byte Count field specifies the quantity of complete bytes of data. """ + function_code = 1 def __init__(self, values=None, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param values: The request values to respond with """ @@ -176,16 +179,18 @@ def __init__(self, values=None, **kwargs): class ReadDiscreteInputsRequest(ReadBitsRequestBase): - """ This function code is used to read from 1 to 2000(0x7d0) contiguous status - of discrete inputs in a remote device. The Request PDU specifies the + """This function code is used to read from 1 to 2000(0x7d0). + + Contiguous status of discrete inputs in a remote device. The Request PDU specifies the starting address, ie the address of the first input specified, and the number of inputs. In the PDU Discrete Inputs are addressed starting at zero. Therefore Discrete inputs numbered 1-16 are addressed as 0-15. """ + function_code = 2 def __init__(self, address=None, count=None, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param address: The address to start reading from :param count: The number of bits to read @@ -193,7 +198,7 @@ def __init__(self, address=None, count=None, **kwargs): ReadBitsRequestBase.__init__(self, address, count, **kwargs) def execute(self, context): - """ Run a read discrete input request against a datastore + """Run a read discrete input request against a datastore. Before running the request, we make sure that the request is in the max valid range (0x001-0x7d0). Next we make sure that the @@ -211,8 +216,9 @@ def execute(self, context): class ReadDiscreteInputsResponse(ReadBitsResponseBase): - """ The discrete inputs in the response message are packed as one input per - bit of the data field. Status is indicated as 1= ON; 0= OFF. The LSB of + """The discrete inputs in the response message are packed as one input per bit of the data field. + + Status is indicated as 1= ON; 0= OFF. The LSB of the first data byte contains the input addressed in the query. The other inputs follow toward the high order end of this byte, and from low order to high order in subsequent bytes. @@ -222,18 +228,20 @@ class ReadDiscreteInputsResponse(ReadBitsResponseBase): (toward the high order end of the byte). The Byte Count field specifies the quantity of complete bytes of data. """ + function_code = 2 def __init__(self, values=None, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param values: The request values to respond with """ ReadBitsResponseBase.__init__(self, values, **kwargs) -#---------------------------------------------------------------------------# -# Exported symbols -#---------------------------------------------------------------------------# + +# ---------------------------------------------------------------------------# +# Exported symbols +# ---------------------------------------------------------------------------# __all__ = [ "ReadCoilsRequest", "ReadCoilsResponse", "ReadDiscreteInputsRequest", "ReadDiscreteInputsResponse", diff --git a/pymodbus/bit_write_message.py b/pymodbus/bit_write_message.py index 5ed86dcdc..8263f6732 100644 --- a/pymodbus/bit_write_message.py +++ b/pymodbus/bit_write_message.py @@ -1,5 +1,4 @@ -""" Bit Writing Request/Response ------------------------------- +"""Bit Writing Request/Response. TODO write mask request/response """ @@ -10,18 +9,17 @@ from pymodbus.pdu import ModbusExceptions as merror from pymodbus.utilities import pack_bitstring, unpack_bitstring -#---------------------------------------------------------------------------# -# Local Constants -#---------------------------------------------------------------------------# -# These are defined in the spec to turn a coil on/off -#---------------------------------------------------------------------------# -_turn_coil_on = struct.pack(">H", ModbusStatus.On) +# ---------------------------------------------------------------------------# +# Local Constants +# ---------------------------------------------------------------------------# +# These are defined in the spec to turn a coil on/off +# ---------------------------------------------------------------------------# +_turn_coil_on = struct.pack(">H", ModbusStatus.On) _turn_coil_off = struct.pack(">H", ModbusStatus.Off) class WriteSingleCoilRequest(ModbusRequest): - """ This function code is used to write a single output to either ON or OFF - in a remote device. + """This function code is used to write a single output to either ON or OFF in a remote device. The requested ON/OFF state is specified by a constant in the request data field. A value of FF 00 hex requests the output to be ON. A value @@ -35,11 +33,12 @@ class WriteSingleCoilRequest(ModbusRequest): 0X0000 requests the coil to be off. All other values are illegal and will not affect the coil. """ + function_code = 5 _rtu_frame_size = 8 def __init__(self, address=None, value=None, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param address: The variable address to write :param value: The value to write at address @@ -49,18 +48,19 @@ def __init__(self, address=None, value=None, **kwargs): self.value = bool(value) def encode(self): - """ Encodes write coil request + """Encode write coil request. :returns: The byte encoded message """ - result = struct.pack('>H', self.address) + result = struct.pack('>H', self.address) if self.value: result += _turn_coil_on - else: result += _turn_coil_off + else: + result += _turn_coil_off return result def decode(self, data): - """ Decodes a write coil request + """Decode a write coil request. :param data: The packet data to decode """ @@ -68,12 +68,12 @@ def decode(self, data): self.value = (value == ModbusStatus.On) def execute(self, context): - """ Run a write coil request against a datastore + """Run a write coil request against a datastore. :param context: The datastore to request from :returns: The populated response or exception message """ - #if self.value not in [ModbusStatus.Off, ModbusStatus.On]: + # if self.value not in [ModbusStatus.Off, ModbusStatus.On]: # return self.doException(merror.IllegalValue) if not context.validate(self.function_code, self.address, 1): return self.doException(merror.IllegalAddress) @@ -82,14 +82,16 @@ def execute(self, context): values = context.getValues(self.function_code, self.address, 1) return WriteSingleCoilResponse(self.address, values[0]) - def get_response_pdu_size(self): # pylint: disable=no-self-use - """ Func_code (1 byte) + Output Address (2 byte) + Output Value (2 Bytes) + def get_response_pdu_size(self): # pylint: disable=no-self-use + """Get response pdu size. + + Func_code (1 byte) + Output Address (2 byte) + Output Value (2 Bytes) :return: """ return 1 + 2 + 2 def __str__(self): - """ Returns a string representation of the instance + """Return a string representation of the instance. :return: A string representation of the instance """ @@ -97,14 +99,16 @@ def __str__(self): class WriteSingleCoilResponse(ModbusResponse): - """ The normal response is an echo of the request, returned after the coil - state has been written. + """The normal response is an echo of the request. + + Returned after the coil state has been written. """ + function_code = 5 _rtu_frame_size = 8 def __init__(self, address=None, value=None, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param address: The variable address written to :param value: The value written at address @@ -114,18 +118,19 @@ def __init__(self, address=None, value=None, **kwargs): self.value = value def encode(self): - """ Encodes write coil response + """Encode write coil response. :return: The byte encoded message """ - result = struct.pack('>H', self.address) + result = struct.pack('>H', self.address) if self.value: result += _turn_coil_on - else: result += _turn_coil_off + else: + result += _turn_coil_off return result def decode(self, data): - """ Decodes a write coil response + """Decode a write coil response. :param data: The packet data to decode """ @@ -133,7 +138,7 @@ def decode(self, data): self.value = (value == ModbusStatus.On) def __str__(self): - """ Returns a string representation of the instance + """Return a string representation of the instance. :returns: A string representation of the instance """ @@ -141,8 +146,9 @@ def __str__(self): class WriteMultipleCoilsRequest(ModbusRequest): - """ This function code is used to force each coil in a sequence of coils to - either ON or OFF in a remote device. The Request PDU specifies the coil + """This function code is used to forcea sequence of coils. + + To either ON or OFF in a remote device. The Request PDU specifies the coil references to be forced. Coils are addressed starting at zero. Therefore coil numbered 1 is addressed as 0. @@ -150,11 +156,12 @@ class WriteMultipleCoilsRequest(ModbusRequest): data field. A logical '1' in a bit position of the field requests the corresponding output to be ON. A logical '0' requests it to be OFF." """ + function_code = 15 _rtu_byte_count_pos = 6 def __init__(self, address=None, values=None, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param address: The starting request address :param values: The values to write @@ -165,22 +172,22 @@ def __init__(self, address=None, values=None, **kwargs): values = [] elif not hasattr(values, '__iter__'): values = [values] - self.values = values + self.values = values self.byte_count = (len(self.values) + 7) // 8 def encode(self): - """ Encodes write coils request + """Encode write coils request. :returns: The byte encoded message """ - count = len(self.values) + count = len(self.values) self.byte_count = (count + 7) // 8 - packet = struct.pack('>HHB', self.address, count, self.byte_count) + packet = struct.pack('>HHB', self.address, count, self.byte_count) packet += pack_bitstring(self.values) return packet def decode(self, data): - """ Decodes a write coils request + """Decode a write coils request. :param data: The packet data to decode """ @@ -189,7 +196,7 @@ def decode(self, data): self.values = values[:count] def execute(self, context): - """ Run a write coils request against a datastore + """Run a write coils request against a datastore. :param context: The datastore to request from :returns: The populated response or exception message @@ -206,29 +213,33 @@ def execute(self, context): return WriteMultipleCoilsResponse(self.address, count) def __str__(self): - """ Returns a string representation of the instance + """Return a string representation of the instance. :returns: A string representation of the instance """ params = (self.address, len(self.values)) - return "WriteNCoilRequest (%d) => %d " % params # pylint: disable=consider-using-f-string + return "WriteNCoilRequest (%d) => %d " % params # pylint: disable=consider-using-f-string + + def get_response_pdu_size(self): # pylint: disable=no-self-use + """Get response pdu size. - def get_response_pdu_size(self): # pylint: disable=no-self-use - """ Func_code (1 byte) + Output Address (2 byte) + Quantity of Outputs (2 Bytes) + Func_code (1 byte) + Output Address (2 byte) + Quantity of Outputs (2 Bytes) :return: """ return 1 + 2 + 2 class WriteMultipleCoilsResponse(ModbusResponse): - """ The normal response returns the function code, starting address, and - quantity of coils forced. + """The normal response returns the function code. + + Starting address, and quantity of coils forced. """ + function_code = 15 _rtu_frame_size = 8 def __init__(self, address=None, count=None, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param address: The starting variable address written to :param count: The number of values written @@ -238,29 +249,30 @@ def __init__(self, address=None, count=None, **kwargs): self.count = count def encode(self): - """ Encodes write coils response + """Encode write coils response. :returns: The byte encoded message """ return struct.pack('>HH', self.address, self.count) def decode(self, data): - """ Decodes a write coils response + """Decode a write coils response. :param data: The packet data to decode """ self.address, self.count = struct.unpack('>HH', data) def __str__(self): - """ Returns a string representation of the instance + """Return a string representation of the instance. :returns: A string representation of the instance """ return f"WriteNCoilResponse({self.address}, {self.count})" -#---------------------------------------------------------------------------# -# Exported symbols -#---------------------------------------------------------------------------# + +# ---------------------------------------------------------------------------# +# Exported symbols +# ---------------------------------------------------------------------------# __all__ = [ "WriteSingleCoilRequest", "WriteSingleCoilResponse", "WriteMultipleCoilsRequest", "WriteMultipleCoilsResponse", diff --git a/pymodbus/client/__init__.py b/pymodbus/client/__init__.py index e69de29bb..867de7e12 100644 --- a/pymodbus/client/__init__.py +++ b/pymodbus/client/__init__.py @@ -0,0 +1 @@ +"""Initialize client.""" diff --git a/pymodbus/client/asynchronous/__init__.py b/pymodbus/client/asynchronous/__init__.py index 77164e4ed..258d4644c 100644 --- a/pymodbus/client/asynchronous/__init__.py +++ b/pymodbus/client/asynchronous/__init__.py @@ -1,5 +1,4 @@ -""" Async Modbus Client implementation based on Twisted, tornado and asyncio ------------------------------------------------------------------------- +"""Async Modbus Client implementation based on Twisted, tornado and asyncio Example run:: @@ -28,14 +27,15 @@ # and future.result when using twisted # For asyncio the actual client is returned and event loop is asyncio loop - """ +import logging import importlib.util + +_logger = logging.getLogger(__name__) + if installed := importlib.util.find_spec('twisted'): # Import deprecated async client only if twisted is installed #338 - from pymodbus.client.asynchronous.deprecated.asynchronous import * - import logging - logger = logging.getLogger(__name__) - logger.warning("Importing deprecated clients. " - "Dependency Twisted is Installed") + from pymodbus.client.asynchronous.deprecated.asynchronous import * # noqa F403 + _logger.warning("Importing deprecated clients. " + "Dependency Twisted is Installed") diff --git a/pymodbus/client/asynchronous/async_io/__init__.py b/pymodbus/client/asynchronous/async_io/__init__.py index 1193006a3..2a2d03178 100644 --- a/pymodbus/client/asynchronous/async_io/__init__.py +++ b/pymodbus/client/asynchronous/async_io/__init__.py @@ -1,4 +1,4 @@ -""" Asynchronous framework adapter for asyncio. """ +"""Asynchronous framework adapter for asyncio.""" import logging import socket import asyncio @@ -7,7 +7,6 @@ from serial_asyncio import create_serial_connection from pymodbus.exceptions import ConnectionException from pymodbus.client.asynchronous.mixins import AsyncModbusClientMixin -from pymodbus.client.tls_helper import sslctx_provider from pymodbus.utilities import hexlify_packets from pymodbus.transaction import FifoTransactionManager @@ -17,28 +16,27 @@ class BaseModbusAsyncClientProtocol(AsyncModbusClientMixin): - """ Asyncio specific implementation of asynchronous modbus client protocol. """ + """Asyncio specific implementation of asynchronous modbus client protocol.""" #: Factory that created this instance. factory = None transport = None - async def execute(self, request=None): # pylint: disable=invalid-overridden-method - """ Executes requests asynchronously + async def execute(self, request=None): # pylint: disable=invalid-overridden-method + """Execute requests asynchronously. + :param request: :return: """ req = self._execute(request) - broadcast = (self.broadcast_enable - and not request.unit_id) - if broadcast: + if self.broadcast_enable and not request.unit_id: resp = b'Broadcast write sent - no response expected' else: resp = await asyncio.wait_for(req, timeout=self._timeout) return resp def connection_made(self, transport): - """ Called when a connection is made. + """Call when a connection is made. The transport argument is the transport representing the connection. :param transport: @@ -51,7 +49,7 @@ def connection_made(self, transport): self.factory.protocol_made_connection(self) def connection_lost(self, reason): - """ Called when the connection is lost or closed. + """Call when the connection is lost or closed. The argument is either an exception object or None :param reason: @@ -64,31 +62,26 @@ def connection_lost(self, reason): self.factory.protocol_lost_connection(self) def data_received(self, data): - """ Called when some data is received. + """Call when some data is received. + data is a non-empty bytes object containing the incoming data. :param data: :return: """ self._data_received(data) - def create_future(self): # pylint: disable=no-self-use - """ Helper function to create asyncio Future object. """ + def create_future(self): # pylint: disable=no-self-use + """Create asyncio Future object.""" return asyncio.Future() - def resolve_future(self, my_future, result): - """ Resolves the completed future and sets the result - :param f: - :param result: - :return: - """ - - def resolve_future(self, my_future, result): # pylint: disable=no-self-use - """ Resolve future. """ + def resolve_future(self, my_future, result): # pylint: disable=no-self-use + """Resolve future.""" if not my_future.done(): my_future.set_result(result) - def raise_future(self, my_future, exc): # pylint: disable=no-self-use - """ Sets exception of a future if not done + def raise_future(self, my_future, exc): # pylint: disable=no-self-use + """Set exception of a future if not done + :param f: :param exc: :return: @@ -97,12 +90,12 @@ def raise_future(self, my_future, exc): # pylint: disable=no-self-use my_future.set_exception(exc) def _connection_made(self): - """ Called upon a successful client connection. """ + """Call upon a successful client connection.""" _logger.debug("Client connected to modbus server") self._connected = True def _connection_lost(self, reason): - """ Called upon a client disconnect + """Call upon a client disconnect :param reason: The reason for the disconnect """ @@ -116,17 +109,15 @@ def _connection_lost(self, reason): @property def connected(self): - """ Return connection status. """ + """Return connection status.""" return self._connected def write_transport(self, packet): - """ Write transport. """ + """Write transport.""" return self.transport.write(packet) - def _execute(self, request, **kwargs): #NOSONAR pylint: disable=unused-argument - """ Starts the producer to send the next request to - consumer.write(Frame(request)) - """ + def _execute(self, request, **kwargs): # NOSONAR pylint: disable=unused-argument + """Start the producer to send the next request to consumer.write(Frame(request)).""" request.transaction_id = self.transaction.getNextTID() packet = self.framer.buildPacket(request) txt = f"send: {hexlify_packets(packet)}" @@ -135,7 +126,7 @@ def _execute(self, request, **kwargs): #NOSONAR pylint: disable=unused-argument return self._build_response(request.transaction_id) def _data_received(self, data): - """ Get response, check for valid message, decode result + """Get response, check for valid message, decode result :param data: The data returned from the server """ @@ -144,8 +135,8 @@ def _data_received(self, data): unit = self.framer.decode_data(data).get("unit", 0) self.framer.processIncomingPacket(data, self._handle_response, unit=unit) - def _handle_response(self, reply, **kwargs): # pylint: disable=unused-argument - """ Handle the processed response and link to correct deferred + def _handle_response(self, reply, **kwargs): # pylint: disable=unused-argument + """Handle the processed response and link to correct deferred :param reply: The reply to process """ @@ -158,8 +149,7 @@ def _handle_response(self, reply, **kwargs): # pylint: disable=unused-argument _logger.debug(txt) def _build_response(self, tid): - """ Helper method to return a deferred response - for the current request. + """Return a deferred response for the current request. :param tid: The transaction identifier for this response :returns: A defer linked to the latest request @@ -173,19 +163,21 @@ def _build_response(self, tid): return my_future def close(self): + """Close.""" self.transport.close() self._connected = False class ModbusClientProtocol(BaseModbusAsyncClientProtocol, asyncio.Protocol): - """ Asyncio specific implementation of asynchronous modbus client protocol. """ + """Asyncio specific implementation of asynchronous modbus client protocol.""" #: Factory that created this instance. factory = None transport = None def data_received(self, data): - """ Called when some data is received. + """Call when some data is received. + data is a non-empty bytes object containing the incoming data. :param data: :return: @@ -195,32 +187,37 @@ def data_received(self, data): class ModbusUdpClientProtocol(BaseModbusAsyncClientProtocol, asyncio.DatagramProtocol): - """ Asyncio specific implementation of asynchronous modbus udp client protocol. """ + """Asyncio specific implementation of asynchronous modbus udp client protocol.""" #: Factory that created this instance. factory = None def __init__(self, host=None, port=0, **kwargs): + """Initialize.""" self.host = host self.port = port super().__init__(**kwargs) def datagram_received(self, data, addr): + """Receive datagram.""" self._data_received(data) def write_transport(self, packet): + """Write transport.""" return self.transport.sendto(packet) class ReconnectingAsyncioModbusTcpClient: - """ Client to connect to modbus device repeatedly over TCP/IP. """ + """Client to connect to modbus device repeatedly over TCP/IP.""" + #: Minimum delay in milli seconds before reconnect is attempted. DELAY_MIN_MS = 100 #: Maximum delay in milli seconds before reconnect is attempted. DELAY_MAX_MS = 1000 * 60 * 5 def __init__(self, protocol_class=None, loop=None, **kwargs): - """ Initialize ReconnectingAsyncioModbusTcpClient + """Initialize ReconnectingAsyncioModbusTcpClient + :param protocol_class: Protocol used to talk to modbus device. :param loop: Event loop to use """ @@ -238,11 +235,12 @@ def __init__(self, protocol_class=None, loop=None, **kwargs): self._proto_args = kwargs def reset_delay(self): - """ Resets wait before next reconnect to minimal period. """ + """Reset wait before next reconnect to minimal period.""" self.delay_ms = self.DELAY_MIN_MS async def start(self, host, port=502): - """ Initiates connection to start client + """Initiate connection to start client + :param host: :param port: :return: @@ -257,7 +255,7 @@ async def start(self, host, port=502): return await self._connect() def stop(self): - """ Stops client. """ + """Stop client.""" # prevent reconnect: self.host = None @@ -267,19 +265,19 @@ def stop(self): self.protocol.transport.close() def _create_protocol(self): - """ Factory function to create initialized protocol instance. """ + """Create initialized protocol instance with factory function.""" protocol = self.protocol_class(**self._proto_args) protocol.factory = self return protocol async def _connect(self): - """ Internal connect. """ + """Connect.""" _logger.debug('Connecting.') try: transport, protocol = await self.loop.create_connection( self._create_protocol, self.host, self.port) return transport, protocol - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except txt = f"Failed to connect: {exc}" _logger.warning(txt) asyncio.ensure_future(self._reconnect(), loop=self.loop) @@ -289,7 +287,7 @@ async def _connect(self): self.reset_delay() def protocol_made_connection(self, protocol): - """ Protocol notification of successful connection. """ + """Notify successful connection.""" _logger.info('Protocol made connection.') if not self.connected: self.connected = True @@ -299,7 +297,7 @@ def protocol_made_connection(self, protocol): 'callback called while connected.') def protocol_lost_connection(self, protocol): - """ Protocol notification of lost connection. """ + """Notify lost connection.""" if self.connected: _logger.info('Protocol lost connection.') if protocol is not self.protocol: @@ -313,9 +311,8 @@ def protocol_lost_connection(self, protocol): else: _logger.error('Factory protocol disconnect callback called while not connected.') - async def _reconnect(self): - """ Internal reconnect. """ + """Reconnect.""" txt = f"Waiting {self.delay_ms} ms before next connection attempt." _logger.debug(txt) await asyncio.sleep(self.delay_ms / 1000) @@ -323,11 +320,13 @@ async def _reconnect(self): return await self._connect() + class AsyncioModbusTcpClient: - """ Client to connect to modbus device over TCP/IP. """ + """Client to connect to modbus device over TCP/IP.""" def __init__(self, host=None, port=502, protocol_class=None, loop=None, **kwargs): - """ Initializes Asyncio Modbus Tcp Client + """Initialize Asyncio Modbus Tcp Client + :param host: Host IP address :param port: Port to connect :param protocol_class: Protocol used to talk to modbus device. @@ -347,20 +346,20 @@ def __init__(self, host=None, port=502, protocol_class=None, loop=None, **kwargs self._proto_args = kwargs def stop(self): - """ Stops the client. """ + """Stop the client.""" if self.connected: if self.protocol: if self.protocol.transport: self.protocol.transport.close() def _create_protocol(self): - """ Factory function to create initialized protocol instance. """ + """Create initialized protocol instance with factory function.""" protocol = self.protocol_class(**self._proto_args) protocol.factory = self return protocol async def connect(self): - """ Connect and start Async client. """ + """Connect and start Async client.""" _logger.debug('Connecting.') try: transport, protocol = await self.loop.create_connection( @@ -368,13 +367,13 @@ async def connect(self): txt = f"Connected to {self.host}:{self.port}." _logger.info(txt) return transport, protocol - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except txt = f"Failed to connect: {exc}" _logger.warning(txt) # asyncio.asynchronous(self._reconnect(), loop=self.loop) def protocol_made_connection(self, protocol): - """ Protocol notification of successful connection. """ + """Notify successful connection.""" _logger.info('Protocol made connection.') if not self.connected: self.connected = True @@ -384,7 +383,7 @@ def protocol_made_connection(self, protocol): 'callback called while connected.') def protocol_lost_connection(self, protocol): - """ Protocol notification of lost connection. """ + """Notify lost connection.""" if self.connected: _logger.info('Protocol lost connection.') if protocol is not self.protocol: @@ -401,9 +400,11 @@ def protocol_lost_connection(self, protocol): class ReconnectingAsyncioModbusTlsClient(ReconnectingAsyncioModbusTcpClient): - """ Client to connect to modbus device repeatedly over TLS. """ + """Client to connect to modbus device repeatedly over TLS.""" + def __init__(self, protocol_class=None, loop=None, framer=None, **kwargs): - """ Initialize ReconnectingAsyncioModbusTcpClient + """Initialize ReconnectingAsyncioModbusTcpClient + :param protocol_class: Protocol used to talk to modbus device. :param loop: Event loop to use """ @@ -413,14 +414,14 @@ def __init__(self, protocol_class=None, loop=None, framer=None, **kwargs): ReconnectingAsyncioModbusTcpClient.__init__(self, protocol_class, loop, **kwargs) async def start(self, host, port=802, sslctx=None, server_hostname=None): - """ Initiates connection to start client + """Initiate connection to start client + :param host: :param port: :param sslctx: :param server_hostname: :return: """ - self.sslctx = sslctx if self.sslctx is None: self.sslctx = ssl.create_default_context() @@ -438,11 +439,11 @@ async def _connect(self): try: return await self.loop.create_connection( self._create_protocol, self.host, - self.port, - ssl=self.sslctx, - server_hostname=self.host + self.port, + ssl=self.sslctx, + server_hostname=self.host ) - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except txt = f"Failed to connect: {exc}" _logger.warning(txt) asyncio.ensure_future(self._reconnect(), loop=self.loop) @@ -452,14 +453,15 @@ async def _connect(self): self.reset_delay() def _create_protocol(self): - """ Factory function to create initialized protocol instance. """ + """Create initialized protocol instance with Factory function.""" protocol = self.protocol_class(framer=self.framer, **self._proto_args) protocol.transaction = FifoTransactionManager(self) protocol.factory = self return protocol + class ReconnectingAsyncioModbusUdpClient: - """ Client to connect to modbus device repeatedly over UDP. """ + """Client to connect to modbus device repeatedly over UDP.""" #: Reconnect delay in milli seconds. delay_ms = 0 @@ -468,7 +470,8 @@ class ReconnectingAsyncioModbusUdpClient: DELAY_MAX_MS = 1000 * 60 * 5 def __init__(self, protocol_class=None, loop=None, **kwargs): - """ Initializes ReconnectingAsyncioModbusUdpClient + """Initialize ReconnectingAsyncioModbusUdpClient + :param protocol_class: Protocol used to talk to modbus device. :param loop: Asyncio Event loop """ @@ -487,11 +490,12 @@ def __init__(self, protocol_class=None, loop=None, **kwargs): self.reset_delay() def reset_delay(self): - """ Resets wait before next reconnect to minimal period. """ + """Reset wait before next reconnect to minimal period.""" self.delay_ms = 100 async def start(self, host, port=502): - """ Start reconnecting asynchronous udp client + """Start reconnecting asynchronous udp client + :param host: Host IP to connect :param port: Host port to connect :return: @@ -507,14 +511,13 @@ async def start(self, host, port=502): # We want sockaddr which is a (ip, port) tuple # udp needs ip addresses, not hostnames addrinfo = await self.loop.getaddrinfo(host, - port, - type=DGRAM_TYPE) + port, + type=DGRAM_TYPE) self.host, self.port = addrinfo[0][-1] return await self._connect() - def stop(self): - """ Stops connection and prevents reconnect. """ + """Stop connection and prevents reconnect.""" # prevent reconnect: self.host = None @@ -524,16 +527,15 @@ def stop(self): self.protocol.transport.close() def _create_protocol(self, host=None, port=0): - """ Factory function to create initialized protocol instance. """ + """Create initialized protocol instance with factory function.""" protocol = self.protocol_class(**self._proto_args) protocol.host = host protocol.port = port protocol.factory = self return protocol - async def _connect(self): - """ Internal connect. """ + """Connect.""" _logger.debug('Connecting.') try: endpoint = await self.loop.create_datagram_endpoint( @@ -545,13 +547,13 @@ async def _connect(self): txt = f"Connected to {self.host}:{self.port}." _logger.info(txt) return endpoint - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except txt = f"Failed to connect: {exc}" _logger.warning(txt) asyncio.ensure_future(self._reconnect(), loop=self.loop) def protocol_made_connection(self, protocol): - """ Protocol notification of successful connection. """ + """Notify successful connection.""" _logger.info('Protocol made connection.') if not self.connected: self.connected = True @@ -561,7 +563,7 @@ def protocol_made_connection(self, protocol): 'called while connected.') def protocol_lost_connection(self, protocol): - """ Protocol notification of lost connection. """ + """Notify lost connection.""" if self.connected: _logger.info('Protocol lost connection.') if protocol is not self.protocol: @@ -577,7 +579,7 @@ def protocol_lost_connection(self, protocol): 'callback called while not connected.') async def _reconnect(self): - """ Internal reconnect. """ + """Reconnect.""" txt = f"Waiting {self.delay_ms} ms before next connection attempt." _logger.debug(txt) await asyncio.sleep(self.delay_ms / 1000) @@ -586,10 +588,11 @@ async def _reconnect(self): class AsyncioModbusUdpClient: - """ Client to connect to modbus device over UDP. """ + """Client to connect to modbus device over UDP.""" def __init__(self, host=None, port=502, protocol_class=None, loop=None, **kwargs): - """ Initializes Asyncio Modbus UDP Client + """Initialize Asyncio Modbus UDP Client + :param host: Host IP address :param port: Port to connect :param protocol_class: Protocol used to talk to modbus device. @@ -609,7 +612,7 @@ def __init__(self, host=None, port=502, protocol_class=None, loop=None, **kwargs self._proto_args = kwargs def stop(self): - """ Stops connection. """ + """Stop connection.""" # prevent reconnect: # self.host = None @@ -619,7 +622,7 @@ def stop(self): self.protocol.transport.close() def _create_protocol(self, host=None, port=0): - """ Factory function to create initialized protocol instance. """ + """Create initialized protocol instance with factory function.""" protocol = self.protocol_class(**self._proto_args) protocol.host = host protocol.port = port @@ -627,7 +630,7 @@ def _create_protocol(self, host=None, port=0): return protocol async def connect(self): - """ Connect. """ + """Connect.""" _logger.debug('Connecting.') try: addrinfo = await self.loop.getaddrinfo( @@ -644,13 +647,13 @@ async def connect(self): txt = f"Connected to {self.host}:{self.port}." _logger.info(txt) return endpoint - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except txt = f"Failed to connect: {exc}" _logger.warning(txt) # asyncio.asynchronous(self._reconnect(), loop=self.loop) def protocol_made_connection(self, protocol): - """ Protocol notification of successful connection. """ + """Protocol notification of successful connection.""" _logger.info('Protocol made connection.') if not self.connected: self.connected = True @@ -660,7 +663,7 @@ def protocol_made_connection(self, protocol): 'callback called while connected.') def protocol_lost_connection(self, protocol): - """ Protocol notification of lost connection. """ + """Protocol notification of lost connection.""" if self.connected: _logger.info('Protocol lost connection.') if protocol is not self.protocol: @@ -677,13 +680,15 @@ def protocol_lost_connection(self, protocol): class AsyncioModbusSerialClient: - """ Client to connect to modbus device over serial. """ + """Client to connect to modbus device over serial.""" + transport = None framer = None - def __init__(self, port, protocol_class=None, framer=None, loop=None, + def __init__(self, port, protocol_class=None, framer=None, loop=None, baudrate=9600, bytesize=8, parity='N', stopbits=1, **serial_kwargs): - """ Initializes Asyncio Modbus Serial Client + """Initialize Asyncio Modbus Serial Client + :param port: Port to connect :param protocol_class: Protocol used to talk to modbus device. :param framer: Framer to use @@ -705,25 +710,25 @@ def __init__(self, port, protocol_class=None, framer=None, loop=None, self._connected_event = asyncio.Event() def stop(self): - """ Stops connection. """ + """Stop connection.""" if self._connected: if self.protocol: if self.protocol.transport: self.protocol.transport.close() def _create_protocol(self): - """ Internal create protocol. """ + """Create protocol.""" protocol = self.protocol_class(framer=self.framer) protocol.factory = self return protocol @property def _connected(self): - """ Internal connected. """ + """Connect internal.""" return self._connected_event.is_set() async def connect(self): - """ Connect Async client. """ + """Connect Async client.""" _logger.debug('Connecting.') try: await create_serial_connection( @@ -734,12 +739,12 @@ async def connect(self): await self._connected_event.wait() txt = f"Connected to {self.port}" _logger.info(txt) - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except txt = f"Failed to connect: {exc}" _logger.warning(txt) def protocol_made_connection(self, protocol): - """ Protocol notification of successful connection. """ + """Notify successful connection.""" _logger.info('Protocol made connection.') if not self._connected: self._connected_event.set() @@ -749,7 +754,7 @@ def protocol_made_connection(self, protocol): 'callback called while connected.') def protocol_lost_connection(self, protocol): - """ Protocol notification of lost connection. """ + """Notify lost connection.""" if self._connected: _logger.info('Protocol lost connection.') if protocol is not self.protocol: @@ -766,7 +771,8 @@ def protocol_lost_connection(self, protocol): async def init_tcp_client(proto_cls, loop, host, port, **kwargs): - """ Helper function to initialize tcp client + """Initialize tcp client with helper function. + :param proto_cls: :param loop: :param host: @@ -774,7 +780,6 @@ async def init_tcp_client(proto_cls, loop, host, port, **kwargs): :param kwargs: :return: """ - client = ReconnectingAsyncioModbusTcpClient(protocol_class=proto_cls, loop=loop, **kwargs) await client.start(host, port) @@ -782,8 +787,9 @@ async def init_tcp_client(proto_cls, loop, host, port, **kwargs): async def init_tls_client(proto_cls, loop, host, port, sslctx=None, - server_hostname=None, framer=None, **kwargs): - """ Helper function to initialize tcp client + server_hostname=None, framer=None, **kwargs): + """Initialize tcp client with Helper function. + :param proto_cls: :param loop: :param host: @@ -794,7 +800,6 @@ async def init_tls_client(proto_cls, loop, host, port, sslctx=None, :param kwargs: :return: """ - client = ReconnectingAsyncioModbusTlsClient(protocol_class=proto_cls, loop=loop, framer=framer, **kwargs) @@ -803,7 +808,8 @@ async def init_tls_client(proto_cls, loop, host, port, sslctx=None, async def init_udp_client(proto_cls, loop, host, port, **kwargs): - """ Helper function to initialize UDP client + """Initialize UDP client with helper function. + :param proto_cls: :param loop: :param host: @@ -811,7 +817,6 @@ async def init_udp_client(proto_cls, loop, host, port, **kwargs): :param kwargs: :return: """ - client = ReconnectingAsyncioModbusUdpClient(protocol_class=proto_cls, loop=loop, **kwargs) await client.start(host, port) diff --git a/pymodbus/client/asynchronous/deprecated/__init__.py b/pymodbus/client/asynchronous/deprecated/__init__.py index a1d09b676..d2c0e70af 100644 --- a/pymodbus/client/asynchronous/deprecated/__init__.py +++ b/pymodbus/client/asynchronous/deprecated/__init__.py @@ -4,7 +4,7 @@ WARNING = """ Usage of '{}' is deprecated from 2.0.0 and will be removed in future releases. -Use the new Async Modbus Client implementation based on Twisted, tornado +Use the new Async Modbus Client implementation based on Twisted, tornado and asyncio ------------------------------------------------------------------------ diff --git a/pymodbus/client/asynchronous/deprecated/asynchronous.py b/pymodbus/client/asynchronous/deprecated/asynchronous.py index 4eb0f575b..5647eb91b 100644 --- a/pymodbus/client/asynchronous/deprecated/asynchronous.py +++ b/pymodbus/client/asynchronous/deprecated/asynchronous.py @@ -1,5 +1,4 @@ -""" Implementation of a Modbus Client Using Twisted --------------------------------------------------- +"""Implementation of a Modbus Client Using Twisted. Example run:: @@ -53,12 +52,14 @@ def process(): # --------------------------------------------------------------------------- # # Connected Client Protocols # --------------------------------------------------------------------------- # -class ModbusClientProtocol(protocol.Protocol, ModbusClientMixin): # pragma: no cover - """ This represents the base modbus client protocol. All the application - layer code is deferred to a higher level wrapper. +class ModbusClientProtocol(protocol.Protocol, ModbusClientMixin): # pragma: no cover + """This represents the base modbus client protocol. + + All the application layer code is deferred to a higher level wrapper. """ + def __init__(self, framer=None, **kwargs): - """ Initializes the framer module + """Initialize the framer module. :param framer: The framer to use for the protocol """ @@ -74,13 +75,12 @@ def __init__(self, framer=None, **kwargs): self.transaction = FifoTransactionManager(self, **kwargs) def connectionMade(self): - """ Called upon a successful client connection. - """ + """Call upon a successful client connection.""" _logger.debug("Client connected to modbus server") self._connected = True - def connectionLost(self, reason): # pylint: disable=signature-differs - """ Called upon a client disconnect + def connectionLost(self, reason): # pylint: disable=signature-differs + """Call upon a client disconnect. :param reason: The reason for the disconnect """ @@ -92,7 +92,7 @@ def connectionLost(self, reason): # pylint: disable=signature-differs ConnectionException('Connection lost during request'))) def dataReceived(self, data): - """ Get response, check for valid message, decode result + """Get response, check for valid message, decode result. :param data: The data returned from the server """ @@ -100,15 +100,13 @@ def dataReceived(self, data): self.framer.processIncomingPacket(data, self._handle_response, unit=unit) def execute(self, request): - """ Starts the producer to send the next request to - consumer.write(Frame(request)) - """ + """Start the producer to send the next request to consumer.write(Frame(request)).""" request.transaction_id = self.transaction.getNextTID() self.transport.write(self.framer.buildPacket(request)) return self._build_response(request.transaction_id) def _handle_response(self, reply): - """ Handle the processed response and link to correct deferred + """Handle the processed response and link to correct deferred. :param reply: The reply to process """ @@ -120,8 +118,7 @@ def _handle_response(self, reply): _logger.debug(txt) def _build_response(self, tid): - """ Helper method to return a deferred response - for the current request. + """Return a deferred response for the current request. :param tid: The transaction identifier for this response :returns: A defer linked to the latest request @@ -146,13 +143,14 @@ def _build_response(self, tid): # --------------------------------------------------------------------------- # # Not Connected Client Protocol # --------------------------------------------------------------------------- # -class ModbusUdpClientProtocol(protocol.DatagramProtocol, ModbusClientMixin): # pragma: no cover - """ This represents the base modbus client protocol. All the application - layer code is deferred to a higher level wrapper. +class ModbusUdpClientProtocol(protocol.DatagramProtocol, ModbusClientMixin): # pragma: no cover + """This represents the base modbus client protocol. + + All the application layer code is deferred to a higher level wrapper. """ def __init__(self, framer=None, **kwargs): - """ Initializes the framer module + """Initialize the framer module. :param framer: The framer to use for the protocol """ @@ -164,7 +162,7 @@ def __init__(self, framer=None, **kwargs): self.transaction = FifoTransactionManager(self, **kwargs) def datagramReceived(self, datagram, addr): - """ Get response, check for valid message, decode result + """Get response, check for valid message, decode result. :param data: The data returned from the server :param params: The host parameters sending the datagram @@ -175,16 +173,14 @@ def datagramReceived(self, datagram, addr): self.framer.processIncomingPacket(datagram, self._handle_response, unit=unit) def execute(self, request): - """ Starts the producer to send the next request to - consumer.write(Frame(request)) - """ + """Start the producer to send the next request to consumer.write(Frame(request)).""" request.transaction_id = self.transaction.getNextTID() packet = self.framer.buildPacket(request) self.transport.write(packet) return self._build_response(request.transaction_id) def _handle_response(self, reply): - """ Handle the processed response and link to correct deferred + """Handle the processed response and link to correct deferred. :param reply: The reply to process """ @@ -197,8 +193,7 @@ def _handle_response(self, reply): _logger.debug(txt) def _build_response(self, tid): - """ Helper method to return a deferred response - for the current request. + """Return a deferred response for the current request. :param tid: The transaction identifier for this response :returns: A defer linked to the latest request @@ -211,12 +206,13 @@ def _build_response(self, tid): # --------------------------------------------------------------------------- # # Client Factories # --------------------------------------------------------------------------- # -class ModbusClientFactory(protocol.ReconnectingClientFactory): # pragma: no cover - """ Simple client protocol factory """ +class ModbusClientFactory(protocol.ReconnectingClientFactory): # pragma: no cover + """Simple client protocol factory.""" protocol = ModbusClientProtocol def __init__(self): + """Initialize.""" deprecated(self.__class__.__name__) protocol.ReconnectingClientFactory.__init__(self) diff --git a/pymodbus/client/asynchronous/factory/serial.py b/pymodbus/client/asynchronous/factory/serial.py index 86e9408a1..558bd89cb 100644 --- a/pymodbus/client/asynchronous/factory/serial.py +++ b/pymodbus/client/asynchronous/factory/serial.py @@ -1,5 +1,4 @@ -""" Factory to create asynchronous serial clients based on twisted/tornado/asyncio -""" +"""Factory to create asynchronous serial clients based on twisted/tornado/asyncio.""" from __future__ import unicode_literals from __future__ import absolute_import import logging @@ -16,34 +15,36 @@ def reactor_factory(port, framer, **kwargs): - """Factory to create twisted serial asynchronous client + """Create twisted serial asynchronous client. + :param port: Serial port :param framer: Modbus Framer :param kwargs: :return: event_loop_thread and twisted serial client """ - from twisted.internet import reactor # pylint: disable=import-outside-toplevel - from twisted.internet.serialport import SerialPort # pylint: disable=import-outside-toplevel - from twisted.internet.protocol import ClientFactory # pylint: disable=import-outside-toplevel + from twisted.internet import reactor # pylint: disable=import-outside-toplevel + from twisted.internet.serialport import SerialPort # pylint: disable=import-outside-toplevel + from twisted.internet.protocol import ClientFactory # pylint: disable=import-outside-toplevel class SerialClientFactory(ClientFactory): """Define serial client factory.""" + def __init__(self, framer, proto_cls): - """ Remember things necessary for building a protocols """ + """Remember things necessary for building a protocols.""" self.proto_cls = proto_cls self.framer = framer - def buildProtocol(self): # pylint: disable=arguments-differ - """ Create a protocol and start the reading cycle """ + def buildProtocol(self): # pylint: disable=arguments-differ + """Create a protocol and start the reading cycle-""" proto = self.proto_cls(self.framer) proto.factory = self return proto - class SerialModbusClient(SerialPort): # pylint: disable=abstract-method + class SerialModbusClient(SerialPort): # pylint: disable=abstract-method """Define serial client.""" def __init__(self, framer, *args, **kwargs): - """ Setup the client and start listening on the serial port + """Initialize the client and start listening on the serial port. :param factory: The factory to build clients with """ @@ -52,7 +53,7 @@ def __init__(self, framer, *args, **kwargs): proto = SerialClientFactory(framer, proto_cls).buildProtocol() SerialPort.__init__(self, proto, *args, **kwargs) - proto = EventLoopThread("reactor", reactor.run, reactor.stop, # pylint: disable=no-member + proto = EventLoopThread("reactor", reactor.run, reactor.stop, # pylint: disable=no-member installSignalHandlers=0) ser_client = SerialModbusClient(framer, port, reactor, **kwargs) @@ -60,16 +61,16 @@ def __init__(self, framer, *args, **kwargs): def io_loop_factory(port=None, framer=None, **kwargs): - """ Factory to create Tornado based asynchronous serial clients + """Create Tornado based asynchronous serial clients. + :param port: Serial port :param framer: Modbus Framer :param kwargs: :return: event_loop_thread and tornado future """ - - from tornado.ioloop import IOLoop # pylint: disable=import-outside-toplevel - from pymodbus.client.asynchronous.tornado import (AsyncModbusSerialClient as # pylint: disable=import-outside-toplevel - Client) + from tornado.ioloop import IOLoop # pylint: disable=import-outside-toplevel + from pymodbus.client.asynchronous.tornado import ( # pylint: disable=import-outside-toplevel + AsyncModbusSerialClient as Client) # pylint: disable=import-outside-toplevel ioloop = IOLoop() protocol = EventLoopThread("ioloop", ioloop.start, ioloop.stop) @@ -82,7 +83,8 @@ def io_loop_factory(port=None, framer=None, **kwargs): def async_io_factory(port=None, framer=None, **kwargs): - """ Factory to create asyncio based asynchronous serial clients + """Create asyncio based asynchronous serial clients. + :param port: Serial port :param framer: Modbus Framer :param kwargs: Serial port options @@ -99,7 +101,7 @@ def async_io_factory(port=None, framer=None, **kwargs): coro = client.connect if not loop.is_running(): loop.run_until_complete(coro()) - else:# loop is not asyncio.get_event_loop(): + else: # loop is not asyncio.get_event_loop(): future = asyncio.run_coroutine_threadsafe(coro, loop=loop) future.result() @@ -107,7 +109,8 @@ def async_io_factory(port=None, framer=None, **kwargs): def get_factory(scheduler): - """ Gets protocol factory based on the backend scheduler being used + """Get protocol factory based on the backend scheduler being used. + :param scheduler: REACTOR/IO_LOOP/ASYNC_IO :return: """ @@ -121,4 +124,4 @@ def get_factory(scheduler): txt = f"Allowed Schedulers: {schedulers.REACTOR}, {schedulers.IO_LOOP}, {schedulers.ASYNC_IO}" _logger.warning(txt) txt = f"Invalid Scheduler '{scheduler}'" - raise Exception(txt) #NOSONAR + raise Exception(txt) # NOSONAR diff --git a/pymodbus/client/asynchronous/factory/tcp.py b/pymodbus/client/asynchronous/factory/tcp.py index 162589d2a..d61e0a751 100644 --- a/pymodbus/client/asynchronous/factory/tcp.py +++ b/pymodbus/client/asynchronous/factory/tcp.py @@ -1,5 +1,4 @@ -""" Factory to create asynchronous tcp clients based on twisted/tornado/asyncio -""" +"""Factory to create asynchronous tcp clients based on twisted/tornado/asyncio.""" from __future__ import unicode_literals from __future__ import absolute_import import logging @@ -13,9 +12,10 @@ _logger = logging.getLogger(__name__) -def reactor_factory(host="127.0.0.1", port=Defaults.Port, framer=None, # pylint: disable=unused-argument +def reactor_factory(host="127.0.0.1", port=Defaults.Port, framer=None, # pylint: disable=unused-argument source_address=None, timeout=None, **kwargs): - """ Factory to create twisted tcp asynchronous client + """Create twisted tcp asynchronous client. + :param host: Host IP address :param port: Port :param framer: Modbus Framer @@ -24,8 +24,8 @@ def reactor_factory(host="127.0.0.1", port=Defaults.Port, framer=None, # pylint: :param kwargs: :return: event_loop_thread and twisted_deferred """ - from twisted.internet import reactor, protocol # pylint: disable=import-outside-toplevel - from pymodbus.client.asynchronous.twisted import ModbusTcpClientProtocol # pylint: disable=import-outside-toplevel + from twisted.internet import reactor, protocol # pylint: disable=import-outside-toplevel + from pymodbus.client.asynchronous.twisted import ModbusTcpClientProtocol # pylint: disable=import-outside-toplevel deferred = protocol.ClientCreator( reactor, ModbusTcpClientProtocol @@ -40,7 +40,7 @@ def reactor_factory(host="127.0.0.1", port=Defaults.Port, framer=None, # pylint: if errback: deferred.addErrback(errback) - protocol = EventLoopThread("reactor", reactor.run, reactor.stop, # pylint: disable=no-member + protocol = EventLoopThread("reactor", reactor.run, reactor.stop, # pylint: disable=no-member installSignalHandlers=0) protocol.start() @@ -49,7 +49,8 @@ def reactor_factory(host="127.0.0.1", port=Defaults.Port, framer=None, # pylint: def io_loop_factory(host="127.0.0.1", port=Defaults.Port, framer=None, source_address=None, timeout=None, **kwargs): - """ Factory to create Tornado based asynchronous tcp clients + """Create Tornado based asynchronous tcp clients. + :param host: Host IP address :param port: Port :param framer: Modbus Framer @@ -58,9 +59,9 @@ def io_loop_factory(host="127.0.0.1", port=Defaults.Port, framer=None, :param kwargs: :return: event_loop_thread and tornado future """ - from tornado.ioloop import IOLoop # pylint: disable=import-outside-toplevel + from tornado.ioloop import IOLoop # pylint: disable=import-outside-toplevel from pymodbus.client.asynchronous.tornado import AsyncModbusTCPClient as \ - Client # pylint: disable=import-outside-toplevel + Client # pylint: disable=import-outside-toplevel ioloop = IOLoop() protocol = EventLoopThread("ioloop", ioloop.start, ioloop.stop) @@ -76,7 +77,8 @@ def io_loop_factory(host="127.0.0.1", port=Defaults.Port, framer=None, def async_io_factory(host="127.0.0.1", port=Defaults.Port, **kwargs): - """ Factory to create asyncio based asynchronous tcp clients + """Create asyncio based asynchronous tcp clients. + :param host: Host IP address :param port: Port :param framer: Modbus Framer @@ -85,7 +87,6 @@ def async_io_factory(host="127.0.0.1", port=Defaults.Port, **kwargs): :param kwargs: :return: asyncio event loop and tcp client """ - try: loop = kwargs.pop("loop", None) or asyncio.get_event_loop() except RuntimeError: @@ -110,7 +111,8 @@ def async_io_factory(host="127.0.0.1", port=Defaults.Port, **kwargs): def get_factory(scheduler): - """ Gets protocol factory based on the backend scheduler being used + """Get protocol factory based on the backend scheduler being used. + :param scheduler: REACTOR/IO_LOOP/ASYNC_IO :return """ @@ -124,4 +126,4 @@ def get_factory(scheduler): txt = f"Allowed Schedulers: {schedulers.REACTOR}, {schedulers.IO_LOOP}, {schedulers.ASYNC_IO}" _logger.warning(txt) txt = f"Invalid Scheduler '{scheduler}'" - raise Exception(txt) #NOSONAR + raise Exception(txt) # NOSONAR diff --git a/pymodbus/client/asynchronous/factory/tls.py b/pymodbus/client/asynchronous/factory/tls.py index 48adce00c..d64cb8893 100644 --- a/pymodbus/client/asynchronous/factory/tls.py +++ b/pymodbus/client/asynchronous/factory/tls.py @@ -1,4 +1,4 @@ -""" Factory to create asynchronous tls clients based on asyncio. """ +"""Factory to create asynchronous tls clients based on asyncio.""" from __future__ import unicode_literals from __future__ import absolute_import import logging @@ -10,9 +10,11 @@ _logger = logging.getLogger(__name__) + def async_io_factory(host="127.0.0.1", port=Defaults.TLSPort, sslctx=None, server_hostname=None, framer=None, **kwargs): - """ Factory to create asyncio based asynchronous tls clients + """Create asyncio based asynchronous tls clients. + :param host: Target server's name, also matched for certificate :param port: Port :param sslctx: The SSLContext to use for TLS (default None and auto create) @@ -25,7 +27,6 @@ def async_io_factory(host="127.0.0.1", port=Defaults.TLSPort, sslctx=None, :param kwargs: :return: asyncio event loop and tcp client """ - try: loop = kwargs.pop("loop", None) or asyncio.get_event_loop() except RuntimeError: @@ -39,7 +40,7 @@ def async_io_factory(host="127.0.0.1", port=Defaults.TLSPort, sslctx=None, client = loop.run_until_complete(asyncio.gather(cor))[0] elif loop is asyncio.get_event_loop(): return loop, init_tls_client(proto_cls, loop, host, port, sslctx, server_hostname, - framer, **kwargs) + framer, **kwargs) else: cor = init_tls_client(proto_cls, loop, host, port, sslctx, server_hostname, framer, **kwargs) @@ -50,7 +51,8 @@ def async_io_factory(host="127.0.0.1", port=Defaults.TLSPort, sslctx=None, def get_factory(scheduler): - """ Gets protocol factory based on the backend scheduler being used + """Get protocol factory based on the backend scheduler being used. + :param scheduler: ASYNC_IO :return """ @@ -60,4 +62,4 @@ def get_factory(scheduler): txt = f"Allowed Schedulers: {schedulers.ASYNC_IO}" _logger.warning(txt) txt = f"Invalid Scheduler '{scheduler}'" - raise Exception(txt) #NOSONAR + raise Exception(txt) # NOSONAR diff --git a/pymodbus/client/asynchronous/factory/udp.py b/pymodbus/client/asynchronous/factory/udp.py index 9627805eb..a6751f417 100644 --- a/pymodbus/client/asynchronous/factory/udp.py +++ b/pymodbus/client/asynchronous/factory/udp.py @@ -14,7 +14,8 @@ def reactor_factory(host="127.0.0.1", port=Defaults.Port, framer=None, source_address=None, timeout=None, **kwargs): - """ Factory to create twisted udp asynchronous client + """Create twisted udp asynchronous client. + :param host: Host IP address :param port: Port :param framer: Modbus Framer @@ -27,8 +28,9 @@ def reactor_factory(host="127.0.0.1", port=Defaults.Port, framer=None, def io_loop_factory(host="127.0.0.1", port=Defaults.Port, framer=None, - source_address=None, timeout=None, **kwargs): - """ Factory to create Tornado based asynchronous udp clients + source_address=None, timeout=None, **kwargs): + """Create Tornado based asynchronous udp clients. + :param host: Host IP address :param port: Port :param framer: Modbus Framer @@ -37,9 +39,9 @@ def io_loop_factory(host="127.0.0.1", port=Defaults.Port, framer=None, :param kwargs: :return: event_loop_thread and tornado future """ - from tornado.ioloop import IOLoop # pylint: disable=import-outside-toplevel + from tornado.ioloop import IOLoop # pylint: disable=import-outside-toplevel from pymodbus.client.asynchronous.tornado import AsyncModbusUDPClient as \ - Client # pylint: disable=import-outside-toplevel + Client # pylint: disable=import-outside-toplevel client = Client(host=host, port=port, framer=framer, source_address=source_address, @@ -53,7 +55,8 @@ def io_loop_factory(host="127.0.0.1", port=Defaults.Port, framer=None, def async_io_factory(host="127.0.0.1", port=Defaults.Port, **kwargs): - """ Factory to create asyncio based asynchronous udp clients + """Create asyncio based asynchronous udp clients. + :param host: Host IP address :param port: Port :param framer: Modbus Framer @@ -83,7 +86,8 @@ def async_io_factory(host="127.0.0.1", port=Defaults.Port, **kwargs): def get_factory(scheduler): - """ Gets protocol factory based on the backend scheduler being used + """Get protocol factory based on the backend scheduler being used. + :param scheduler: REACTOR/IO_LOOP/ASYNC_IO :return """ diff --git a/pymodbus/client/asynchronous/mixins.py b/pymodbus/client/asynchronous/mixins.py index 5b47c16a2..0b72eab39 100644 --- a/pymodbus/client/asynchronous/mixins.py +++ b/pymodbus/client/asynchronous/mixins.py @@ -1,8 +1,7 @@ -""" Mix ins. """ +"""Mix ins.""" import logging from pymodbus.client.sync import BaseModbusClient from pymodbus.constants import Defaults - from pymodbus.factory import ClientDecoder from pymodbus.transaction import ModbusSocketFramer @@ -11,10 +10,10 @@ class BaseAsyncModbusClient(BaseModbusClient): - """ This represents the base ModbusAsyncClient. """ + """This represents the base ModbusAsyncClient.""" def __init__(self, framer=None, timeout=2, **kwargs): - """ Initializes the framer module + """Initialize framer module :param framer: The framer to use for the protocol. Default: ModbusSocketFramer @@ -29,11 +28,12 @@ def __init__(self, framer=None, timeout=2, **kwargs): class AsyncModbusClientMixin(BaseAsyncModbusClient): - """ Async Modbus client mixing for UDP and TCP clients. """ + """Async Modbus client mixing for UDP and TCP clients.""" def __init__(self, host="127.0.0.1", port=Defaults.Port, framer=None, source_address=None, timeout=None, **kwargs): - """ Initializes a Modbus TCP/UDP asynchronous client + """Initialize a Modbus TCP/UDP asynchronous client + :param host: Host IP address :param port: Port :param framer: Framer to use @@ -49,10 +49,11 @@ def __init__(self, host="127.0.0.1", port=Defaults.Port, framer=None, class AsyncModbusSerialClientMixin(BaseAsyncModbusClient): - """ Async Modbus Serial Client Mixing. """ + """Async Modbus Serial Client Mixing.""" def __init__(self, framer=None, port=None, **kwargs): - """ Initializes a Async Modbus Serial Client + """Initialize a Async Modbus Serial Client + :param framer: Modbus Framer :param port: Serial port to use :param kwargs: Extra arguments if any diff --git a/pymodbus/client/asynchronous/schedulers/__init__.py b/pymodbus/client/asynchronous/schedulers/__init__.py index 87971722f..948e28f65 100644 --- a/pymodbus/client/asynchronous/schedulers/__init__.py +++ b/pymodbus/client/asynchronous/schedulers/__init__.py @@ -1,7 +1,6 @@ -""" Backend schedulers to use with generic Async clients. """ +"""Backend schedulers to use with generic Async clients.""" from __future__ import unicode_literals - REACTOR = "reactor" IO_LOOP = "io_loop" ASYNC_IO = "async_io" diff --git a/pymodbus/client/asynchronous/serial.py b/pymodbus/client/asynchronous/serial.py index 0197498fe..eeb3bc2b4 100644 --- a/pymodbus/client/asynchronous/serial.py +++ b/pymodbus/client/asynchronous/serial.py @@ -1,4 +1,4 @@ -""" SERIAL communication. """ +"""SERIAL communication.""" from __future__ import unicode_literals from __future__ import absolute_import @@ -16,16 +16,16 @@ _logger = logging.getLogger(__name__) -class AsyncModbusSerialClient: # pylint: disable=too-few-public-methods - """ Actual Async Serial Client to be used. +class AsyncModbusSerialClient: # pylint: disable=too-few-public-methods + """Actual Async Serial Client to be used. To use do:: - from pymodbus.client.asynchronous.serial import AsyncModbusSerialClient """ + @classmethod def _framer(cls, method): - """ Returns the requested framer + """Return the requested framer :method: The serial framer to instantiate :returns: The requested serial framer @@ -42,17 +42,14 @@ def _framer(cls, method): raise ParameterException("Invalid framer method requested") - def __new__(cls, scheduler, method, port, **kwargs): - """ Scheduler to use: - - reactor (Twisted) - - io_loop (Tornado) - - async_io (asyncio) - The methods to connect are:: + def __new__(cls, scheduler, method, port, **kwargs): + """Use scheduler reactor (Twisted), io_loop (Tornado), async_io (asyncio). + The methods to connect are:: - ascii - rtu - binary - : param scheduler: Backend to use + :param scheduler: Backend to use :param method: The method to use for connection :param port: The serial port to attach to :param stopbits: The number of stop bits to use diff --git a/pymodbus/client/asynchronous/tcp.py b/pymodbus/client/asynchronous/tcp.py index 39d913eb1..97b19dc22 100644 --- a/pymodbus/client/asynchronous/tcp.py +++ b/pymodbus/client/asynchronous/tcp.py @@ -9,16 +9,17 @@ _logger = logging.getLogger(__name__) -class AsyncModbusTCPClient: # pylint: disable=too-few-public-methods - """ Actual Async Serial Client to be used. +class AsyncModbusTCPClient: # pylint: disable=too-few-public-methods + """Actual Async Serial Client to be used. To use do:: - from pymodbus.client.asynchronous.tcp import AsyncModbusTCPClient """ + def __new__(cls, scheduler, host="127.0.0.1", port=Defaults.Port, framer=None, source_address=None, timeout=None, **kwargs): - """ Scheduler to use: + """Scheduler to use: + - reactor (Twisted) - io_loop (Tornado) - async_io (asyncio) diff --git a/pymodbus/client/asynchronous/thread.py b/pymodbus/client/asynchronous/thread.py index cbbbacac9..f075c1109 100644 --- a/pymodbus/client/asynchronous/thread.py +++ b/pymodbus/client/asynchronous/thread.py @@ -1,4 +1,4 @@ -""" Thread setup. """ +"""Thread setup.""" from __future__ import unicode_literals from __future__ import absolute_import @@ -10,11 +10,16 @@ class EventLoopThread: - """ Event loop controlling the backend event loops (io_loop for tornado, - reactor for twisted and event_loop for Asyncio) + """Event loop controlling the backend event loops. + + io_loop for tornado, + reactor for twisted, + event_loop for Asyncio """ + def __init__(self, name, start, stop, *args, **kwargs): - """ Initialize Event loop thread + """Initialize Event loop thread. + :param name: Name of the event loop :param start: Start method to start the backend event loop :param stop: Stop method to stop the backend event loop @@ -30,13 +35,15 @@ def __init__(self, name, start, stop, *args, **kwargs): self._event_loop.daemon = True def _start(self): - """ Starts the backend event loop + """Start the backend event loop + :return: """ self._start_loop(*self._args, **self._kwargs) def start(self): - """ Starts the backend event loop + """Start the backend event loop + :return: """ txt = f"Starting Event Loop: 'PyModbus_{self._name}" @@ -44,7 +51,8 @@ def start(self): self._event_loop.start() def stop(self): - """ Stops the backend event loop + """Stop the backend event loop + :return: """ txt = f"Stopping Event Loop: 'PyModbus_{self._name}" diff --git a/pymodbus/client/asynchronous/tls.py b/pymodbus/client/asynchronous/tls.py index e18012c97..691f0901e 100644 --- a/pymodbus/client/asynchronous/tls.py +++ b/pymodbus/client/asynchronous/tls.py @@ -11,18 +11,18 @@ _logger = logging.getLogger(__name__) -class AsyncModbusTLSClient: # pylint: disable=too-few-public-methods - """ Actual Async TLS Client to be used. +class AsyncModbusTLSClient: # pylint: disable=too-few-public-methods + """Actual Async TLS Client to be used. To use do:: - from pymodbus.client.asynchronous.tls import AsyncModbusTLSClient """ - def __new__(cls, scheduler, host="127.0.0.1", port=Defaults.TLSPort, # pylint: disable=too-many-arguments + + def __new__(cls, scheduler, host="127.0.0.1", port=Defaults.TLSPort, # pylint: disable=too-many-arguments framer=None, sslctx=None, certfile=None, keyfile=None, password=None, source_address=None, timeout=None, **kwargs): - """ Scheduler to use: - - async_io (asyncio) + """Use scheduler async_io (asyncio) + :param scheduler: Backend to use :param host: Target server's name, also matched for certificate :param port: Port diff --git a/pymodbus/client/asynchronous/tornado/__init__.py b/pymodbus/client/asynchronous/tornado/__init__.py index 6a09134c7..4cbb35558 100644 --- a/pymodbus/client/asynchronous/tornado/__init__.py +++ b/pymodbus/client/asynchronous/tornado/__init__.py @@ -1,4 +1,4 @@ -""" Asynchronous framework adapter for tornado. """ +"""Asynchronous framework adapter for tornado.""" from __future__ import unicode_literals import abc @@ -29,13 +29,14 @@ class BaseTornadoClient(AsyncModbusClientMixin): - """ Base Tornado client. """ - + """Base Tornado client.""" + stream = None io_loop = None def __init__(self, *args, **kwargs): - """ Initializes BaseTornadoClient. + """Initialize BaseTornadoClient. + ioloop to be passed as part of kwargs ('ioloop') :param args: :param kwargs: @@ -45,11 +46,11 @@ def __init__(self, *args, **kwargs): @abc.abstractmethod def get_socket(self): - """ Return instance of the socket to connect to. """ + """Return instance of the socket to connect to.""" @gen.coroutine def connect(self): - """ Connect to the socket identified by host and port + """Connect to the socket identified by host and port. :returns: Future :rtype: tornado.concurrent.Future @@ -65,7 +66,8 @@ def connect(self): raise gen.Return(self) def on_receive(self, *args): - """ On data receive call back + """Receive call back. + :param args: data received :return: """ @@ -77,7 +79,8 @@ def on_receive(self, *args): self.framer.processIncomingPacket(data, self._handle_response, unit=unit) def execute(self, request=None): - """ Executes a transaction + """Execute a transaction. + :param request: :return: """ @@ -88,8 +91,9 @@ def execute(self, request=None): self.stream.write(packet) return self._build_response(request.transaction_id) - def _handle_response(self, reply, **kwargs): # pylint: disable=unused-argument - """ Handle response received + def _handle_response(self, reply, **kwargs): # pylint: disable=unused-argument + """Handle response received. + :param reply: :param kwargs: :return: @@ -103,7 +107,8 @@ def _handle_response(self, reply, **kwargs): # pylint: disable=unused-argument _logger.debug(txt) def _build_response(self, tid): - """ Builds a future response + """Build a future response. + :param tid: :return: """ @@ -117,7 +122,7 @@ def _build_response(self, tid): return my_future def close(self): - """ Closes the underlying IOStream. """ + """Close the underlying IOStream.""" _logger.debug("Client disconnected") if self.stream: self.stream.close_fd() @@ -127,13 +132,14 @@ def close(self): class BaseTornadoSerialClient(AsyncModbusSerialClientMixin): - """ Base Tonado serial client. """ + """Base Tonado serial client.""" stream = None io_loop = None def __init__(self, *args, **kwargs): - """ Initializes BaseTornadoSerialClient. + """Initialize BaseTornadoSerialClient. + ioloop to be passed as part of kwargs ('ioloop') :param args: :param kwargs: @@ -143,19 +149,20 @@ def __init__(self, *args, **kwargs): @abc.abstractmethod def get_socket(self): - """ return instance of the socket to connect to. """ + """Return instance of the socket to connect to.""" def on_receive(self, *args): - """ To be handled in the execute method.""" + """Handle (to be) in the execute method.""" def execute(self, request=None): - """ Executes a transaction + """Execute a transaction. + :param request: Request to be written on to the bus :return: """ request.transaction_id = self.transaction.getNextTID() - def callback(*args): # pylint: disable=unused-argument + def callback(*args): # pylint: disable=unused-argument txt = f"in callback - {request.transaction_id}" _logger.debug(txt) while True: @@ -179,8 +186,9 @@ def callback(*args): # pylint: disable=unused-argument response = self._build_response(request.transaction_id) return response - def _handle_response(self, reply, **kwargs): # pylint: disable=unused-argument - """ Handles a received response and updates a future + def _handle_response(self, reply, **kwargs): # pylint: disable=unused-argument + """Handle a received response and updates a future. + :param reply: Reply received :param kwargs: :return: @@ -194,7 +202,8 @@ def _handle_response(self, reply, **kwargs): # pylint: disable=unused-argument _logger.debug(txt) def _build_response(self, tid): - """ Prepare for a response, returns a future + """Prepare for a response, returns a future. + :param tid: :return: Future """ @@ -208,7 +217,7 @@ def _build_response(self, tid): return my_future def close(self): - """ Closes the underlying IOStream. """ + """Close the underlying IOStream.""" _logger.debug("Client disconnected") if self.stream: self.stream.close_fd() @@ -218,11 +227,11 @@ def close(self): class SerialIOStream(BaseIOStream): - """ Serial IO Stream class to control and handle serial connections - over tornado - """ + """Serial IO Stream class to control and handle serial connections over tornado.""" + def __init__(self, connection, *args, **kwargs): - """ Initializes Serial IO Stream + """Initialize Serial IO Stream. + :param connection: serial object :param args: :param kwargs: @@ -231,13 +240,15 @@ def __init__(self, connection, *args, **kwargs): super().__init__(*args, **kwargs) def fileno(self): - """ Returns serial fd + """Return serial fd. + :return: """ return self.connection.fileno() def close_fd(self): - """ Closes a serial Fd + """Close a serial Fd. + :return: """ if self.connection: @@ -245,33 +256,36 @@ def close_fd(self): self.connection = None def read_from_fd(self): - """ Reads from a fd + """Read from a fd + :return: """ try: chunk = self.connection.readline() - except Exception: # pylint: disable=broad-except + except Exception: # pylint: disable=broad-except return None return chunk def write_to_fd(self, data): - """ Writes to a fd + """Write to a fd. + :param data: :return: """ try: return self.connection.write(data) - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except _logger.error(exc) return None class AsyncModbusSerialClient(BaseTornadoSerialClient): - """ Tornado based asynchronous serial client. """ + """Tornado based asynchronous serial client.""" def __init__(self, *args, **kwargs): - """ Initializes AsyncModbusSerialClient. + """Initialize AsyncModbusSerialClient. + :param args: :param kwargs: """ @@ -288,14 +302,15 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def get_socket(self): - """ Creates Pyserial object + """Create Pyserial object + :return: serial object """ return Serial(port=self.port, **self.serial_settings) @gen.coroutine def connect(self): - """ Connect to the socket identified by host and port + """Connect to the socket identified by host and port. :returns: Future :rtype: tornado.concurrent.Future @@ -305,7 +320,7 @@ def connect(self): self.io_loop = IOLoop.current() try: self.stream = SerialIOStream(conn, io_loop=self.io_loop) - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except _logger.exception(exc) self._connected = True @@ -313,21 +328,22 @@ def connect(self): raise gen.Return(self) - def execute(self, request=None): #NOSONAR pylint: disable=too-complex - """ Executes a transaction + def execute(self, request=None): # NOSONAR pylint: disable=too-complex + """Execute a transaction. + :param request: Request to be written on to the bus :return: """ request.transaction_id = self.transaction.getNextTID() def _clear_timer(): - """ Clear serial waiting timeout. """ + """Clear serial waiting timeout.""" if self.timeout_handle: self.io_loop.remove_timeout(self.timeout_handle) - self.timeout_handle = None # pylint: disable=attribute-defined-outside-init + self.timeout_handle = None # pylint: disable=attribute-defined-outside-init def _on_timeout(): - """ Got timeout while waiting data from serial port. """ + """Got timeout while waiting data from serial port.""" _logger.warning("serial receive timeout") _clear_timer() if self.stream: @@ -337,7 +353,7 @@ def _on_timeout(): transaction.set_exception(TimeOutException()) def _on_write_done(): - """ Set up reader part after successful write to the serial. """ + """Set up reader part after successful write to the serial.""" _logger.debug("frame sent, waiting for a reply") self.last_frame_end = round(time.time(), 6) self.state = ModbusTransactionState.WAITING_FOR_REPLY @@ -348,10 +364,10 @@ def _on_fd_error(fd, *args): self.io_loop.remove_handler(fd) self.close() self.transaction.getTransaction(request.transaction_id).set_exception( - ModbusIOException(*args)) + ModbusIOException(*args)) def _on_receive(fd, events): - """ New data in serial buffer to read or serial port closed. """ + """Check new data in serial buffer to read or serial port closed.""" if events & IOLoop.ERROR: _on_fd_error(fd) return @@ -371,9 +387,9 @@ def _on_receive(fd, events): # check if we have regular frame or modbus exception fcode = self.framer.decode_data(self.framer.getRawFrame()).get("fcode", 0) if fcode and ( - (fcode > 0x80 and len(self.framer.getRawFrame()) == exception_response_length) - or - (len(self.framer.getRawFrame()) == expected_response_length) + (fcode > 0x80 and len(self.framer.getRawFrame()) == exception_response_length) + or # noqa W504 + (len(self.framer.getRawFrame()) == expected_response_length) ): _clear_timer() self.io_loop.remove_handler(fd) @@ -390,21 +406,25 @@ def _on_receive(fd, events): response = self._build_response(request.transaction_id) response_pdu_size = request.get_response_pdu_size() - expected_response_length = self.transaction._calculate_response_length(response_pdu_size) # pylint: disable=protected-access + expected_response_length = self.transaction._calculate_response_length( # pylint: disable=protected-access + response_pdu_size) txt = f"expected_response_length = {expected_response_length}" _logger.debug(txt) - #NOSONAR TODO: calculate once - exception_response_length = self.transaction._calculate_exception_length() # pylint: disable=protected-access + # NOSONAR TODO: calculate once + exception_response_length = self.transaction._calculate_exception_length() # pylint: disable=protected-access if self.timeout: - self.timeout_handle = self.io_loop.add_timeout(time.time() + self.timeout, _on_timeout) # pylint: disable=attribute-defined-outside-init + self.timeout_handle = self.io_loop.add_timeout( # pylint: disable=attribute-defined-outside-init + time.time() + self.timeout, + _on_timeout) # pylint: disable=attribute-defined-outside-init self._send_packet(packet, callback=_on_write_done) return response def _send_packet(self, message, callback): - """ Sends packets on the bus with 3.5char delay between frames + """Send packets on the bus with 3.5char delay between frames. + :param message: Message to be sent over the bus :return: """ @@ -434,19 +454,24 @@ def sleep(timeout): _logger.debug(txt) self.stream.write(message, callback) + class AsyncModbusTCPClient(BaseTornadoClient): - """ Tornado based Async tcp client. """ + """Tornado based Async tcp client.""" + def get_socket(self): - """ Creates socket object + """Create socket object. + :return: socket """ return socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM) class AsyncModbusUDPClient(BaseTornadoClient): - """ Tornado based Async UDP client. """ + """Tornado based Async UDP client.""" + def get_socket(self): - """ Create socket object + """Create socket object. + :return: socket """ return socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM) diff --git a/pymodbus/client/asynchronous/twisted/__init__.py b/pymodbus/client/asynchronous/twisted/__init__.py index 71235fd44..7680235b1 100644 --- a/pymodbus/client/asynchronous/twisted/__init__.py +++ b/pymodbus/client/asynchronous/twisted/__init__.py @@ -1,5 +1,4 @@ -""" Implementation of a Modbus Client Using Twisted --------------------------------------------------- +"""Implementation of a Modbus Client Using Twisted Example run:: @@ -56,12 +55,15 @@ def process(): # --------------------------------------------------------------------------- # class ModbusClientProtocol(protocol.Protocol, AsyncModbusClientMixin): - """ This represents the base modbus client protocol. All the application - layer code is deferred to a higher level wrapper. + """This represents the base modbus client protocol. + + All the application layer code is deferred to a higher level wrapper. """ + framer = None - def __init__(self, framer=None, **kwargs): # pylint: disable=super-init-not-called + def __init__(self, framer=None, **kwargs): # pylint: disable=super-init-not-called + """Initialize.""" self._connected = False self.framer = framer or ModbusSocketFramer(ClientDecoder()) if isinstance(self.framer, type): @@ -73,12 +75,12 @@ def __init__(self, framer=None, **kwargs): # pylint: disable=super-init-not-call self.transaction = FifoTransactionManager(self, **kwargs) def connectionMade(self): - """ Called upon a successful client connection. """ + """Call upon a successful client connection.""" _logger.debug("Client connected to modbus server") self._connected = True def connectionLost(self, reason=None): - """ Called upon a client disconnect + """Call upon a client disconnect. :param reason: The reason for the disconnect """ @@ -90,7 +92,7 @@ def connectionLost(self, reason=None): ConnectionException('Connection lost during request'))) def dataReceived(self, data): - """ Get response, check for valid message, decode result + """Get response, check for valid message, decode result. :param data: The data returned from the server """ @@ -99,9 +101,7 @@ def dataReceived(self, data): unit=unit) def execute(self, request=None): - """ Starts the producer to send the next request to - consumer.write(Frame(request)) - """ + """Start the producer to send the next request to consumer.write(Frame(request)).""" request.transaction_id = self.transaction.getNextTID() packet = self.framer.buildPacket(request) txt = f"send: {hexlify_packets(packet)}" @@ -109,8 +109,8 @@ def execute(self, request=None): self.transport.write(packet) return self._buildResponse(request.transaction_id) - def _handleResponse(self, reply, **kwargs): # pylint: disable=invalid-name,unused-argument - """ Handle the processed response and link to correct deferred + def _handleResponse(self, reply, **kwargs): # pylint: disable=invalid-name,unused-argument + """Handle the processed response and link to correct deferred. :param reply: The reply to process """ @@ -122,9 +122,8 @@ def _handleResponse(self, reply, **kwargs): # pylint: disable=invalid-name,unuse txt = f"Unrequested message: {str(reply)}" _logger.debug(txt) - def _buildResponse(self, tid): # pylint: disable=invalid-name, - """ Helper method to return a deferred response - for the current request. + def _buildResponse(self, tid): # pylint: disable=invalid-name, + """Return a deferred response for the current request. :param tid: The transaction identifier for this response :returns: A defer linked to the latest request @@ -138,7 +137,8 @@ def _buildResponse(self, tid): # pylint: disable=invalid-name, return deferred def close(self): - """ Closes underlying transport layer ,essentially closing the client + """Close underlying transport layer ,essentially closing the client. + :return: """ if self.transport and hasattr(self.transport, "close"): @@ -147,18 +147,20 @@ def close(self): class ModbusTcpClientProtocol(ModbusClientProtocol): - """ Async TCP Client protocol based on twisted. + """Async TCP Client protocol based on twisted. Default framer: ModbusSocketFramer """ + framer = ModbusSocketFramer(ClientDecoder()) class ModbusSerClientProtocol(ModbusClientProtocol): - """ Async Serial Client protocol based on twisted + """Async Serial Client protocol based on twisted. Default framer: ModbusRtuFramer """ + def __init__(self, framer=None, **kwargs): framer = framer or ModbusRtuFramer(ClientDecoder()) super().__init__(framer, **kwargs) @@ -169,12 +171,13 @@ def __init__(self, framer=None, **kwargs): # --------------------------------------------------------------------------- # class ModbusUdpClientProtocol(protocol.DatagramProtocol, AsyncModbusClientMixin): - """ This represents the base modbus client protocol. All the application - layer code is deferred to a higher level wrapper. + """This represents the base modbus client protocol. + + All the application layer code is deferred to a higher level wrapper. """ def datagramReceived(self, datagram, addr): - """ Get response, check for valid message, decode result + """Get response, check for valid message, decode result. :param data: The data returned from the server :param params: The host parameters sending the datagram @@ -185,16 +188,14 @@ def datagramReceived(self, datagram, addr): self.framer.processIncomingPacket(datagram, self._handleResponse, unit=unit) def execute(self, request=None): - """ Starts the producer to send the next request to - consumer.write(Frame(request)) - """ + """Start the producer to send the next request to consumer.write(Frame(request)).""" request.transaction_id = self.transaction.getNextTID() packet = self.framer.buildPacket(request) self.transport.write(packet, (self.host, self.port)) return self._buildResponse(request.transaction_id) - def _handleResponse(self, reply, **kwargs): # pylint: disable=invalid-name,unused-argument - """ Handle the processed response and link to correct deferred + def _handleResponse(self, reply, **kwargs): # pylint: disable=invalid-name,unused-argument + """Handle the processed response and link to correct deferred. :param reply: The reply to process """ @@ -206,9 +207,8 @@ def _handleResponse(self, reply, **kwargs): # pylint: disable=invalid-name,unuse txt = f"Unrequested message: {str(reply)}" _logger.debug(txt) - def _buildResponse(self, tid): # pylint: disable=invalid-name - """ Helper method to return a deferred response - for the current request. + def _buildResponse(self, tid): # pylint: disable=invalid-name + """Return a deferred response for the current request. :param tid: The transaction identifier for this response :returns: A defer linked to the latest request @@ -222,7 +222,7 @@ def _buildResponse(self, tid): # pylint: disable=invalid-name # Client Factories # --------------------------------------------------------------------------- # class ModbusClientFactory(protocol.ReconnectingClientFactory): - """ Simple client protocol factory """ + """Simple client protocol factory.""" protocol = ModbusClientProtocol diff --git a/pymodbus/client/asynchronous/udp.py b/pymodbus/client/asynchronous/udp.py index 87b42a66b..5fbb5a292 100644 --- a/pymodbus/client/asynchronous/udp.py +++ b/pymodbus/client/asynchronous/udp.py @@ -9,19 +9,17 @@ _logger = logging.getLogger(__name__) -class AsyncModbusUDPClient: # pylint: disable=too-few-public-methods - """ Actual Async UDP Client to be used. +class AsyncModbusUDPClient: # pylint: disable=too-few-public-methods + """Actual Async UDP Client to be used. To use do:: - from pymodbus.client.asynchronous.tcp import AsyncModbusUDPClient """ + def __new__(cls, scheduler, host="127.0.0.1", port=Defaults.Port, framer=None, source_address=None, timeout=None, **kwargs): - """ Scheduler to use: - - reactor (Twisted) - - io_loop (Tornado) - - async_io (asyncio) + """Use scheduler reactor (Twisted), io_loop (Tornado), async_io (asyncio). + :param scheduler: Backend to use :param host: Host IP address :param port: Port diff --git a/pymodbus/client/common.py b/pymodbus/client/common.py index e3ae537dd..46253db63 100644 --- a/pymodbus/client/common.py +++ b/pymodbus/client/common.py @@ -1,5 +1,4 @@ -""" Modbus Client Common ----------------------------------- +"""Modbus Client Common. This is a common client mixin that can be used by both the synchronous and asynchronous clients to @@ -27,8 +26,9 @@ class ModbusClientMixin: - """ This is a modbus client mixin that provides additional factory - methods for all the current modbus methods. This can be used + """Modbus client mixin that provides additional factory methods. + + for all the current modbus methods. This can be used instead of the normal pattern of:: # instead of this @@ -40,12 +40,13 @@ class ModbusClientMixin: client = ModbusClient(...) response = client.read_coils(1, 10) """ + state = ModbusTransactionState.IDLE last_frame_end = 0 silent_interval = 0 def read_coils(self, address, count=1, **kwargs): - """ Read coils. + """Read coils. :param address: The starting address to read from :param count: The number of coils to read @@ -53,10 +54,10 @@ def read_coils(self, address, count=1, **kwargs): :returns: A deferred response handle """ request = ReadCoilsRequest(address, count, **kwargs) - return self.execute(request) # pylint: disable=no-member + return self.execute(request) # pylint: disable=no-member def read_discrete_inputs(self, address, count=1, **kwargs): - """ Read discrete inputs. + """Read discrete inputs. :param address: The starting address to read from :param count: The number of discretes to read @@ -64,10 +65,10 @@ def read_discrete_inputs(self, address, count=1, **kwargs): :returns: A deferred response handle """ request = ReadDiscreteInputsRequest(address, count, **kwargs) - return self.execute(request) # pylint: disable=no-member + return self.execute(request) # pylint: disable=no-member def write_coil(self, address, value, **kwargs): - """ write_coil. + """Write_coil. :param address: The starting address to write to :param value: The value to write to the specified address @@ -75,10 +76,10 @@ def write_coil(self, address, value, **kwargs): :returns: A deferred response handle """ request = WriteSingleCoilRequest(address, value, **kwargs) - return self.execute(request) # pylint: disable=no-member + return self.execute(request) # pylint: disable=no-member def write_coils(self, address, values, **kwargs): - """ write coils. + """Write coils. :param address: The starting address to write to :param values: The values to write to the specified address @@ -86,10 +87,10 @@ def write_coils(self, address, values, **kwargs): :returns: A deferred response handle """ request = WriteMultipleCoilsRequest(address, values, **kwargs) - return self.execute(request) # pylint: disable=no-member + return self.execute(request) # pylint: disable=no-member def write_register(self, address, value, **kwargs): - """ write register. + """Write register. :param address: The starting address to write to :param value: The value to write to the specified address @@ -97,10 +98,10 @@ def write_register(self, address, value, **kwargs): :returns: A deferred response handle """ request = WriteSingleRegisterRequest(address, value, **kwargs) - return self.execute(request) # pylint: disable=no-member + return self.execute(request) # pylint: disable=no-member def write_registers(self, address, values, **kwargs): - """ write registers. + """Write registers. :param address: The starting address to write to :param values: The values to write to the specified address @@ -108,10 +109,10 @@ def write_registers(self, address, values, **kwargs): :returns: A deferred response handle """ request = WriteMultipleRegistersRequest(address, values, **kwargs) - return self.execute(request) # pylint: disable=no-member + return self.execute(request) # pylint: disable=no-member def read_holding_registers(self, address, count=1, **kwargs): - """ Read holding registers. + """Read holding registers. :param address: The starting address to read from :param count: The number of registers to read @@ -119,10 +120,10 @@ def read_holding_registers(self, address, count=1, **kwargs): :returns: A deferred response handle """ request = ReadHoldingRegistersRequest(address, count, **kwargs) - return self.execute(request) # pylint: disable=no-member + return self.execute(request) # pylint: disable=no-member def read_input_registers(self, address, count=1, **kwargs): - """ Read input registers. + """Read input registers. :param address: The starting address to read from :param count: The number of registers to read @@ -130,10 +131,10 @@ def read_input_registers(self, address, count=1, **kwargs): :returns: A deferred response handle """ request = ReadInputRegistersRequest(address, count, **kwargs) - return self.execute(request) # pylint: disable=no-member + return self.execute(request) # pylint: disable=no-member def readwrite_registers(self, *args, **kwargs): - """ Read/Write registers + """Read/Write registers :param read_address: The address to start reading from :param read_count: The number of registers to read from address @@ -143,10 +144,10 @@ def readwrite_registers(self, *args, **kwargs): :returns: A deferred response handle """ request = ReadWriteMultipleRegistersRequest(*args, **kwargs) - return self.execute(request) # pylint: disable=no-member + return self.execute(request) # pylint: disable=no-member def mask_write_register(self, *args, **kwargs): - """ Mask write register. + """Mask write register. :param address: The address of the register to write :param and_mask: The and bitmask to apply to the register address @@ -155,9 +156,10 @@ def mask_write_register(self, *args, **kwargs): :returns: A deferred response handle """ request = MaskWriteRegisterRequest(*args, **kwargs) - return self.execute(request) # pylint: disable=no-member + return self.execute(request) # pylint: disable=no-member + -#---------------------------------------------------------------------------# -# Exported symbols -#---------------------------------------------------------------------------# -__all__ = [ 'ModbusClientMixin' ] +# ---------------------------------------------------------------------------# +# Exported symbols +# ---------------------------------------------------------------------------# +__all__ = ['ModbusClientMixin'] diff --git a/pymodbus/client/sync.py b/pymodbus/client/sync.py index 507c21d72..842f242e3 100644 --- a/pymodbus/client/sync.py +++ b/pymodbus/client/sync.py @@ -1,4 +1,4 @@ -""" Sync client. """ +"""Sync client.""" import logging import socket import select @@ -29,13 +29,15 @@ class BaseModbusClient(ModbusClientMixin): - """ Interface for a modbus synchronous client. Defined here are all the - methods for performing the related request methods. Derived classes - simply need to implement the transport methods and set the correct - framer. + """Interface for a modbus synchronous client. + + Defined here are all the methods for performing the related request + methods. Derived classes simply need to implement the transport + methods and set the correct framer. """ + def __init__(self, framer, **kwargs): - """ Initialize a client instance + """Initialize a client instance. :param framer: The modbus framer implementation to use """ @@ -48,24 +50,23 @@ def __init__(self, framer, **kwargs): # ----------------------------------------------------------------------- # # Client interface # ----------------------------------------------------------------------- # - def connect(self): # pylint: disable=no-self-use - """ Connect to the modbus remote host + def connect(self): # pylint: disable=no-self-use + """Connect to the modbus remote host. :returns: True if connection succeeded, False otherwise """ raise NotImplementedException("Method not implemented by derived class") def close(self): - """ Closes the underlying socket connection. """ + """Close the underlying socket connection.""" def is_socket_open(self): - """ Check whether the underlying socket/serial is open or not. + """Check whether the underlying socket/serial is open or not. :returns: True if socket/serial is open, False otherwise """ raise NotImplementedException(f"is_socket_open() not implemented by {self.__str__()}") - def send(self, request): """Send request.""" if self.state != ModbusTransactionState.RETRYING: @@ -73,8 +74,8 @@ def send(self, request): self.state = ModbusTransactionState.SENDING return self._send(request) - def _send(self, request): # pylint: disable=no-self-use - """ Sends data on the underlying socket + def _send(self, request): # pylint: disable=no-self-use + """Send data on the underlying socket. :param request: The encoded request to send :return: The number of bytes written @@ -85,8 +86,8 @@ def recv(self, size): """Receive data.""" return self._recv(size) - def _recv(self, size): # pylint: disable=no-self-use - """ Reads data from the underlying descriptor + def _recv(self, size): # pylint: disable=no-self-use + """Read data from the underlying descriptor. :param size: The number of bytes to read :return: The bytes read @@ -97,7 +98,8 @@ def _recv(self, size): # pylint: disable=no-self-use # Modbus client methods # ----------------------------------------------------------------------- # def execute(self, request=None): - """ Execute. + """Execute. + :param request: The request to process :returns: The result of the request execution """ @@ -109,7 +111,7 @@ def execute(self, request=None): # The magic methods # ----------------------------------------------------------------------- # def __enter__(self): - """ Implement the client with enter block + """Implement the client with enter block. :returns: The current instance of the client """ @@ -118,11 +120,12 @@ def __enter__(self): return self def __exit__(self, klass, value, traceback): - """ Implement the client with exit block """ + """Implement the client with exit block.""" self.close() def idle_time(self): - """ Bus Idle Time to initiate next transaction + """Return bus Idle Time to initiate next transaction. + :return: time stamp """ if self.last_frame_end is None or self.silent_interval is None: @@ -130,37 +133,38 @@ def idle_time(self): return self.last_frame_end + self.silent_interval def debug_enabled(self): - """ Returns a boolean indicating if debug is enabled. """ + """Return a boolean indicating if debug is enabled.""" return self._debug def set_debug(self, debug): - """ Sets the current debug flag. """ + """Set the current debug flag.""" self._debug = debug def trace(self, writeable): - """ Show trace. """ + """Show trace.""" if writeable: self.set_debug(True) self._debugfd = writeable def _dump(self, data): - """ Internal dump. """ + """Dump.""" fd = self._debugfd if self._debugfd else sys.stdout try: fd.write(hexlify_packets(data)) - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except _logger.debug(hexlify_packets(data)) _logger.exception(exc) def register(self, function): - """ Registers a function and sub function class with the decoder + """Register a function and sub function class with the decoder. + :param function: Custom function class to register :return: """ self.framer.decoder.register(function) def __str__(self): - """ Builds a string representation of the connection + """Build a string representation of the connection. :returns: The string representation """ @@ -171,11 +175,11 @@ def __str__(self): # Modbus TCP Client Transport Implementation # --------------------------------------------------------------------------- # class ModbusTcpClient(BaseModbusClient): - """ Implementation of a modbus tcp client. """ + """Implementation of a modbus tcp client.""" def __init__(self, host='127.0.0.1', port=Defaults.Port, - framer=ModbusSocketFramer, **kwargs): - """ Initialize a client instance + framer=ModbusSocketFramer, **kwargs): + """Initialize a client instance. :param host: The host to connect to (default 127.0.0.1) :param port: The modbus port to connect to (default 502) @@ -189,11 +193,11 @@ def __init__(self, host='127.0.0.1', port=Defaults.Port, self.port = port self.source_address = kwargs.get('source_address', ('', 0)) self.socket = None - self.timeout = kwargs.get('timeout', Defaults.Timeout) + self.timeout = kwargs.get('timeout', Defaults.Timeout) BaseModbusClient.__init__(self, framer(ClientDecoder(), self), **kwargs) def connect(self): - """ Connect to the modbus tcp server + """Connect to the modbus tcp server. :returns: True if connection succeeded, False otherwise """ @@ -213,13 +217,13 @@ def connect(self): return self.socket is not None def close(self): - """ Closes the underlying socket connection. """ + """Close the underlying socket connection.""" if self.socket: self.socket.close() self.socket = None def _check_read_buffer(self): - """ Internal check read buffer. """ + """Check read buffer.""" time_ = time.time() end = time_ + self.timeout data = None @@ -229,7 +233,7 @@ def _check_read_buffer(self): return data def _send(self, request): - """ Sends data on the underlying socket + """Send data on the underlying socket. :param request: The encoded request to send :return: The number of bytes written @@ -245,7 +249,7 @@ def _send(self, request): return 0 def _recv(self, size): - """ Reads data from the underlying descriptor + """Read data from the underlying descriptor. :param size: The number of bytes to read :return: The bytes read if the peer sent a response, or a zero-length @@ -307,7 +311,7 @@ def _recv(self, size): return b"".join(data) def _handle_abrupt_socket_close(self, size, data, duration): - """ Handle unexpected socket close by remote end + """Handle unexpected socket close by remote end. Intended to be invoked after determining that the remote end has unexpectedly closed the connection, to clean up and handle @@ -335,16 +339,18 @@ def _handle_abrupt_socket_close(self, size, data, duration): raise ConnectionException(msg) def is_socket_open(self): - return True if self.socket is not None else False # pylint: disable=simplifiable-if-expression + """Check if socket is open.""" + return True if self.socket is not None else False # pylint: disable=simplifiable-if-expression def __str__(self): - """ Builds a string representation of the connection + """Build a string representation of the connection. :returns: The string representation """ return f"ModbusTcpClient({self.host}:{self.port})" def __repr__(self): + """Return string representation.""" return ( f"<{self.__class__.__name__} at {hex(id(self))} socket={self.socket}, " f"ipaddr={self.host}, port={self.port}, timeout={self.timeout}>" @@ -356,12 +362,12 @@ def __repr__(self): class ModbusTlsClient(ModbusTcpClient): - """ Implementation of a modbus tls client. """ + """Implementation of a modbus tls client.""" def __init__(self, host='localhost', port=Defaults.TLSPort, sslctx=None, - certfile=None, keyfile=None, password=None, framer=ModbusTlsFramer, - **kwargs): - """ Initialize a client instance + certfile=None, keyfile=None, password=None, framer=ModbusTlsFramer, + **kwargs): + """Initialize a client instance. :param host: The host to connect to (default localhost) :param port: The modbus port to connect to (default 802) @@ -379,7 +385,7 @@ def __init__(self, host='localhost', port=Defaults.TLSPort, sslctx=None, ModbusTcpClient.__init__(self, host, port, framer, **kwargs) def connect(self): - """ Connect to the modbus tls server + """Connect to the modbus tls server. :returns: True if connection succeeded, False otherwise """ @@ -399,7 +405,7 @@ def connect(self): return self.socket is not None def _recv(self, size): - """ Reads data from the underlying descriptor + """Read data from the underlying descriptor. :param size: The number of bytes to read :return: The bytes read @@ -443,13 +449,14 @@ def _recv(self, size): return data def __str__(self): - """ Builds a string representation of the connection + """Build a string representation of the connection. :returns: The string representation """ return f"ModbusTlsClient({self.host}:{self.port})" def __repr__(self): + """Return string representation.""" return ( f"<{self.__class__.__name__} at {hex(id(self))} socket={self.socket}, " f"ipaddr={self.host}, port={self.port}, sslctx={self.sslctx}, " @@ -463,11 +470,11 @@ def __repr__(self): class ModbusUdpClient(BaseModbusClient): - """ Implementation of a modbus udp client. """ + """Implementation of a modbus udp client.""" def __init__(self, host='127.0.0.1', port=Defaults.Port, framer=ModbusSocketFramer, **kwargs): - """ Initialize a client instance + """Initialize a client instance. :param host: The host to connect to (default 127.0.0.1) :param port: The modbus port to connect to (default 502) @@ -482,7 +489,8 @@ def __init__(self, host='127.0.0.1', port=Defaults.Port, @classmethod def _get_address_family(cls, address): - """ A helper method to get the correct address family + """Get the correct address family. + for a given address. :param address: The address to get the af for @@ -490,12 +498,12 @@ def _get_address_family(cls, address): """ try: _ = socket.inet_pton(socket.AF_INET6, address) - except socket.error: # not a valid ipv6 address + except socket.error: # not a valid ipv6 address return socket.AF_INET return socket.AF_INET6 def connect(self): - """ Connect to the modbus tcp server + """Connect to the modbus tcp server. :returns: True if connection succeeded, False otherwise """ @@ -512,11 +520,11 @@ def connect(self): return self.socket is not None def close(self): - """ Closes the underlying socket connection. """ + """Close the underlying socket connection.""" self.socket = None def _send(self, request): - """ Sends data on the underlying socket + """Send data on the underlying socket. :param request: The encoded request to send :return: The number of bytes written @@ -528,7 +536,7 @@ def _send(self, request): return 0 def _recv(self, size): - """ Reads data from the underlying descriptor + """Read data from the underlying descriptor. :param size: The number of bytes to read :return: The bytes read @@ -538,18 +546,20 @@ def _recv(self, size): return self.socket.recvfrom(size)[0] def is_socket_open(self): + """Check if socket is open.""" if self.socket: return True return self.connect() def __str__(self): - """ Builds a string representation of the connection + """Build a string representation of the connection. :returns: The string representation """ return f"ModbusUdpClient({self.host}:{self.port})" def __repr__(self): + """Return string representation.""" return ( f"<{self.__class__.__name__} at {hex(id(self))} socket={self.socket}, " f"ipaddr={self.host}, port={self.port}, timeout={self.timeout}>" @@ -560,15 +570,15 @@ def __repr__(self): # --------------------------------------------------------------------------- # -class ModbusSerialClient(BaseModbusClient): # pylint: disable=too-many-instance-attributes - """ Implementation of a modbus serial client. """ +class ModbusSerialClient(BaseModbusClient): # pylint: disable=too-many-instance-attributes + """Implementation of a modbus serial client.""" state = ModbusTransactionState.IDLE inter_char_timeout = 0 silent_interval = 0 def __init__(self, method='ascii', **kwargs): - """ Initialize a serial client instance + """Initialize a serial client instance. The methods to connect are:: @@ -595,9 +605,9 @@ def __init__(self, method='ascii', **kwargs): self.port = kwargs.get('port', 0) self.stopbits = kwargs.get('stopbits', Defaults.Stopbits) self.bytesize = kwargs.get('bytesize', Defaults.Bytesize) - self.parity = kwargs.get('parity', Defaults.Parity) + self.parity = kwargs.get('parity', Defaults.Parity) self.baudrate = kwargs.get('baudrate', Defaults.Baudrate) - self.timeout = kwargs.get('timeout', Defaults.Timeout) + self.timeout = kwargs.get('timeout', Defaults.Timeout) self._strict = kwargs.get("strict", False) self.last_frame_end = None self.handle_local_echo = kwargs.get("handle_local_echo", False) @@ -612,7 +622,7 @@ def __init__(self, method='ascii', **kwargs): @staticmethod def __implementation(method, client): - """ Returns the requested framer + """Return the requested framer. :method: The serial framer to instantiate :returns: The requested serial framer @@ -629,7 +639,7 @@ def __implementation(method, client): raise ParameterException("Invalid framer method requested") def connect(self): - """ Connect to the modbus serial server + """Connect to the modbus serial server. :returns: True if connection succeeded, False otherwise """ @@ -637,11 +647,11 @@ def connect(self): return True try: self.socket = serial.serial_for_url(self.port, - timeout=self.timeout, - bytesize=self.bytesize, - stopbits=self.stopbits, - baudrate=self.baudrate, - parity=self.parity) + timeout=self.timeout, + bytesize=self.bytesize, + stopbits=self.stopbits, + baudrate=self.baudrate, + parity=self.parity) if self.method == "rtu": if self._strict: self.socket.interCharTimeout = self.inter_char_timeout @@ -652,13 +662,13 @@ def connect(self): return self.socket is not None def close(self): - """ Closes the underlying socket connection. """ + """Close the underlying socket connection.""" if self.socket: self.socket.close() self.socket = None def _in_waiting(self): - """ Internal _in_waiting. """ + """Return _in_waiting.""" in_waiting = ("in_waiting" if hasattr( self.socket, "in_waiting") else "inWaiting") @@ -669,7 +679,7 @@ def _in_waiting(self): return waitingbytes def _send(self, request): - """ Sends data on the underlying socket + """Send data on the underlying socket. If receive buffer still holds some data then flush it. @@ -702,7 +712,7 @@ def _send(self, request): return 0 def _wait_for_data(self): - """ Internal wait for data. """ + """Wait for data.""" size = 0 more_data = False if self.timeout is not None and self.timeout: @@ -723,7 +733,7 @@ def _wait_for_data(self): return size def _recv(self, size): - """ Reads data from the underlying descriptor + """Read data from the underlying descriptor. :param size: The number of bytes to read :return: The bytes read @@ -736,6 +746,7 @@ def _recv(self, size): return result def is_socket_open(self): + """Check if socket is open.""" if self.socket: if hasattr(self.socket, "is_open"): return self.socket.is_open @@ -743,13 +754,14 @@ def is_socket_open(self): return False def __str__(self): - """ Builds a string representation of the connection + """Build a string representation of the connection. :returns: The string representation """ return f"ModbusSerialClient({self.method} baud[{self.baudrate}])" def __repr__(self): + """Return string representation.""" return ( f"<{self.__class__.__name__} at {hex(id(self))} socket={self.socket}, " f"method={self.method}, timeout={self.timeout}>" diff --git a/pymodbus/client/sync_diag.py b/pymodbus/client/sync_diag.py index de2f36a4c..f336a3c63 100644 --- a/pymodbus/client/sync_diag.py +++ b/pymodbus/client/sync_diag.py @@ -30,8 +30,9 @@ class ModbusTcpDiagClient(ModbusTcpClient): - """ Variant of pymodbus.client.sync.ModbusTcpClient with additional - logging to diagnose network issues. + """Variant of pymodbus.client.sync.ModbusTcpClient. + + With additional logging to diagnose network issues. The following events are logged: @@ -58,7 +59,7 @@ class ModbusTcpDiagClient(ModbusTcpClient): def __init__(self, host='127.0.0.1', port=Defaults.Port, framer=ModbusSocketFramer, **kwargs): - """ Initialize a client instance + """Initialize a client instance. The keys of LOG_MSGS can be used in kwargs to customize the messages. @@ -83,7 +84,7 @@ def __init__(self, host='127.0.0.1', port=Defaults.Port, self.__dict__[k_item] = kwargs.get(k_item, v_item) def connect(self): - """ Connect to the modbus tcp server + """Connect to the modbus tcp server. :returns: True if connection succeeded, False otherwise """ @@ -101,8 +102,7 @@ def connect(self): return self.socket is not None def close(self): - """ Closes the underlying socket connection - """ + """Close the underlying socket connection.""" if self.socket: _logger.info(self.discon_msg, self) self.socket.close() @@ -130,7 +130,7 @@ def _recv(self, size): raise ConnectionException from exc def _log_delayed_response(self, result_len, size, delay): - """ Internal log delayed response. """ + """Log delayed response.""" if not size and result_len > 0: _logger.info(self.timelimit_read_msg, delay, result_len) elif ((not result_len) or (size and result_len < size)) and delay >= self.timeout: @@ -140,7 +140,7 @@ def _log_delayed_response(self, result_len, size, delay): _logger.warning(self.delay_msg, delay, result_len, size) def __str__(self): - """ Builds a string representation of the connection + """Build a string representation of the connection. :returns: The string representation """ @@ -148,7 +148,7 @@ def __str__(self): def get_client(): - """ Returns an appropriate client based on logging level + """Return an appropriate client based on logging level. This will be ModbusTcpDiagClient by default, or the parent class if the log level is such that the diagnostic client will not log diff --git a/pymodbus/client/tls_helper.py b/pymodbus/client/tls_helper.py index 80f1aaadb..9010e50d0 100644 --- a/pymodbus/client/tls_helper.py +++ b/pymodbus/client/tls_helper.py @@ -1,11 +1,9 @@ -""" TLS helper for Modbus TLS Client ------------------------------------------- - -""" +"""TLS helper for Modbus TLS Client.""" import ssl + def sslctx_provider(sslctx=None, certfile=None, keyfile=None, password=None): - """ Provide the SSLContext for ModbusTlsClient + """Provide the SSLContext for ModbusTlsClient. If the user defined SSLContext is not passed in, sslctx_provider will produce a default one. diff --git a/pymodbus/constants.py b/pymodbus/constants.py index 806758964..3636c1b81 100644 --- a/pymodbus/constants.py +++ b/pymodbus/constants.py @@ -1,5 +1,4 @@ -""" Constants For Modbus Server/Client ----------------------------------- +"""Constants For Modbus Server/Client. This is the single location for storing default values for the servers and clients. @@ -7,8 +6,8 @@ from pymodbus.interfaces import Singleton -class Defaults(Singleton): # pylint: disable=too-few-public-methods - """ A collection of modbus default values +class Defaults(Singleton): # pylint: disable=too-few-public-methods + """A collection of modbus default values. .. attribute:: Port @@ -111,29 +110,30 @@ class Defaults(Singleton): # pylint: disable=too-few-public-methods legacy behavior for existing pymodbus users. """ - Port = 502 - TLSPort = 802 - Backoff = 0.3 - Retries = 3 - RetryOnEmpty = False - RetryOnInvalid = False - Timeout = 3 - Reconnects = 0 - TransactionId = 0 - ProtocolId = 0 - UnitId = 0x00 - Baudrate = 19200 - Parity = 'N' - Bytesize = 8 - Stopbits = 1 - ZeroMode = False + + Port = 502 + TLSPort = 802 + Backoff = 0.3 + Retries = 3 + RetryOnEmpty = False + RetryOnInvalid = False + Timeout = 3 + Reconnects = 0 + TransactionId = 0 + ProtocolId = 0 + UnitId = 0x00 + Baudrate = 19200 + Parity = 'N' + Bytesize = 8 + Stopbits = 1 + ZeroMode = False IgnoreMissingSlaves = False - ReadSize = 1024 - broadcast_enable = False + ReadSize = 1024 + broadcast_enable = False + -class ModbusStatus(Singleton): # pylint: disable=too-few-public-methods - """ These represent various status codes in the modbus - protocol. +class ModbusStatus(Singleton): # pylint: disable=too-few-public-methods + """These represent various status codes in the modbus protocol. .. attribute:: Waiting @@ -161,16 +161,17 @@ class ModbusStatus(Singleton): # pylint: disable=too-few-public-methods This indicates that the given modbus slave is not running """ - Waiting = 0xffff - Ready = 0x0000 - On = 0xff00 # pylint: disable=invalid-name - Off = 0x0000 - SlaveOn = 0xff + + Waiting = 0xffff + Ready = 0x0000 + On = 0xff00 # pylint: disable=invalid-name + Off = 0x0000 + SlaveOn = 0xff SlaveOff = 0x00 -class Endian(Singleton): # pylint: disable=too-few-public-methods - """ An enumeration representing the various byte endianness. +class Endian(Singleton): # pylint: disable=too-few-public-methods + """An enumeration representing the various byte endianness. .. attribute:: Auto @@ -188,13 +189,14 @@ class Endian(Singleton): # pylint: disable=too-few-public-methods .. note:: I am simply borrowing the format strings from the python struct module for my convenience. """ - Auto = '@' - Big = '>' + + Auto = '@' + Big = '>' Little = '<' -class ModbusPlusOperation(Singleton): # pylint: disable=too-few-public-methods - """ Represents the type of modbus plus request +class ModbusPlusOperation(Singleton): # pylint: disable=too-few-public-methods + """Represents the type of modbus plus request. .. attribute:: GetStatistics @@ -206,12 +208,13 @@ class ModbusPlusOperation(Singleton): # pylint: disable=too-few-public-methods Operation requesting that the current modbus plus statistics be cleared and not returned in the response. """ - GetStatistics = 0x0003 + + GetStatistics = 0x0003 ClearStatistics = 0x0004 -class DeviceInformation(Singleton): # pylint: disable=too-few-public-methods - """ Represents what type of device information to read +class DeviceInformation(Singleton): # pylint: disable=too-few-public-methods + """Represents what type of device information to read. .. attribute:: Basic @@ -236,14 +239,15 @@ class DeviceInformation(Singleton): # pylint: disable=too-few-public-methods Request to return a single data object. """ - Basic = 0x01 - Regular = 0x02 + + Basic = 0x01 + Regular = 0x02 Extended = 0x03 Specific = 0x04 -class MoreData(Singleton): # pylint: disable=too-few-public-methods - """ Represents the more follows condition +class MoreData(Singleton): # pylint: disable=too-few-public-methods + """Represents the more follows condition. .. attribute:: Nothing @@ -253,12 +257,14 @@ class MoreData(Singleton): # pylint: disable=too-few-public-methods This indicates that there are more objects to be returned. """ - Nothing = 0x00 + + Nothing = 0x00 KeepReading = 0xFF -#---------------------------------------------------------------------------# -# Exported Identifiers -#---------------------------------------------------------------------------# + +# ---------------------------------------------------------------------------# +# Exported Identifiers +# ---------------------------------------------------------------------------# __all__ = [ "Defaults", "ModbusStatus", "Endian", "ModbusPlusOperation", diff --git a/pymodbus/datastore/__init__.py b/pymodbus/datastore/__init__.py index 589d2559f..f7514213b 100644 --- a/pymodbus/datastore/__init__.py +++ b/pymodbus/datastore/__init__.py @@ -4,9 +4,9 @@ from pymodbus.datastore.context import ModbusSlaveContext from pymodbus.datastore.context import ModbusServerContext -#---------------------------------------------------------------------------# -# Exported symbols -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Exported symbols +# ---------------------------------------------------------------------------# __all__ = [ "ModbusSequentialDataBlock", "ModbusSparseDataBlock", "ModbusSlaveContext", "ModbusServerContext", diff --git a/pymodbus/datastore/context.py b/pymodbus/datastore/context.py index 5b707e986..a942ca312 100644 --- a/pymodbus/datastore/context.py +++ b/pymodbus/datastore/context.py @@ -1,4 +1,4 @@ -""" Context for datastore. """ +"""Context for datastore.""" import logging from pymodbus.exceptions import NoSuchSlaveException @@ -6,22 +6,22 @@ from pymodbus.datastore.store import ModbusSequentialDataBlock from pymodbus.constants import Defaults -#---------------------------------------------------------------------------# -# Logging -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Logging +# ---------------------------------------------------------------------------# _logger = logging.getLogger(__name__) -#---------------------------------------------------------------------------# -# Slave Contexts -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Slave Contexts +# ---------------------------------------------------------------------------# class ModbusSlaveContext(IModbusSlaveContext): - """ This creates a modbus data model with each data access - stored in its own personal block - """ + """This creates a modbus data model with each data access stored in a block.""" + + def __init__(self, *args, **kwargs): # pylint: disable=unused-argument + """Initialize the datastores. - def __init__(self, *args, **kwargs): # pylint: disable=unused-argument - """ Initializes the datastores, defaults to fully populated + Defaults to fully populated sequential data blocks if none are passed in. :param kwargs: Each element is a ModbusDataBlock @@ -39,19 +39,19 @@ def __init__(self, *args, **kwargs): # pylint: disable=unused-argument self.zero_mode = kwargs.get('zero_mode', Defaults.ZeroMode) def __str__(self): - """ Returns a string representation of the context + """Return a string representation of the context. :returns: A string representation of the context """ return "Modbus Slave Context" def reset(self): - """ Resets all the datastores to their default values """ + """Reset all the datastores to their default values.""" for datastore in iter(self.store.values()): datastore.reset() def validate(self, fc_as_hex, address, count=1): - """ Validates the request to make sure it is in range + """Validate the request to make sure it is in range. :param fx: The function we are working with :param address: The starting address @@ -65,7 +65,7 @@ def validate(self, fc_as_hex, address, count=1): return self.store[self.decode(fc_as_hex)].validate(address, count) def getValues(self, fc_as_hex, address, count=1): - """ Get `count` values from datastore + """Get `count` values from datastore. :param fx: The function we are working with :param address: The starting address @@ -79,7 +79,7 @@ def getValues(self, fc_as_hex, address, count=1): return self.store[self.decode(fc_as_hex)].getValues(address, count) def setValues(self, fc_as_hex, address, values): - """ Sets the datastore with the supplied values + """Set the datastore with the supplied values. :param fx: The function we are working with :param address: The starting address @@ -92,18 +92,20 @@ def setValues(self, fc_as_hex, address, values): self.store[self.decode(fc_as_hex)].setValues(address, values) def register(self, function_code, fc_as_hex, datablock=None): - """ Registers a datablock with the slave context + """Register a datablock with the slave context. + :param fc: function code (int) :param fx: string representation of function code (e.g 'cf' ) :param datablock: datablock to associate with this function code :return: """ self.store[fc_as_hex] = datablock or ModbusSequentialDataBlock.create() - self._IModbusSlaveContext__fx_mapper[function_code] = fc_as_hex # pylint: disable=no-member + self._IModbusSlaveContext__fx_mapper[function_code] = fc_as_hex # pylint: disable=no-member class ModbusServerContext: - """ This represents a master collection of slave contexts. + """This represents a master collection of slave contexts. + If single is set to true, it will be treated as a single context so every unit-id returns the same context. If single is set to false, it will be interpreted as a collection of @@ -111,7 +113,7 @@ class ModbusServerContext: """ def __init__(self, slaves=None, single=True): - """ Initializes a new instance of a modbus server context. + """Initialize a new instance of a modbus server context. :param slaves: A dictionary of client contexts :param single: Set to true to treat this as a single context @@ -122,15 +124,14 @@ def __init__(self, slaves=None, single=True): self._slaves = {Defaults.UnitId: self._slaves} def __iter__(self): - """ Iterator over the current collection of slave - contexts. + """Iterate over the current collection of slave contexts. :returns: An iterator over the slave contexts """ return iter(self._slaves.items()) def __contains__(self, slave): - """ Check if the given slave is in this list + """Check if the given slave is in this list. :param slave: slave The slave to check for existence :returns: True if the slave exists, False otherwise @@ -140,7 +141,7 @@ def __contains__(self, slave): return slave in self._slaves def __setitem__(self, slave, context): - """ Used to set a new slave context + """Use to set a new slave context. :param slave: The slave context to set :param context: The new context to set for this slave @@ -153,7 +154,7 @@ def __setitem__(self, slave, context): raise NoSuchSlaveException(f"slave index :{slave} out of range") def __delitem__(self, slave): - """ Wrapper used to access the slave context + """Use to access the slave context. :param slave: The slave context to remove """ @@ -163,7 +164,7 @@ def __delitem__(self, slave): raise NoSuchSlaveException(f"slave index: {slave} out of range") def __getitem__(self, slave): - """ Used to get access to a slave context + """Use to get access to a slave context. :param slave: The slave context to get :returns: The requested slave context diff --git a/pymodbus/datastore/database/__init__.py b/pymodbus/datastore/database/__init__.py index edd4f5f9f..0b5cf1396 100644 --- a/pymodbus/datastore/database/__init__.py +++ b/pymodbus/datastore/database/__init__.py @@ -2,7 +2,7 @@ from pymodbus.datastore.database.sql_datastore import SqlSlaveContext from pymodbus.datastore.database.redis_datastore import RedisSlaveContext -#---------------------------------------------------------------------------# -# Exported symbols -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Exported symbols +# ---------------------------------------------------------------------------# __all__ = ["SqlSlaveContext", "RedisSlaveContext"] diff --git a/pymodbus/datastore/database/redis_datastore.py b/pymodbus/datastore/database/redis_datastore.py index 7c0faa45c..4a8e8d89c 100644 --- a/pymodbus/datastore/database/redis_datastore.py +++ b/pymodbus/datastore/database/redis_datastore.py @@ -1,23 +1,23 @@ -"""mDatastore using redis. """ +"""Datastore using redis.""" import logging import redis from pymodbus.interfaces import IModbusSlaveContext from pymodbus.utilities import pack_bitstring, unpack_bitstring -#---------------------------------------------------------------------------# -# Logging -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Logging +# ---------------------------------------------------------------------------# _logger = logging.getLogger(__name__) -#---------------------------------------------------------------------------# -# Context -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Context +# ---------------------------------------------------------------------------# class RedisSlaveContext(IModbusSlaveContext): - """ This is a modbus slave context using redis as a backing store. """ + """This is a modbus slave context using redis as a backing store.""" def __init__(self, **kwargs): - """ Initializes the datastores + """Initialize the datastores. :param host: The host to connect to :param port: The port to connect to @@ -30,18 +30,18 @@ def __init__(self, **kwargs): self._build_mapping() def __str__(self): - """ Returns a string representation of the context + """Return a string representation of the context. :returns: A string representation of the context """ return f"Redis Slave Context {self.client}" def reset(self): - """ Resets all the datastores to their default values """ + """Reset all the datastores to their default values.""" self.client.flushall() def validate(self, fx, address, count=1): - """ Validates the request to make sure it is in range + """Validate the request to make sure it is in range. :param fx: The function we are working with :param address: The starting address @@ -54,7 +54,7 @@ def validate(self, fx, address, count=1): return self._val_callbacks[self.decode(fx)](address, count) def getValues(self, fx, address, count=1): - """ Get `count` values from datastore + """Get `count` values from datastore. :param fx: The function we are working with :param address: The starting address @@ -67,7 +67,7 @@ def getValues(self, fx, address, count=1): return self._get_callbacks[self.decode(fx)](address, count) def setValues(self, fx, address, values): - """ Sets the datastore with the supplied values + """Set the datastore with the supplied values. :param fx: The function we are working with :param address: The starting address @@ -78,11 +78,11 @@ def setValues(self, fx, address, values): _logger.debug(txt) self._set_callbacks[self.decode(fx)](address, values) - #--------------------------------------------------------------------------# - # Redis Helper Methods - #--------------------------------------------------------------------------# + # --------------------------------------------------------------------------# + # Redis Helper Methods + # --------------------------------------------------------------------------# def _get_prefix(self, key): - """ This is a helper to abstract getting bit values + """Abstract getting bit values. :param key: The key prefix to use :returns: The key prefix to redis @@ -90,9 +90,7 @@ def _get_prefix(self, key): return f"{self.prefix}:{key}" def _build_mapping(self): - """ A quick helper method to build the function - code mapper. - """ + """Build the function code mapper.""" self._val_callbacks = { 'd': lambda o, c: self._val_bit('d', o, c), 'c': lambda o, c: self._val_bit('c', o, c), @@ -112,14 +110,14 @@ def _build_mapping(self): 'i': lambda o, v: self._set_reg('i', o, v), } - #--------------------------------------------------------------------------# - # Redis discrete implementation - #--------------------------------------------------------------------------# + # --------------------------------------------------------------------------# + # Redis discrete implementation + # --------------------------------------------------------------------------# _bit_size = 16 _bit_default = '\x00' * (_bit_size % 8) def _get_bit_values(self, key, offset, count): - """ This is a helper to abstract getting bit values + """Abstract getting bit values. :param key: The key prefix to use :param offset: The address offset to start at @@ -134,7 +132,8 @@ def _get_bit_values(self, key, offset, count): return response def _val_bit(self, key, offset, count): - """ Validates that the given range is currently set in redis. + """Validate that the given range is currently set in redis. + If any of the keys return None, then it is invalid. :param key: The key prefix to use @@ -142,10 +141,10 @@ def _val_bit(self, key, offset, count): :param count: The number of bits to read """ response = self._get_bit_values(key, offset, count) - return True if None not in response else False # pylint: disable=simplifiable-if-expression + return True if None not in response else False # pylint: disable=simplifiable-if-expression def _get_bit(self, key, offset, count): - """ Internal get bit. + """Get bit. :param key: The key prefix to use :param offset: The address offset to start at @@ -158,7 +157,7 @@ def _get_bit(self, key, offset, count): return result[offset:offset + count] def _set_bit(self, key, offset, values): - """ Internal set bit. + """Set bit. :param key: The key prefix to use :param offset: The address offset to start at @@ -180,30 +179,27 @@ def _set_bit(self, key, offset, values): request = dict(zip(request, final)) self.client.mset(request) - #--------------------------------------------------------------------------# - # Redis register implementation - #--------------------------------------------------------------------------# + # --------------------------------------------------------------------------# + # Redis register implementation + # --------------------------------------------------------------------------# _reg_size = 16 _reg_default = '\x00' * (_reg_size % 8) def _get_reg_values(self, key, offset, count): - """ This is a helper to abstract getting register values + """Abstract getting register values. :param key: The key prefix to use :param offset: The address offset to start at :param count: The number of bits to read """ key = self._get_prefix(key) - #s = divmod(offset, self.__reg_size)[0] - #e = divmod(offset+count, self.__reg_size)[0] - - #request = ('%s:%s' % (key, v) for v in range(s, e + 1)) request = (f"{key}:{v}" for v in range(offset, count + 1)) response = self.client.mget(request) return response def _val_reg(self, key, offset, count): - """ Validates that the given range is currently set in redis. + """Validate that the given range is currently set in redis. + If any of the keys return None, then it is invalid. :param key: The key prefix to use @@ -214,7 +210,7 @@ def _val_reg(self, key, offset, count): return None not in response def _get_reg(self, key, offset, count): - """ Internal get register. + """Get register. :param key: The key prefix to use :param offset: The address offset to start at @@ -225,18 +221,13 @@ def _get_reg(self, key, offset, count): return response[offset:offset + count] def _set_reg(self, key, offset, values): - """ Internal set register + """Set register. :param key: The key prefix to use :param offset: The address offset to start at :param values: The values to set """ count = len(values) - #s = divmod(offset, self.__reg_size) - #e = divmod(offset+count, self.__reg_size) - - #current = self.__get_reg_values(key, offset, count) - key = self._get_prefix(key) request = (f"{key}:{v}" for v in range(offset, count + 1)) request = dict(zip(request, values)) diff --git a/pymodbus/datastore/database/sql_datastore.py b/pymodbus/datastore/database/sql_datastore.py index 44c6e4441..728070cd4 100644 --- a/pymodbus/datastore/database/sql_datastore.py +++ b/pymodbus/datastore/database/sql_datastore.py @@ -18,12 +18,11 @@ # Context # --------------------------------------------------------------------------- # class SqlSlaveContext(IModbusSlaveContext): - """ This creates a modbus data model with each data access - stored in its own personal block. - """ + """This creates a modbus data model with each data access in its a block.""" + + def __init__(self, *args, **kwargs): # pylint: disable=unused-argument + """Initialize the datastores. - def __init__(self, *args, **kwargs): # pylint: disable=unused-argument - """ Initializes the datastores :param kwargs: Each element is a ModbusDataBlock """ self.table = kwargs.get('table', 'pymodbus') @@ -31,18 +30,20 @@ def __init__(self, *args, **kwargs): # pylint: disable=unused-argument self._db_create(self.table, self.database) def __str__(self): - """ Returns a string representation of the context + """Return a string representation of the context. + :returns: A string representation of the context """ return "Modbus Slave Context" def reset(self): - """ Resets all the datastores to their default values """ + """Reset all the datastores to their default values.""" self._metadata.drop_all() self._db_create(self.table, self.database) def validate(self, fx, address, count=1): - """ Validates the request to make sure it is in range + """Validate the request to make sure it is in range. + :param fx: The function we are working with :param address: The starting address :param count: The number of values to test @@ -54,7 +55,8 @@ def validate(self, fx, address, count=1): return self._validate(self.decode(fx), address, count) def getValues(self, fx, address, count=1): - """ Get `count` values from datastore + """Get `count` values from datastore. + :param fx: The function we are working with :param address: The starting address :param count: The number of values to retrieve @@ -66,7 +68,8 @@ def getValues(self, fx, address, count=1): return self._get(self.decode(fx), address, count) def setValues(self, fx, address, values, update=True): - """ Sets the datastore with the supplied values + """Set the datastore with the supplied values. + :param fx: The function we are working with :param address: The starting address :param values: The new values to be set @@ -84,7 +87,8 @@ def setValues(self, fx, address, values, update=True): # Sqlite Helper Methods # ----------------------------------------------------------------------- # def _db_create(self, table, database): - """ A helper method to initialize the database and handles + """Initialize the database and handles. + :param table: The table name to create :param database: The database uri to use """ @@ -98,8 +102,9 @@ def _db_create(self, table, database): self._table.create(checkfirst=True) self._connection = self._engine.connect() - def _get(self, type, offset, count): # pylint: disable=redefined-builtin - """ Internal get. + def _get(self, type, offset, count): # pylint: disable=redefined-builtin + """Get. + :param type: The key prefix to use :param offset: The address offset to start at :param count: The number of bits to read @@ -114,8 +119,9 @@ def _get(self, type, offset, count): # pylint: disable=redefined-builtin result = self._connection.execute(query).fetchall() return [row.value for row in result] - def _build_set(self, type, offset, values, prefix=''): # pylint: disable=no-self-use,redefined-builtin - """ A helper method to generate the sql update context + def _build_set(self, type, offset, values, prefix=''): # pylint: disable=no-self-use,redefined-builtin + """Generate the sql update context. + :param type: The key prefix to use :param offset: The address offset to start at :param values: The values to set @@ -130,13 +136,14 @@ def _build_set(self, type, offset, values, prefix=''): # pylint: disable=no-self }) return result - def _check(self, type, offset, values): #NOSONAR pylint: disable=unused-argument,redefined-builtin - """ Internal check. """ + def _check(self, type, offset, values): # NOSONAR pylint: disable=unused-argument,redefined-builtin + """Check.""" result = self._get(type, offset, count=1) - return False if len(result) > 0 else True # pylint: disable=simplifiable-if-expression + return False if len(result) > 0 else True # pylint: disable=simplifiable-if-expression + + def _set(self, type, offset, values): # pylint: disable=redefined-builtin + """Set. - def _set(self, type, offset, values): # pylint: disable=redefined-builtin - """ Internal set. :param key: The type prefix to use :param offset: The address offset to start at :param values: The values to set @@ -148,8 +155,9 @@ def _set(self, type, offset, values): # pylint: disable=redefined-builtin return result.rowcount == len(values) return False - def _update(self, type, offset, values): # pylint: disable=redefined-builtin - """ Internal update. + def _update(self, type, offset, values): # pylint: disable=redefined-builtin + """Update. + :param type: The type prefix to use :param offset: The address offset to start at :param values: The values to set @@ -162,8 +170,9 @@ def _update(self, type, offset, values): # pylint: disable=redefined-builtin result = self._connection.execute(query, context) return result.rowcount == len(values) - def _validate(self, type, offset, count): # pylint: disable=redefined-builtin - """ Internal validate. + def _validate(self, type, offset, count): # pylint: disable=redefined-builtin + """Validate. + :param type: The key prefix to use :param offset: The address offset to start at :param count: The number of bits to read diff --git a/pymodbus/datastore/remote.py b/pymodbus/datastore/remote.py index 406ef188f..00c96048c 100644 --- a/pymodbus/datastore/remote.py +++ b/pymodbus/datastore/remote.py @@ -1,26 +1,27 @@ -""" Remote datastore. """ +"""Remote datastore.""" import logging from pymodbus.exceptions import NotImplementedException from pymodbus.interfaces import IModbusSlaveContext -#---------------------------------------------------------------------------# -# Logging -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Logging +# ---------------------------------------------------------------------------# _logger = logging.getLogger(__name__) -#---------------------------------------------------------------------------# -# Context -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Context +# ---------------------------------------------------------------------------# class RemoteSlaveContext(IModbusSlaveContext): - """ TODO + """TODO. + This creates a modbus data model that connects to a remote device (depending on the client used) """ def __init__(self, client, unit=None): - """ Initializes the datastores + """Initialize the datastores. :param client: The client to retrieve values with :param unit: Unit ID of the remote slave @@ -30,11 +31,11 @@ def __init__(self, client, unit=None): self.__build_mapping() def reset(self): - """ Resets all the datastores to their default values """ + """Reset all the datastores to their default values.""" raise NotImplementedException() def validate(self, fc_as_hex, address, count=1): - """ Validates the request to make sure it is in range + """Validate the request to make sure it is in range. :param fc_as_hex: The function we are working with :param address: The starting address @@ -47,61 +48,60 @@ def validate(self, fc_as_hex, address, count=1): return not result.isError() def getValues(self, fc_as_hex, address, count=1): - """ Get `count` values from datastore + """Get `count` values from datastore. :param fc_as_hex: The function we are working with :param address: The starting address :param count: The number of values to retrieve :returns: The requested values from a:a+c """ - #NOSONAR TODO deal with deferreds + # NOSONAR TODO deal with deferreds txt = f"get values[{fc_as_hex}] {address}:{count}" _logger.debug(txt) result = self.__get_callbacks[self.decode(fc_as_hex)](address, count) return self.__extract_result(self.decode(fc_as_hex), result) def setValues(self, fc_as_hex, address, values): - """ Sets the datastore with the supplied values + """Set the datastore with the supplied values. :param fc_as_hex: The function we are working with :param address: The starting address :param values: The new values to be set """ - #NOSONAR TODO deal with deferreds + # NOSONAR TODO deal with deferreds txt = f"set values[{fc_as_hex}] {address}:{len(values)}" _logger.debug(txt) self.__set_callbacks[self.decode(fc_as_hex)](address, values) def __str__(self): - """ Returns a string representation of the context + """Return a string representation of the context. :returns: A string representation of the context """ return f"Remote Slave Context({self._client})" def __build_mapping(self): - """ A quick helper method to build the function - code mapper. - """ + """Build the function code mapper.""" kwargs = {} if self.unit: kwargs["unit"] = self.unit self.__get_callbacks = { - 'd': lambda a, c: self._client.read_discrete_inputs(a, c, **kwargs), # pylint: disable=unnecessary-lambda - 'c': lambda a, c: self._client.read_coils(a, c, **kwargs), # pylint: disable=unnecessary-lambda - 'h': lambda a, c: self._client.read_holding_registers(a, c, **kwargs), # pylint: disable=unnecessary-lambda - 'i': lambda a, c: self._client.read_input_registers(a, c, **kwargs), # pylint: disable=unnecessary-lambda + 'd': lambda a, c: self._client.read_discrete_inputs(a, c, **kwargs), # pylint: disable=unnecessary-lambda + 'c': lambda a, c: self._client.read_coils(a, c, **kwargs), # pylint: disable=unnecessary-lambda + 'h': lambda a, c: self._client.read_holding_registers(a, c, **kwargs), # pylint: disable=unnecessary-lambda + 'i': lambda a, c: self._client.read_input_registers(a, c, **kwargs), # pylint: disable=unnecessary-lambda } self.__set_callbacks = { - 'd': lambda a, v: self._client.write_coils(a, v, **kwargs), # pylint: disable=unnecessary-lambda - 'c': lambda a, v: self._client.write_coils(a, v, **kwargs), # pylint: disable=unnecessary-lambda - 'h': lambda a, v: self._client.write_registers(a, v, **kwargs), # pylint: disable=unnecessary-lambda - 'i': lambda a, v: self._client.write_registers(a, v, **kwargs), # pylint: disable=unnecessary-lambda + 'd': lambda a, v: self._client.write_coils(a, v, **kwargs), # pylint: disable=unnecessary-lambda + 'c': lambda a, v: self._client.write_coils(a, v, **kwargs), # pylint: disable=unnecessary-lambda + 'h': lambda a, v: self._client.write_registers(a, v, **kwargs), # pylint: disable=unnecessary-lambda + 'i': lambda a, v: self._client.write_registers(a, v, **kwargs), # pylint: disable=unnecessary-lambda } - def __extract_result(self, fc_as_hex, result): # pylint: disable=no-self-use - """ A helper method to extract the values out of - a response. TODO make this consistent (values?) + def __extract_result(self, fc_as_hex, result): # pylint: disable=no-self-use + """Extract the values out of a response. + + TODO make this consistent (values?) """ if not result.isError(): if fc_as_hex in set(['d', 'c']): diff --git a/pymodbus/datastore/store.py b/pymodbus/datastore/store.py index f0e018f67..6869e4828 100644 --- a/pymodbus/datastore/store.py +++ b/pymodbus/datastore/store.py @@ -1,5 +1,4 @@ -""" Modbus Server Datastore -------------------------- +"""Modbus Server Datastore. For each server, you will create a ModbusServerContext and pass in the default address space for each data access. The class @@ -49,17 +48,17 @@ from pymodbus.exceptions import NotImplementedException, ParameterException -#---------------------------------------------------------------------------# -# Logging -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Logging +# ---------------------------------------------------------------------------# _logger = logging.getLogger(__name__) -#---------------------------------------------------------------------------# -# Datablock Storage -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Datablock Storage +# ---------------------------------------------------------------------------# class BaseModbusDataBlock: - """ Base class for a modbus datastore + """Base class for a modbus datastore Derived classes must create the following fields: @address The starting address point @@ -73,21 +72,21 @@ class BaseModbusDataBlock: """ def default(self, count, value=False): - """ Used to initialize a store to one value + """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 # pylint: disable=attribute-defined-outside-init - self.values = [self.default_value] * count # pylint: disable=attribute-defined-outside-init - self.address = 0x00 # pylint: disable=attribute-defined-outside-init + self.default_value = value # pylint: disable=attribute-defined-outside-init + self.values = [self.default_value] * count # pylint: disable=attribute-defined-outside-init + self.address = 0x00 # pylint: disable=attribute-defined-outside-init def reset(self): - """ Resets the datastore to the initialized default value """ - self.values = [self.default_value] * len(self.values) # pylint: disable=attribute-defined-outside-init + """Reset the datastore to the initialized default value.""" + self.values = [self.default_value] * len(self.values) # pylint: disable=attribute-defined-outside-init - def validate(self, address, count=1): # pylint: disable=no-self-use - """ Checks to see if the request is in range + def validate(self, address, count=1): # pylint: disable=no-self-use + """Check to see if the request is in range. :param address: The starting address :param count: The number of values to test for @@ -95,8 +94,8 @@ def validate(self, address, count=1): # pylint: disable=no-self-use """ raise NotImplementedException("Datastore Address Check") - def getValues(self, address, count=1): #NOSONAR pylint: disable=invalid-name,no-self-use - """ Returns the requested values from the datastore + def getValues(self, address, count=1): # NOSONAR pylint: disable=invalid-name,no-self-use + """Return the requested values from the datastore. :param address: The starting address :param count: The number of values to retrieve @@ -104,8 +103,8 @@ def getValues(self, address, count=1): #NOSONAR pylint: disable=invalid-name,no """ raise NotImplementedException("Datastore Value Retrieve") - def setValues(self, address, values): #NOSONAR pylint: disable=invalid-name,no-self-use - """ Returns the requested values from the datastore + def setValues(self, address, values): # NOSONAR pylint: disable=invalid-name,no-self-use + """Return the requested values from the datastore. :param address: The starting address :param values: The values to store @@ -113,14 +112,14 @@ def setValues(self, address, values): #NOSONAR pylint: disable=invalid-name,no-s raise NotImplementedException("Datastore Value Retrieve") def __str__(self): - """ Build a representation of the datastore + """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): - """ Iterator over the data block data + """Iterate over the data block data. :returns: An iterator of the data block data """ @@ -130,10 +129,10 @@ def __iter__(self): class ModbusSequentialDataBlock(BaseModbusDataBlock): - """ Creates a sequential modbus datastore """ + """Creates a sequential modbus datastore.""" def __init__(self, address, values): - """ Initializes the datastore + """Initialize the datastore. :param address: The starting address of the datastore :param values: Either a list or a dictionary of values @@ -147,26 +146,27 @@ def __init__(self, address, values): @classmethod def create(cls): - """ Factory method to create a datastore with the - full address space initialized to 0x00 + """Create a datastore. + + With the full address space initialized to 0x00 :returns: An initialized datastore """ return cls(0x00, [0x00] * 65536) def validate(self, address, count=1): - """ Checks to see if the request is in range + """Check to see if the request is in range. :param address: The starting address :param count: The number of values to test for :returns: True if the request in within range, False otherwise """ - result = (self.address <= address) + result = (self.address <= address) result &= ((self.address + len(self.values)) >= (address + count)) return result def getValues(self, address, count=1): - """ Returns the requested values of the datastore + """Return the requested values of the datastore. :param address: The starting address :param count: The number of values to retrieve @@ -176,7 +176,7 @@ def getValues(self, address, count=1): return self.values[start:start + count] def setValues(self, address, values): - """ Sets the requested values of the datastore + """Set the requested values of the datastore. :param address: The starting address :param values: The new values to be set @@ -188,7 +188,7 @@ def setValues(self, address, values): class ModbusSparseDataBlock(BaseModbusDataBlock): - """ Creates a sparse modbus datastore + """Create a sparse modbus datastore. E.g Usage. sparse = ModbusSparseDataBlock({10: [3, 5, 6, 8], 30: 1, 40: [0]*20}) @@ -208,7 +208,9 @@ class ModbusSparseDataBlock(BaseModbusDataBlock): """ def __init__(self, values=None, mutable=True): - """ Initializes a sparse datastore. Will only answer to addresses + """Initialize a sparse datastore. + + Will only answer to addresses registered, either initially here, or later via setValues() :param values: Either a list or a dictionary of values @@ -228,7 +230,8 @@ def __init__(self, values=None, mutable=True): @classmethod def create(cls, values=None): - """ Factory method to create sparse datastore. + """Create sparse datastore. + Use setValues to initialize registers. :param values: Either a list or a dictionary of values @@ -237,11 +240,11 @@ def create(cls, values=None): return cls(values) def reset(self): - """ Reset the store to the initially provided defaults""" + """Reset the store to the initially provided defaults.""" self.values = self.default_value.copy() def validate(self, address, count=1): - """ Checks to see if the request is in range + """Check to see if the request is in range. :param address: The starting address :param count: The number of values to test for @@ -253,7 +256,7 @@ def validate(self, address, count=1): return handle.issubset(set(iter(self.values.keys()))) def getValues(self, address, count=1): - """ Returns the requested values of the datastore + """Return the requested values of the datastore. :param address: The starting address :param count: The number of values to retrieve @@ -262,7 +265,7 @@ def getValues(self, address, count=1): return [self.values[i] for i in range(address, address + count)] def _process_values(self, values): - """ Internal process values. """ + """Process values.""" def _process_as_dict(values): for idx, val in iter(values.items()): if isinstance(val, (list, tuple)): @@ -283,7 +286,7 @@ def _process_as_dict(values): _process_as_dict(values) def setValues(self, address, values, use_as_default=False): - """ Sets the requested values of the datastore + """Set the requested values of the datastore. :param address: The starting address :param values: The new values to be set @@ -298,7 +301,7 @@ def setValues(self, address, values, use_as_default=False): if not isinstance(values, list): values = [values] for idx, val in enumerate(values): - if address+idx not in self.values and not self.mutable: + 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 not self.address: diff --git a/pymodbus/device.py b/pymodbus/device.py index 686de8af9..f4c96aad2 100644 --- a/pymodbus/device.py +++ b/pymodbus/device.py @@ -1,5 +1,4 @@ -""" Modbus Device Controller -------------------------- +"""Modbus Device Controller. These are the device management handlers. They should be maintained in the server context and the various methods @@ -13,11 +12,12 @@ from pymodbus.utilities import dict_property -#---------------------------------------------------------------------------# -# Network Access Control -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Network Access Control +# ---------------------------------------------------------------------------# class ModbusAccessControl(Singleton): - """ This is a simple implementation of a Network Management System table. + """Simple implementation of a Network Management System table. + Its purpose is to control access to the server (if it is used). We assume that if an entry is in the table, it is allowed accesses to resources. However, if the host does not appear in the table (all @@ -26,26 +26,27 @@ class ModbusAccessControl(Singleton): Since it is a singleton, only one version can possible exist and all instances pull from here. """ + __nmstable = [ - "127.0.0.1", + "127.0.0.1", ] def __iter__(self): - """ Iterator over the network access tablek + """Iterate over the network access table. :returns: An iterator of the network access table """ return self.__nmstable.__iter__() def __contains__(self, host): - """ Check if a host is allowed to access resources + """Check if a host is allowed to access resources. :param host: The host to check """ return host in self.__nmstable def add(self, host): - """ Add allowed host(s) from the NMS table + """Add allowed host(s) from the NMS table. :param host: The host to add """ @@ -56,7 +57,7 @@ def add(self, host): self.__nmstable.append(entry) def remove(self, host): - """ Remove allowed host(s) from the NMS table + """Remove allowed host(s) from the NMS table. :param host: The host to remove """ @@ -67,123 +68,123 @@ def remove(self, host): self.__nmstable.remove(entry) def check(self, host): - """ Check if a host is allowed to access resources + """Check if a host is allowed to access resources. :param host: The host to check """ return host in self.__nmstable -#---------------------------------------------------------------------------# -# Modbus Plus Statistics -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Modbus Plus Statistics +# ---------------------------------------------------------------------------# class ModbusPlusStatistics: - """ This is used to maintain the current modbus plus statistics count. As of - right now this is simply a stub to complete the modbus implementation. + """This is used to maintain the current modbus plus statistics count. + + As of right now this is simply a stub to complete the modbus implementation. For more information, see the modbus implementation guide page 87. """ __data = OrderedDict({ - 'node_type_id' : [0x00] * 2, # 00 - 'software_version_number' : [0x00] * 2, # 01 - 'network_address' : [0x00] * 2, # 02 - 'mac_state_variable' : [0x00] * 2, # 03 - 'peer_status_code' : [0x00] * 2, # 04 - 'token_pass_counter' : [0x00] * 2, # 05 - 'token_rotation_time' : [0x00] * 2, # 06 - - 'program_master_token_failed' : [0x00], # 07 hi - 'data_master_token_failed' : [0x00], # 07 lo - 'program_master_token_owner' : [0x00], # 08 hi - 'data_master_token_owner' : [0x00], # 08 lo - 'program_slave_token_owner' : [0x00], # 09 hi - 'data_slave_token_owner' : [0x00], # 09 lo - 'data_slave_command_transfer' : [0x00], # 10 hi - '__unused_10_lowbit' : [0x00], # 10 lo - - 'program_slave_command_transfer' : [0x00], # 11 hi - 'program_master_rsp_transfer' : [0x00], # 11 lo - 'program_slave_auto_logout' : [0x00], # 12 hi - 'program_master_connect_status' : [0x00], # 12 lo - 'receive_buffer_dma_overrun' : [0x00], # 13 hi - 'pretransmit_deferral_error' : [0x00], # 13 lo - 'frame_size_error' : [0x00], # 14 hi - 'repeated_command_received' : [0x00], # 14 lo - 'receiver_alignment_error' : [0x00], # 15 hi - 'receiver_collision_abort_error' : [0x00], # 15 lo - 'bad_packet_length_error' : [0x00], # 16 hi - 'receiver_crc_error' : [0x00], # 16 lo - 'transmit_buffer_dma_underrun' : [0x00], # 17 hi - 'bad_link_address_error' : [0x00], # 17 lo - - 'bad_mac_function_code_error' : [0x00], # 18 hi - 'internal_packet_length_error' : [0x00], # 18 lo - 'communication_failed_error' : [0x00], # 19 hi - 'communication_retries' : [0x00], # 19 lo - 'no_response_error' : [0x00], # 20 hi - 'good_receive_packet' : [0x00], # 20 lo - 'unexpected_path_error' : [0x00], # 21 hi - 'exception_response_error' : [0x00], # 21 lo - 'forgotten_transaction_error' : [0x00], # 22 hi - 'unexpected_response_error' : [0x00], # 22 lo - - 'active_station_bit_map' : [0x00] * 8, # 23-26 - 'token_station_bit_map' : [0x00] * 8, # 27-30 - 'global_data_bit_map' : [0x00] * 8, # 31-34 - 'receive_buffer_use_bit_map' : [0x00] * 8, # 35-37 - 'data_master_output_path' : [0x00] * 8, # 38-41 - 'data_slave_input_path' : [0x00] * 8, # 42-45 - 'program_master_outptu_path' : [0x00] * 8, # 46-49 - 'program_slave_input_path' : [0x00] * 8, # 50-53 + 'node_type_id': [0x00] * 2, # 00 + 'software_version_number': [0x00] * 2, # 01 + 'network_address': [0x00] * 2, # 02 + 'mac_state_variable': [0x00] * 2, # 03 + 'peer_status_code': [0x00] * 2, # 04 + 'token_pass_counter': [0x00] * 2, # 05 + 'token_rotation_time': [0x00] * 2, # 06 + + 'program_master_token_failed': [0x00], # 07 hi + 'data_master_token_failed': [0x00], # 07 lo + 'program_master_token_owner': [0x00], # 08 hi + 'data_master_token_owner': [0x00], # 08 lo + 'program_slave_token_owner': [0x00], # 09 hi + 'data_slave_token_owner': [0x00], # 09 lo + 'data_slave_command_transfer': [0x00], # 10 hi + '__unused_10_lowbit': [0x00], # 10 lo + + 'program_slave_command_transfer': [0x00], # 11 hi + 'program_master_rsp_transfer': [0x00], # 11 lo + 'program_slave_auto_logout': [0x00], # 12 hi + 'program_master_connect_status': [0x00], # 12 lo + 'receive_buffer_dma_overrun': [0x00], # 13 hi + 'pretransmit_deferral_error': [0x00], # 13 lo + 'frame_size_error': [0x00], # 14 hi + 'repeated_command_received': [0x00], # 14 lo + 'receiver_alignment_error': [0x00], # 15 hi + 'receiver_collision_abort_error': [0x00], # 15 lo + 'bad_packet_length_error': [0x00], # 16 hi + 'receiver_crc_error': [0x00], # 16 lo + 'transmit_buffer_dma_underrun': [0x00], # 17 hi + 'bad_link_address_error': [0x00], # 17 lo + + 'bad_mac_function_code_error': [0x00], # 18 hi + 'internal_packet_length_error': [0x00], # 18 lo + 'communication_failed_error': [0x00], # 19 hi + 'communication_retries': [0x00], # 19 lo + 'no_response_error': [0x00], # 20 hi + 'good_receive_packet': [0x00], # 20 lo + 'unexpected_path_error': [0x00], # 21 hi + 'exception_response_error': [0x00], # 21 lo + 'forgotten_transaction_error': [0x00], # 22 hi + 'unexpected_response_error': [0x00], # 22 lo + + 'active_station_bit_map': [0x00] * 8, # 23-26 + 'token_station_bit_map': [0x00] * 8, # 27-30 + 'global_data_bit_map': [0x00] * 8, # 31-34 + 'receive_buffer_use_bit_map': [0x00] * 8, # 35-37 + 'data_master_output_path': [0x00] * 8, # 38-41 + 'data_slave_input_path': [0x00] * 8, # 42-45 + 'program_master_outptu_path': [0x00] * 8, # 46-49 + 'program_slave_input_path': [0x00] * 8, # 50-53 }) def __init__(self): - """ Initialize the modbus plus statistics with the default - information. - """ + """Initialize the modbus plus statistics with the default information.""" self.reset() def __iter__(self): - """ Iterator over the statistics + """Iterate over the statistics. :returns: An iterator of the modbus plus statistics """ return iter(self.__data.items()) def reset(self): - """ This clears all of the modbus plus statistics - """ + """Clear all of the modbus plus statistics.""" for key in self.__data: self.__data[key] = [0x00] * len(self.__data[key]) def summary(self): - """ Returns a summary of the modbus plus statistics + """Return a summary of the modbus plus statistics. :returns: 54 16-bit words representing the status """ return iter(self.__data.values()) def encode(self): - """ Returns a summary of the modbus plus statistics + """Return a summary of the modbus plus statistics. :returns: 54 16-bit words representing the status """ total, values = [], sum(self.__data.values(), []) for i in range(0, len(values), 2): - total.append((values[i] << 8) | values[i+1]) + total.append((values[i] << 8) | values[i + 1]) return total -#---------------------------------------------------------------------------# -# Device Information Control -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Device Information Control +# ---------------------------------------------------------------------------# class ModbusDeviceIdentification: - """ This is used to supply the device identification - for the readDeviceIdentification function + """This is used to supply the device identification. + + For the readDeviceIdentification function For more information read section 6.21 of the modbus application protocol. """ + __data = { 0x00: '', # VendorName 0x01: '', # ProductCode @@ -208,13 +209,13 @@ class ModbusDeviceIdentification: ] def __init__(self, info=None, info_name=None): - """ Initialize the datastore with the elements you need. + """Initialize the datastore with the elements you need. + (note acceptable range is [0x00-0x06,0x80-0xFF] inclusive) :param info: A dictionary of {int:string} of values :param set: A dictionary of {name:string} of values """ - if isinstance(info_name, dict): for key in info_name: inx = self.__names.index(key) @@ -226,21 +227,22 @@ def __init__(self, info=None, info_name=None): self.__data[key] = info[key] def __iter__(self): - """ Iterator over the device information + """Iterate over the device information. :returns: An iterator of the device information """ return iter(self.__data.items()) def summary(self): - """ Return a summary of the main items + """Return a summary of the main items. :returns: An dictionary of the main items """ return dict(zip(self.__names, iter(self.__data.values()))) def update(self, value): - """ Update the values of this identity + """Update the values of this identity. + using another identify as the value :param value: The value to copy values from @@ -248,7 +250,7 @@ def update(self, value): self.__data.update(value) def __setitem__(self, key, value): - """ Wrapper used to access the device information + """Access the device information. :param key: The register to set :param value: The new value for referenced register @@ -257,51 +259,53 @@ def __setitem__(self, key, value): self.__data[key] = value def __getitem__(self, key): - """ Wrapper used to access the device information + """Access the device information. :param key: The register to read """ return self.__data.setdefault(key, '') def __str__(self): - """ Build a representation of the device + """Build a representation of the device. :returns: A string representation of the device """ return "DeviceIdentity" - #-------------------------------------------------------------------------# - # Properties - #-------------------------------------------------------------------------# - VendorName = dict_property(lambda s: s.__data, 0) #NOSONAR pylint: disable=protected-access,invalid-name - ProductCode = dict_property(lambda s: s.__data, 1) #NOSONAR pylint: disable=protected-access,invalid-name - MajorMinorRevision = dict_property(lambda s: s.__data, 2) #NOSONAR pylint: disable=protected-access,invalid-name - VendorUrl = dict_property(lambda s: s.__data, 3) #NOSONAR pylint: disable=protected-access,invalid-name - ProductName = dict_property(lambda s: s.__data, 4) #NOSONAR pylint: disable=protected-access,invalid-name - ModelName = dict_property(lambda s: s.__data, 5) #NOSONAR pylint: disable=protected-access,invalid-name - UserApplicationName = dict_property(lambda s: s.__data, 6) #NOSONAR pylint: disable=protected-access,invalid-name + # -------------------------------------------------------------------------# + # Properties + # -------------------------------------------------------------------------# + VendorName = dict_property(lambda s: s.__data, 0) # NOSONAR pylint: disable=protected-access,invalid-name + ProductCode = dict_property(lambda s: s.__data, 1) # NOSONAR pylint: disable=protected-access,invalid-name + MajorMinorRevision = dict_property(lambda s: s.__data, 2) # NOSONAR pylint: disable=protected-access,invalid-name + VendorUrl = dict_property(lambda s: s.__data, 3) # NOSONAR pylint: disable=protected-access,invalid-name + ProductName = dict_property(lambda s: s.__data, 4) # NOSONAR pylint: disable=protected-access,invalid-name + ModelName = dict_property(lambda s: s.__data, 5) # NOSONAR pylint: disable=protected-access,invalid-name + UserApplicationName = dict_property(lambda s: s.__data, 6) # NOSONAR pylint: disable=protected-access,invalid-name + +class DeviceInformationFactory(Singleton): # pylint: disable=too-few-public-methods + """This is a helper factory. -class DeviceInformationFactory(Singleton): # pylint: disable=too-few-public-methods - """ This is a helper factory that really just hides + That really just hides some of the complexity of processing the device information requests (function code 0x2b 0x0e). """ __lookup = { - DeviceInformation.Basic: lambda c, r, i: c.__gets(r, list(range(i, 0x03))), # pylint: disable=protected-access - DeviceInformation.Regular: lambda c, r, i: c.__gets(r, list(range(i, 0x07)) # pylint: disable=protected-access - if c.__get(r, i)[i] else list(range(0, 0x07))), # pylint: disable=protected-access - DeviceInformation.Extended: lambda c, r, i: c.__gets(r, # pylint: disable=protected-access - [x for x in range(i, 0x100) if x not in range(0x07, 0x80)] - if c.__get(r, i)[i] else # pylint: disable=protected-access - [x for x in range(0, 0x100) if x not in range(0x07, 0x80)]), - DeviceInformation.Specific: lambda c, r, i: c.__get(r, i), # pylint: disable=protected-access + DeviceInformation.Basic: lambda c, r, i: c.__gets(r, list(range(i, 0x03))), # pylint: disable=protected-access + DeviceInformation.Regular: lambda c, r, i: c.__gets(r, list(range(i, 0x07)) # pylint: disable=protected-access + if c.__get(r, i)[i] else list(range(0, 0x07))), # noqa E501 pylint: disable=protected-access + DeviceInformation.Extended: lambda c, r, i: c.__gets(r, # pylint: disable=protected-access + [x for x in range(i, 0x100) if x not in range(0x07, 0x80)] # noqa E501 + if c.__get(r, i)[i] else # noqa E501 pylint: disable=protected-access + [x for x in range(0, 0x100) if x not in range(0x07, 0x80)]), # noqa E501 + DeviceInformation.Specific: lambda c, r, i: c.__get(r, i), # pylint: disable=protected-access } @classmethod def get(cls, control, read_code=DeviceInformation.Basic, object_id=0x00): - """ Get the requested device data from the system + """Get the requested device data from the system. :param control: The control block to pull data from :param read_code: The read code to process @@ -312,18 +316,18 @@ def get(cls, control, read_code=DeviceInformation.Basic, object_id=0x00): return cls.__lookup[read_code](cls, identity, object_id) @classmethod - def __get(cls, identity, object_id): #NOSONAR pylint: disable=unused-private-member - """ Read a single object_id from the device information + def __get(cls, identity, object_id): # NOSONAR pylint: disable=unused-private-member + """Read a single object_id from the device information. :param identity: The identity block to pull data from :param object_id: The specific object id to read :returns: The requested data (id, length, value) """ - return { object_id:identity[object_id] } + return {object_id: identity[object_id]} @classmethod - def __gets(cls, identity, object_ids): #NOSONAR pylint: disable=unused-private-member - """ Read multiple object_ids from the device information + def __gets(cls, identity, object_ids): # NOSONAR pylint: disable=unused-private-member + """Read multiple object_ids from the device information. :param identity: The identity block to pull data from :param object_ids: The specific object ids to read @@ -332,11 +336,11 @@ def __gets(cls, identity, object_ids): #NOSONAR pylint: disable=unused-private-m return dict((oid, identity[oid]) for oid in object_ids if identity[oid]) -#---------------------------------------------------------------------------# -# Counters Handler -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Counters Handler +# ---------------------------------------------------------------------------# class ModbusCountersHandler: - """ This is a helper class to simplify the properties for the counters:: + """This is a helper class to simplify the properties for the counters. 0x0B 1 Return Bus Message Count @@ -403,8 +407,9 @@ class ModbusCountersHandler: .. note:: I threw the event counter in here for convenience """ - __data = dict([(i, 0x0000) for i in range(9)]) # pylint: disable=consider-using-dict-comprehension - __names = [ + + __data = dict([(i, 0x0000) for i in range(9)]) # pylint: disable=consider-using-dict-comprehension + __names = [ 'BusMessage', 'BusCommunicationError', 'SlaveExceptionError', @@ -417,14 +422,15 @@ class ModbusCountersHandler: ] def __iter__(self): - """ Iterator over the device counters + """Iterate over the device counters. :returns: An iterator of the device counters """ return zip(self.__names, iter(self.__data.values())) def update(self, values): - """ Update the values of this identity + """Update the values of this identity. + using another identify as the value :param values: The value to copy values from @@ -434,41 +440,40 @@ def update(self, values): self.__setattr__(k, v_item) def reset(self): - """ This clears all of the system counters - """ - self.__data = dict([(i, 0x0000) for i in range(9)]) # pylint: disable=consider-using-dict-comprehension + """Clear all of the system counters.""" + self.__data = dict([(i, 0x0000) for i in range(9)]) # pylint: disable=consider-using-dict-comprehension def summary(self): - """ Returns a summary of the counters current status + """Return a summary of the counters current status. :returns: A byte with each bit representing each counter """ count, result = 0x01, 0x00 for i in iter(self.__data.values()): - if i != 0x00: # pylint: disable=compare-to-zero + if i != 0x00: # pylint: disable=compare-to-zero result |= count count <<= 1 return result - #-------------------------------------------------------------------------# - # Properties - #---------k----------------------------------------------------------------# - BusMessage = dict_property(lambda s: s.__data, 0) #NOSONAR pylint: disable=protected-access - BusCommunicationError = dict_property(lambda s: s.__data, 1) #NOSONAR pylint: disable=protected-access - BusExceptionError = dict_property(lambda s: s.__data, 2) #NOSONAR pylint: disable=protected-access - SlaveMessage = dict_property(lambda s: s.__data, 3) #NOSONAR pylint: disable=protected-access - SlaveNoResponse = dict_property(lambda s: s.__data, 4) #NOSONAR pylint: disable=protected-access - SlaveNAK = dict_property(lambda s: s.__data, 5) #NOSONAR pylint: disable=protected-access - SlaveBusy = dict_property(lambda s: s.__data, 6) #NOSONAR pylint: disable=protected-access - BusCharacterOverrun = dict_property(lambda s: s.__data, 7) #NOSONAR pylint: disable=protected-access - Event = dict_property(lambda s: s.__data, 8) #NOSONAR pylint: disable=protected-access - - -#---------------------------------------------------------------------------# -# Main server control block -#---------------------------------------------------------------------------# + # -------------------------------------------------------------------------# + # Properties + # -------------------------------------------------------------------------# + BusMessage = dict_property(lambda s: s.__data, 0) # NOSONAR pylint: disable=protected-access + BusCommunicationError = dict_property(lambda s: s.__data, 1) # NOSONAR pylint: disable=protected-access + BusExceptionError = dict_property(lambda s: s.__data, 2) # NOSONAR pylint: disable=protected-access + SlaveMessage = dict_property(lambda s: s.__data, 3) # NOSONAR pylint: disable=protected-access + SlaveNoResponse = dict_property(lambda s: s.__data, 4) # NOSONAR pylint: disable=protected-access + SlaveNAK = dict_property(lambda s: s.__data, 5) # NOSONAR pylint: disable=protected-access + SlaveBusy = dict_property(lambda s: s.__data, 6) # NOSONAR pylint: disable=protected-access + BusCharacterOverrun = dict_property(lambda s: s.__data, 7) # NOSONAR pylint: disable=protected-access + Event = dict_property(lambda s: s.__data, 8) # NOSONAR pylint: disable=protected-access + + +# ---------------------------------------------------------------------------# +# Main server control block +# ---------------------------------------------------------------------------# class ModbusControlBlock(Singleton): - """ This is a global singleton that controls all system information + """This is a global singleton that controls all system information. All activity should be logged here and all diagnostic requests should come from here. @@ -481,31 +486,31 @@ class ModbusControlBlock(Singleton): __delimiter = '\r' __counters = ModbusCountersHandler() __identity = ModbusDeviceIdentification() - __plus = ModbusPlusStatistics() - __events = [] + __plus = ModbusPlusStatistics() + __events = [] - #-------------------------------------------------------------------------# - # Magic - #-------------------------------------------------------------------------# + # -------------------------------------------------------------------------# + # Magic + # -------------------------------------------------------------------------# def __str__(self): - """ Build a representation of the control block + """Build a representation of the control block. :returns: A string representation of the control block """ return "ModbusControl" def __iter__(self): - """ Iterator over the device counters + """Iterate over the device counters. :returns: An iterator of the device counters """ return self.__counters.__iter__() - #-------------------------------------------------------------------------# - # Events - #-------------------------------------------------------------------------# - def addEvent(self, event): # pylint: disable=invalid-name - """ Adds a new event to the event log + # -------------------------------------------------------------------------# + # Events + # -------------------------------------------------------------------------# + def addEvent(self, event): # pylint: disable=invalid-name + """Add a new event to the event log. :param event: A new event to add to the log """ @@ -513,82 +518,79 @@ def addEvent(self, event): # pylint: disable=invalid-name self.__events = self.__events[0:64] # chomp to 64 entries self.Counter.Event += 1 - def getEvents(self): # pylint: disable=invalid-name - """ Returns an encoded collection of the event log. + def getEvents(self): # pylint: disable=invalid-name + """Return an encoded collection of the event log. :returns: The encoded events packet """ events = [event.encode() for event in self.__events] return b''.join(events) - def clearEvents(self): # pylint: disable=invalid-name - """ Clears the current list of events - """ + def clearEvents(self): # pylint: disable=invalid-name + """Clear the current list of events.""" self.__events = [] - #-------------------------------------------------------------------------# - # Other Properties - #-------------------------------------------------------------------------# + # -------------------------------------------------------------------------# + # Other Properties + # -------------------------------------------------------------------------# Identity = property(lambda s: s.__identity) - Counter = property(lambda s: s.__counters) - Events = property(lambda s: s.__events) - Plus = property(lambda s: s.__plus) + Counter = property(lambda s: s.__counters) + Events = property(lambda s: s.__events) + Plus = property(lambda s: s.__plus) def reset(self): - """ This clears all of the system counters and the - diagnostic register - """ + """Clear all of the system counters and the diagnostic register.""" self.__events = [] self.__counters.reset() self.__diagnostic = [False] * 16 - #-------------------------------------------------------------------------# - # Listen Properties - #-------------------------------------------------------------------------# - def _setListenOnly(self, value): # pylint: disable=invalid-name - """ This toggles the listen only status + # -------------------------------------------------------------------------# + # Listen Properties + # -------------------------------------------------------------------------# + def _setListenOnly(self, value): # pylint: disable=invalid-name + """Toggle the listen only status. :param value: The value to set the listen status to """ - self.__listen_only = bool(value) # pylint: disable=unused-private-member + self.__listen_only = bool(value) # pylint: disable=unused-private-member ListenOnly = property(lambda s: s.__listen_only, _setListenOnly) - #-------------------------------------------------------------------------# - # Mode Properties - #-------------------------------------------------------------------------# - def _setMode(self, mode): # pylint: disable=invalid-name - """ This toggles the current serial mode + # -------------------------------------------------------------------------# + # Mode Properties + # -------------------------------------------------------------------------# + def _setMode(self, mode): # pylint: disable=invalid-name + """Toggle the current serial mode. :param mode: The data transfer method in (RTU, ASCII) """ if mode in set(['ASCII', 'RTU']): - self.__mode = mode # pylint: disable=unused-private-member + self.__mode = mode # pylint: disable=unused-private-member Mode = property(lambda s: s.__mode, _setMode) - #-------------------------------------------------------------------------# - # Delimiter Properties - #-------------------------------------------------------------------------# - def _setDelimiter(self, char): # pylint: disable=invalid-name - """ This changes the serial delimiter character + # -------------------------------------------------------------------------# + # Delimiter Properties + # -------------------------------------------------------------------------# + def _setDelimiter(self, char): # pylint: disable=invalid-name + """Change the serial delimiter character. :param char: The new serial delimiter character """ if isinstance(char, str): - self.__delimiter = char.encode() # pylint: disable=unused-private-member + self.__delimiter = char.encode() # pylint: disable=unused-private-member if isinstance(char, bytes): - self.__delimiter = char # pylint: disable=unused-private-member + self.__delimiter = char # pylint: disable=unused-private-member elif isinstance(char, int): - self.__delimiter = struct.pack(">B", char) # pylint: disable=unused-private-member + self.__delimiter = struct.pack(">B", char) # pylint: disable=unused-private-member Delimiter = property(lambda s: s.__delimiter, _setDelimiter) - #-------------------------------------------------------------------------# - # Diagnostic Properties - #-------------------------------------------------------------------------# - def setDiagnostic(self, mapping): # pylint: disable=invalid-name - """ This sets the value in the diagnostic register + # -------------------------------------------------------------------------# + # Diagnostic Properties + # -------------------------------------------------------------------------# + def setDiagnostic(self, mapping): # pylint: disable=invalid-name + """Set the value in the diagnostic register. :param mapping: Dictionary of key:value pairs to set """ @@ -596,8 +598,8 @@ def setDiagnostic(self, mapping): # pylint: disable=invalid-name if entry[0] >= 0 and entry[0] < len(self.__diagnostic): self.__diagnostic[entry[0]] = bool(entry[1]) - def getDiagnostic(self, bit): # pylint: disable=invalid-name - """ This gets the value in the diagnostic register + def getDiagnostic(self, bit): # pylint: disable=invalid-name + """Get the value in the diagnostic register. :param bit: The bit to get :returns: The current value of the requested bit @@ -605,24 +607,25 @@ def getDiagnostic(self, bit): # pylint: disable=invalid-name try: if bit and 0 <= bit < len(self.__diagnostic): return self.__diagnostic[bit] - except Exception: # pylint: disable=broad-except + except Exception: # pylint: disable=broad-except return None return None - def getDiagnosticRegister(self): # pylint: disable=invalid-name - """ This gets the entire diagnostic register + def getDiagnosticRegister(self): # pylint: disable=invalid-name + """Get the entire diagnostic register. :returns: The diagnostic register collection """ return self.__diagnostic -#---------------------------------------------------------------------------# -# Exported Identifiers -#---------------------------------------------------------------------------# + +# ---------------------------------------------------------------------------# +# Exported Identifiers +# ---------------------------------------------------------------------------# __all__ = [ - "ModbusAccessControl", - "ModbusPlusStatistics", - "ModbusDeviceIdentification", - "DeviceInformationFactory", - "ModbusControlBlock" + "ModbusAccessControl", + "ModbusPlusStatistics", + "ModbusDeviceIdentification", + "DeviceInformationFactory", + "ModbusControlBlock" ] diff --git a/pymodbus/diag_message.py b/pymodbus/diag_message.py index d2eb295bb..553c12e9e 100644 --- a/pymodbus/diag_message.py +++ b/pymodbus/diag_message.py @@ -1,5 +1,4 @@ -""" Diagnostic Record Read/Write ------------------------------- +"""Diagnostic Record Read/Write. These need to be tied into a the current server context or linked to the appropriate data @@ -16,24 +15,26 @@ _MCB = ModbusControlBlock() -#---------------------------------------------------------------------------# -# Diagnostic Function Codes Base Classes -# diagnostic 08, 00-18,20 -#---------------------------------------------------------------------------# -# TODO Make sure all the data is decoded from the response # pylint: disable=fixme -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Diagnostic Function Codes Base Classes +# diagnostic 08, 00-18,20 +# ---------------------------------------------------------------------------# +# TODO Make sure all the data is decoded from the response # pylint: disable=fixme +# ---------------------------------------------------------------------------# class DiagnosticStatusRequest(ModbusRequest): - """ This is a base class for all of the diagnostic request functions. """ + """This is a base class for all of the diagnostic request functions.""" + function_code = 0x08 _rtu_frame_size = 8 def __init__(self, **kwargs): - """ Base initializer for a diagnostic request. """ + """Initialize a diagnostic request.""" ModbusRequest.__init__(self, **kwargs) self.message = None def encode(self): - """ Base encoder for a diagnostic response + """Encode a diagnostic response. + we encode the data set in self.message :returns: The encoded packet @@ -52,38 +53,44 @@ def encode(self): return packet def decode(self, data): - """ Base decoder for a diagnostic request + """Decode a diagnostic request. :param data: The data to decode into the function code """ - self.sub_function_code, self.message = struct.unpack('>HH', data) # pylint: disable=attribute-defined-outside-init + self.sub_function_code, self.message = struct.unpack('>HH', data) # pylint: disable=W0201 def get_response_pdu_size(self): - """ Func_code (1 byte) + Sub function code (2 byte) + Data (2 * N bytes) + """Get response pdu size. + + Func_code (1 byte) + Sub function code (2 byte) + Data (2 * N bytes) :return: """ - if not isinstance(self.message,list): + if not isinstance(self.message, list): self.message = [self.message] return 1 + 2 + 2 * len(self.message) class DiagnosticStatusResponse(ModbusResponse): - """ This is a base class for all of the diagnostic response functions + """Diagnostic status. + + This is a base class for all of the diagnostic response functions It works by performing all of the encoding and decoding of variable data and lets the higher classes define what extra data to append and how to execute a request """ + function_code = 0x08 _rtu_frame_size = 8 def __init__(self, **kwargs): - """ Base initializer for a diagnostic response. """ + """Initialize a diagnostic response.""" ModbusResponse.__init__(self, **kwargs) self.message = None def encode(self): - """ Base encoder for a diagnostic response + """Encode diagnostic response. + we encode the data set in self.message :returns: The encoded packet @@ -102,20 +109,22 @@ def encode(self): return packet def decode(self, data): - """ Base decoder for a diagnostic response + """Decode diagnostic response. :param data: The data to decode into the function code """ - word_len = len(data)//2 + word_len = len(data) // 2 if len(data) % 2: word_len += 1 data = data + b'0' - data = struct.unpack('>' + 'H'*word_len, data) - self.sub_function_code, self.message = data[0], data[1:] # pylint: disable=attribute-defined-outside-init + data = struct.unpack('>' + 'H' * word_len, data) + self.sub_function_code, self.message = data[0], data[1:] # pylint: disable=attribute-defined-outside-init class DiagnosticStatusSimpleRequest(DiagnosticStatusRequest): - """ A large majority of the diagnostic functions are simple + """Return diagnostic status. + + A large majority of the diagnostic functions are simple status request functions. They work by sending 0x0000 as data and their function code and they are returned 2 bytes of data. @@ -125,7 +134,7 @@ class DiagnosticStatusSimpleRequest(DiagnosticStatusRequest): """ def __init__(self, data=0x0000, **kwargs): - """ General initializer for a simple diagnostic request + """Initialize a simple diagnostic request The data defaults to 0x0000 if not provided as over half of the functions require it. @@ -135,20 +144,22 @@ def __init__(self, data=0x0000, **kwargs): DiagnosticStatusRequest.__init__(self, **kwargs) self.message = data - def execute(self, *args): # pylint: disable=no-self-use - """ Base function to raise if not implemented """ + def execute(self, *args): # pylint: disable=no-self-use + """Raise if not implemented.""" raise NotImplementedException("Diagnostic Message Has No Execute Method") class DiagnosticStatusSimpleResponse(DiagnosticStatusResponse): - """ A large majority of the diagnostic functions are simple + """Diagnostic status. + + A large majority of the diagnostic functions are simple status request functions. They work by sending 0x0000 as data and their function code and they are returned 2 bytes of data. """ def __init__(self, data=0x0000, **kwargs): - """ General initializer for a simple diagnostic response + """Return a simple diagnostic response. :param data: The resulting data to return to the client """ @@ -156,18 +167,21 @@ def __init__(self, data=0x0000, **kwargs): self.message = data -#---------------------------------------------------------------------------# -# Diagnostic Sub Code 00 -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Diagnostic Sub Code 00 +# ---------------------------------------------------------------------------# class ReturnQueryDataRequest(DiagnosticStatusRequest): - """ The data passed in the request data field is to be returned (looped back) + """Return query data. + + The data passed in the request data field is to be returned (looped back) in the response. The entire response message should be identical to the request. """ + sub_function_code = 0x0000 def __init__(self, message=0x0000, **kwargs): - """ Initializes a new instance of the request + """Initialize a new instance of the request. :param message: The message to send to loopback """ @@ -177,8 +191,8 @@ def __init__(self, message=0x0000, **kwargs): else: self.message = [message] - def execute(self, *args): # pylint: disable=unused-argument - """ Executes the loopback request (builds the response) + def execute(self, *args): # pylint: disable=unused-argument + """Execute the loopback request (builds the response). :returns: The populated loopback response message """ @@ -186,180 +200,206 @@ def execute(self, *args): # pylint: disable=unused-argument class ReturnQueryDataResponse(DiagnosticStatusResponse): - """ The data passed in the request data field is to be returned (looped back) + """Return query data. + + The data passed in the request data field is to be returned (looped back) in the response. The entire response message should be identical to the request. """ + sub_function_code = 0x0000 def __init__(self, message=0x0000, **kwargs): - """ Initializes a new instance of the response + """Initialize a new instance of the response. :param message: The message to loopback """ DiagnosticStatusResponse.__init__(self, **kwargs) if isinstance(message, list): self.message = message - else: self.message = [message] + else: + self.message = [message] -#---------------------------------------------------------------------------# -# Diagnostic Sub Code 01 -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Diagnostic Sub Code 01 +# ---------------------------------------------------------------------------# class RestartCommunicationsOptionRequest(DiagnosticStatusRequest): - """ The remote device serial line port must be initialized and restarted, and + """Restart communication. + + The remote device serial line port must be initialized and restarted, and all of its communications event counters are cleared. If the port is currently in Listen Only Mode, no response is returned. This function is the only one that brings the port out of Listen Only Mode. If the port is not currently in Listen Only Mode, a normal response is returned. This occurs before the restart is executed. """ + sub_function_code = 0x0001 def __init__(self, toggle=False, **kwargs): - """ Initializes a new request + """Initialize a new request. :param toggle: Set to True to toggle, False otherwise """ DiagnosticStatusRequest.__init__(self, **kwargs) if toggle: - self.message = [ModbusStatus.On] - else: self.message = [ModbusStatus.Off] + self.message = [ModbusStatus.On] + else: + self.message = [ModbusStatus.Off] - def execute(self, *args): # pylint: disable=unused-argument - """ Clear event log and restart + def execute(self, *args): # pylint: disable=unused-argument + """Clear event log and restart. :returns: The initialized response message """ - #if _MCB.ListenOnly: + # if _MCB.ListenOnly: return RestartCommunicationsOptionResponse(self.message) + class RestartCommunicationsOptionResponse(DiagnosticStatusResponse): - """ The remote device serial line port must be initialized and restarted, and + """Restart Communication. + + The remote device serial line port must be initialized and restarted, and all of its communications event counters are cleared. If the port is currently in Listen Only Mode, no response is returned. This function is the only one that brings the port out of Listen Only Mode. If the port is not currently in Listen Only Mode, a normal response is returned. This occurs before the restart is executed. """ + sub_function_code = 0x0001 def __init__(self, toggle=False, **kwargs): - """ Initializes a new response + """Initialize a new response. :param toggle: Set to True if we toggled, False otherwise """ DiagnosticStatusResponse.__init__(self, **kwargs) if toggle: - self.message = [ModbusStatus.On] - else: self.message = [ModbusStatus.Off] + self.message = [ModbusStatus.On] + else: + self.message = [ModbusStatus.Off] -#---------------------------------------------------------------------------# -# Diagnostic Sub Code 02 -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Diagnostic Sub Code 02 +# ---------------------------------------------------------------------------# class ReturnDiagnosticRegisterRequest(DiagnosticStatusSimpleRequest): - """ The contents of the remote device's 16-bit diagnostic register are - returned in the response - """ + """The contents of the remote device's 16-bit diagnostic register are returned in the response.""" + sub_function_code = 0x0002 def execute(self, *args): - """ Execute the diagnostic request on the given device + """Execute the diagnostic request on the given device. :returns: The initialized response message """ - #if _MCB.isListenOnly(): + # if _MCB.isListenOnly(): register = pack_bitstring(_MCB.getDiagnosticRegister()) return ReturnDiagnosticRegisterResponse(register) class ReturnDiagnosticRegisterResponse(DiagnosticStatusSimpleResponse): - """ The contents of the remote device's 16-bit diagnostic register are + """Return diagnostic register. + + The contents of the remote device's 16-bit diagnostic register are returned in the response """ + sub_function_code = 0x0002 -#---------------------------------------------------------------------------# -# Diagnostic Sub Code 03 -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Diagnostic Sub Code 03 +# ---------------------------------------------------------------------------# class ChangeAsciiInputDelimiterRequest(DiagnosticStatusSimpleRequest): - """ The character 'CHAR' passed in the request data field becomes the end of + """Change ascii input delimiter. + + The character 'CHAR' passed in the request data field becomes the end of message delimiter for future messages (replacing the default LF character). This function is useful in cases of a Line Feed is not required at the end of ASCII messages. """ + sub_function_code = 0x0003 def execute(self, *args): - """ Execute the diagnostic request on the given device + """Execute the diagnostic request on the given device. :returns: The initialized response message """ char = (self.message & 0xff00) >> 8 - _MCB._setDelimiter(char) # pylint: disable=protected-access + _MCB._setDelimiter(char) # pylint: disable=protected-access return ChangeAsciiInputDelimiterResponse(self.message) class ChangeAsciiInputDelimiterResponse(DiagnosticStatusSimpleResponse): - """ The character 'CHAR' passed in the request data field becomes the end of + """Change ascii input delimiter. + + The character 'CHAR' passed in the request data field becomes the end of message delimiter for future messages (replacing the default LF character). This function is useful in cases of a Line Feed is not required at the end of ASCII messages. """ + sub_function_code = 0x0003 -#---------------------------------------------------------------------------# -# Diagnostic Sub Code 04 -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Diagnostic Sub Code 04 +# ---------------------------------------------------------------------------# class ForceListenOnlyModeRequest(DiagnosticStatusSimpleRequest): - """ Forces the addressed remote device to its Listen Only Mode for MODBUS - communications. This isolates it from the other devices on the network, + """Forces the addressed remote device to its Listen Only Mode for MODBUS communications. + + This isolates it from the other devices on the network, allowing them to continue communicating without interruption from the addressed remote device. No response is returned. """ + sub_function_code = 0x0004 def execute(self, *args): - """ Execute the diagnostic request on the given device + """Execute the diagnostic request on the given device. :returns: The initialized response message """ - _MCB._setListenOnly(True) # pylint: disable=protected-access + _MCB._setListenOnly(True) # pylint: disable=protected-access return ForceListenOnlyModeResponse() class ForceListenOnlyModeResponse(DiagnosticStatusResponse): - """ Forces the addressed remote device to its Listen Only Mode for MODBUS - communications. This isolates it from the other devices on the network, + """Forces the addressed remote device to its Listen Only Mode for MODBUS communications. + + This isolates it from the other devices on the network, allowing them to continue communicating without interruption from the addressed remote device. No response is returned. This does not send a response """ + sub_function_code = 0x0004 - should_respond = False + should_respond = False def __init__(self, **kwargs): - """ Initializer to block a return response - """ + """Initialize to block a return response.""" DiagnosticStatusResponse.__init__(self, **kwargs) self.message = [] -#---------------------------------------------------------------------------# -# Diagnostic Sub Code 10 -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Diagnostic Sub Code 10 +# ---------------------------------------------------------------------------# class ClearCountersRequest(DiagnosticStatusSimpleRequest): - """ The goal is to clear ll counters and the diagnostic register. + """Clear ll counters and the diagnostic register. + Also, counters are cleared upon power-up """ + sub_function_code = 0x000A def execute(self, *args): - """ Execute the diagnostic request on the given device + """Execute the diagnostic request on the given device. :returns: The initialized response message """ @@ -368,24 +408,29 @@ def execute(self, *args): class ClearCountersResponse(DiagnosticStatusSimpleResponse): - """ The goal is to clear ll counters and the diagnostic register. + """Clear ll counters and the diagnostic register. + Also, counters are cleared upon power-up """ + sub_function_code = 0x000A -#---------------------------------------------------------------------------# -# Diagnostic Sub Code 11 -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Diagnostic Sub Code 11 +# ---------------------------------------------------------------------------# class ReturnBusMessageCountRequest(DiagnosticStatusSimpleRequest): - """ The response data field returns the quantity of messages that the + """Return bus message count. + + The response data field returns the quantity of messages that the remote device has detected on the communications systems since its last restart, clear counters operation, or power-up """ + sub_function_code = 0x000B def execute(self, *args): - """ Execute the diagnostic request on the given device + """Execute the diagnostic request on the given device. :returns: The initialized response message """ @@ -394,25 +439,31 @@ def execute(self, *args): class ReturnBusMessageCountResponse(DiagnosticStatusSimpleResponse): - """ The response data field returns the quantity of messages that the + """Return bus message count. + + The response data field returns the quantity of messages that the remote device has detected on the communications systems since its last restart, clear counters operation, or power-up """ + sub_function_code = 0x000B -#---------------------------------------------------------------------------# -# Diagnostic Sub Code 12 -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Diagnostic Sub Code 12 +# ---------------------------------------------------------------------------# class ReturnBusCommunicationErrorCountRequest(DiagnosticStatusSimpleRequest): - """ The response data field returns the quantity of CRC errors encountered + """Return bus comm. count. + + The response data field returns the quantity of CRC errors encountered by the remote device since its last restart, clear counter operation, or power-up """ + sub_function_code = 0x000C def execute(self, *args): - """ Execute the diagnostic request on the given device + """Execute the diagnostic request on the given device. :returns: The initialized response message """ @@ -421,25 +472,31 @@ def execute(self, *args): class ReturnBusCommunicationErrorCountResponse(DiagnosticStatusSimpleResponse): - """ The response data field returns the quantity of CRC errors encountered + """Return bus comm. error. + + The response data field returns the quantity of CRC errors encountered by the remote device since its last restart, clear counter operation, or power-up """ + sub_function_code = 0x000C -#---------------------------------------------------------------------------# -# Diagnostic Sub Code 13 -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Diagnostic Sub Code 13 +# ---------------------------------------------------------------------------# class ReturnBusExceptionErrorCountRequest(DiagnosticStatusSimpleRequest): - """ The response data field returns the quantity of modbus exception + """Return bus exception. + + The response data field returns the quantity of modbus exception responses returned by the remote device since its last restart, clear counters operation, or power-up """ + sub_function_code = 0x000D def execute(self, *args): - """ Execute the diagnostic request on the given device + """Execute the diagnostic request on the given device. :returns: The initialized response message """ @@ -448,25 +505,31 @@ def execute(self, *args): class ReturnBusExceptionErrorCountResponse(DiagnosticStatusSimpleResponse): - """ The response data field returns the quantity of modbus exception + """Return bus exception. + + The response data field returns the quantity of modbus exception responses returned by the remote device since its last restart, clear counters operation, or power-up """ + sub_function_code = 0x000D -#---------------------------------------------------------------------------# -# Diagnostic Sub Code 14 -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Diagnostic Sub Code 14 +# ---------------------------------------------------------------------------# class ReturnSlaveMessageCountRequest(DiagnosticStatusSimpleRequest): - """ The response data field returns the quantity of messages addressed to the + """Return slave message count. + + The response data field returns the quantity of messages addressed to the remote device, or broadcast, that the remote device has processed since its last restart, clear counters operation, or power-up """ + sub_function_code = 0x000E def execute(self, *args): - """ Execute the diagnostic request on the given device + """Execute the diagnostic request on the given device. :returns: The initialized response message """ @@ -475,25 +538,31 @@ def execute(self, *args): class ReturnSlaveMessageCountResponse(DiagnosticStatusSimpleResponse): - """ The response data field returns the quantity of messages addressed to the + """Return slave message count. + + The response data field returns the quantity of messages addressed to the remote device, or broadcast, that the remote device has processed since its last restart, clear counters operation, or power-up """ + sub_function_code = 0x000E -#---------------------------------------------------------------------------# -# Diagnostic Sub Code 15 -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Diagnostic Sub Code 15 +# ---------------------------------------------------------------------------# class ReturnSlaveNoResponseCountRequest(DiagnosticStatusSimpleRequest): - """ The response data field returns the quantity of messages addressed to the + """Return slave no response. + + The response data field returns the quantity of messages addressed to the remote device, or broadcast, that the remote device has processed since its last restart, clear counters operation, or power-up """ + sub_function_code = 0x000F def execute(self, *args): - """ Execute the diagnostic request on the given device + """Execute the diagnostic request on the given device. :returns: The initialized response message """ @@ -502,26 +571,32 @@ def execute(self, *args): class ReturnSlaveNoReponseCountResponse(DiagnosticStatusSimpleResponse): - """ The response data field returns the quantity of messages addressed to the + """Return slave no response. + + The response data field returns the quantity of messages addressed to the remote device, or broadcast, that the remote device has processed since its last restart, clear counters operation, or power-up """ + sub_function_code = 0x000F -#---------------------------------------------------------------------------# -# Diagnostic Sub Code 16 -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Diagnostic Sub Code 16 +# ---------------------------------------------------------------------------# class ReturnSlaveNAKCountRequest(DiagnosticStatusSimpleRequest): - """ The response data field returns the quantity of messages addressed to the + """Return slave NAK count. + + The response data field returns the quantity of messages addressed to the remote device for which it returned a Negative Acknowledge (NAK) exception response, since its last restart, clear counters operation, or power-up. Exception responses are described and listed in section 7 . """ + sub_function_code = 0x0010 def execute(self, *args): - """ Execute the diagnostic request on the given device + """Execute the diagnostic request on the given device. :returns: The initialized response message """ @@ -530,26 +605,32 @@ def execute(self, *args): class ReturnSlaveNAKCountResponse(DiagnosticStatusSimpleResponse): - """ The response data field returns the quantity of messages addressed to the + """Return slave NAK. + + The response data field returns the quantity of messages addressed to the remote device for which it returned a Negative Acknowledge (NAK) exception response, since its last restart, clear counters operation, or power-up. Exception responses are described and listed in section 7. """ + sub_function_code = 0x0010 -#---------------------------------------------------------------------------# -# Diagnostic Sub Code 17 -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Diagnostic Sub Code 17 +# ---------------------------------------------------------------------------# class ReturnSlaveBusyCountRequest(DiagnosticStatusSimpleRequest): - """ The response data field returns the quantity of messages addressed to the + """Return slave busy count. + + The response data field returns the quantity of messages addressed to the remote device for which it returned a Slave Device Busy exception response, since its last restart, clear counters operation, or power-up. """ + sub_function_code = 0x0011 def execute(self, *args): - """ Execute the diagnostic request on the given device + """Execute the diagnostic request on the given device. :returns: The initialized response message """ @@ -558,27 +639,33 @@ def execute(self, *args): class ReturnSlaveBusyCountResponse(DiagnosticStatusSimpleResponse): - """ The response data field returns the quantity of messages addressed to the + """Return slave busy count. + + The response data field returns the quantity of messages addressed to the remote device for which it returned a Slave Device Busy exception response, since its last restart, clear counters operation, or power-up. """ + sub_function_code = 0x0011 -#---------------------------------------------------------------------------# -# Diagnostic Sub Code 18 -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Diagnostic Sub Code 18 +# ---------------------------------------------------------------------------# class ReturnSlaveBusCharacterOverrunCountRequest(DiagnosticStatusSimpleRequest): - """ The response data field returns the quantity of messages addressed to the + """Return slave character overrun. + + The response data field returns the quantity of messages addressed to the remote device that it could not handle due to a character overrun condition, since its last restart, clear counters operation, or power-up. A character overrun is caused by data characters arriving at the port faster than they can be stored, or by the loss of a character due to a hardware malfunction. """ + sub_function_code = 0x0012 def execute(self, *args): - """ Execute the diagnostic request on the given device + """Execute the diagnostic request on the given device. :returns: The initialized response message """ @@ -587,27 +674,31 @@ def execute(self, *args): class ReturnSlaveBusCharacterOverrunCountResponse(DiagnosticStatusSimpleResponse): - """ The response data field returns the quantity of messages addressed to the - remote device that it could not handle due to a character overrun condition, - since its last restart, clear counters operation, or power-up. A character + """Return the quantity of messages addressed to the remote device unhandled due to a character overrun. + + Since its last restart, clear counters operation, or power-up. A character overrun is caused by data characters arriving at the port faster than they can be stored, or by the loss of a character due to a hardware malfunction. """ + sub_function_code = 0x0012 -#---------------------------------------------------------------------------# -# Diagnostic Sub Code 19 -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Diagnostic Sub Code 19 +# ---------------------------------------------------------------------------# class ReturnIopOverrunCountRequest(DiagnosticStatusSimpleRequest): - """ An IOP overrun is caused by data characters arriving at the port + """Return IopOverrun. + + An IOP overrun is caused by data characters arriving at the port faster than they can be stored, or by the loss of a character due to a hardware malfunction. This function is specific to the 884. """ + sub_function_code = 0x0013 def execute(self, *args): - """ Execute the diagnostic request on the given device + """Execute the diagnostic request on the given device. :returns: The initialized response message """ @@ -616,27 +707,31 @@ def execute(self, *args): class ReturnIopOverrunCountResponse(DiagnosticStatusSimpleResponse): - """ The response data field returns the quantity of messages + """Return Iop overrun count. + + The response data field returns the quantity of messages addressed to the slave that it could not handle due to an 884 IOP overrun condition, since its last restart, clear counters operation, or power-up. """ + sub_function_code = 0x0013 -#---------------------------------------------------------------------------# -# Diagnostic Sub Code 20 -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Diagnostic Sub Code 20 +# ---------------------------------------------------------------------------# class ClearOverrunCountRequest(DiagnosticStatusSimpleRequest): - """ Clears the overrun error counter and reset the error flag + """Clear the overrun error counter and reset the error flag. An error flag should be cleared, but nothing else in the specification mentions is, so it is ignored. """ + sub_function_code = 0x0014 def execute(self, *args): - """ Execute the diagnostic request on the given device + """Execute the diagnostic request on the given device. :returns: The initialized response message """ @@ -645,15 +740,18 @@ def execute(self, *args): class ClearOverrunCountResponse(DiagnosticStatusSimpleResponse): - """ Clears the overrun error counter and reset the error flag. """ + """Clear the overrun error counter and reset the error flag.""" + sub_function_code = 0x0014 -#---------------------------------------------------------------------------# -# Diagnostic Sub Code 21 -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Diagnostic Sub Code 21 +# ---------------------------------------------------------------------------# class GetClearModbusPlusRequest(DiagnosticStatusSimpleRequest): - """ In addition to the Function code (08) and Subfunction code + """Get/Clear modbus plus request. + + In addition to the Function code (08) and Subfunction code (00 15 hex) in the query, a two-byte Operation field is used to specify either a 'Get Statistics' or a 'Clear Statistics' operation. The two operations are exclusive - the 'Get' @@ -662,30 +760,33 @@ class GetClearModbusPlusRequest(DiagnosticStatusSimpleRequest): them. Statistics are also cleared on power-up of the slave device. """ + sub_function_code = 0x0015 def __init__(self, **kwargs): + """Initialize.""" super().__init__(**kwargs) def get_response_pdu_size(self): - """ Returns a series of 54 16-bit words (108 bytes) in the data field of the response - (this function differs from the usual two-byte length of the data field). The data - contains the statistics for the Modbus Plus peer processor in the slave device. + """Return a series of 54 16-bit words (108 bytes) in the data field of the response. + + This function differs from the usual two-byte length of the data field. + The data contains the statistics for the Modbus Plus peer processor in the slave device. Func_code (1 byte) + Sub function code (2 byte) + Operation (2 byte) + Data (108 bytes) :return: """ if self.message == ModbusPlusOperation.GetStatistics: - data = 2 + 108 # byte count(2) + data (54*2) + data = 2 + 108 # byte count(2) + data (54*2) else: data = 0 - return 1 + 2 + 2 + 2+ data + return 1 + 2 + 2 + 2 + data def execute(self, *args): - """ Execute the diagnostic request on the given device + """Execute the diagnostic request on the given device. :returns: The initialized response message """ - message = None # the clear operation does not return info + message = None # the clear operation does not return info if self.message == ModbusPlusOperation.ClearStatistics: _MCB.Plus.reset() message = self.message @@ -695,7 +796,8 @@ def execute(self, *args): return GetClearModbusPlusResponse(message) def encode(self): - """ Base encoder for a diagnostic response + """Encode a diagnostic response. + we encode the data set in self.message :returns: The encoded packet @@ -706,17 +808,18 @@ def encode(self): class GetClearModbusPlusResponse(DiagnosticStatusSimpleResponse): - """ Returns a series of 54 16-bit words (108 bytes) in the data field - of the response (this function differs from the usual two-byte - length of the data field). The data contains the statistics for - the Modbus Plus peer processor in the slave device. + """Return a series of 54 16-bit words (108 bytes) in the data field of the response. + + This function differs from the usual two-byte length of the data field. + The data contains the statistics for the Modbus Plus peer processor in the slave device. """ + sub_function_code = 0x0015 -#---------------------------------------------------------------------------# -# Exported symbols -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Exported symbols +# ---------------------------------------------------------------------------# __all__ = [ "DiagnosticStatusRequest", "DiagnosticStatusResponse", "ReturnQueryDataRequest", "ReturnQueryDataResponse", diff --git a/pymodbus/events.py b/pymodbus/events.py index dfdf5463e..640fe93b3 100644 --- a/pymodbus/events.py +++ b/pymodbus/events.py @@ -1,5 +1,4 @@ -""" Modbus Remote Events ------------------------------------------------------------- +"""Modbus Remote Events. An event byte returned by the Get Communications Event Log function can be any one of four types. The type is defined by bit 7 @@ -13,15 +12,15 @@ class ModbusEvent: """Define modbus events.""" - def encode(self): # pylint: disable=no-self-use - """ Encodes the status bits to an event message + def encode(self): # pylint: disable=no-self-use + """Encode the status bits to an event message. :returns: The encoded event message """ raise NotImplementedException() - def decode(self, event): # pylint: disable=no-self-use - """ Decodes the event message to its status bits + def decode(self, event): # pylint: disable=no-self-use + """Decode the event message to its status bits. :param event: The event to decode """ @@ -29,7 +28,7 @@ def decode(self, event): # pylint: disable=no-self-use class RemoteReceiveEvent(ModbusEvent): - """ Remote device MODBUS Receive Event + """Remote device MODBUS Receive Event. The remote device stores this type of event byte when a query message is received. It is stored before the remote device processes the message. @@ -49,35 +48,34 @@ class RemoteReceiveEvent(ModbusEvent): """ def __init__(self, **kwargs): - """ Initialize a new event instance - """ - self.overrun = kwargs.get('overrun', False) - self.listen = kwargs.get('listen', False) + """Initialize a new event instance.""" + self.overrun = kwargs.get('overrun', False) + self.listen = kwargs.get('listen', False) self.broadcast = kwargs.get('broadcast', False) def encode(self): - """ Encodes the status bits to an event message + """Encode the status bits to an event message. :returns: The encoded event message """ - bits = [False] * 3 + bits = [False] * 3 bits += [self.overrun, self.listen, self.broadcast, True] packet = pack_bitstring(bits) return packet def decode(self, event): - """ Decodes the event message to its status bits + """Decode the event message to its status bits. :param event: The event to decode """ bits = unpack_bitstring(event) - self.overrun = bits[4] - self.listen = bits[5] + self.overrun = bits[4] + self.listen = bits[5] self.broadcast = bits[6] class RemoteSendEvent(ModbusEvent): - """ Remote device MODBUS Send Event + """Remote device MODBUS Send Event. The remote device stores this type of event byte when it finishes processing a request message. It is stored if the remote device @@ -100,43 +98,42 @@ class RemoteSendEvent(ModbusEvent): """ def __init__(self, **kwargs): - """ Initialize a new event instance - """ - self.read = kwargs.get('read', False) - self.slave_abort = kwargs.get('slave_abort', False) - self.slave_busy = kwargs.get('slave_busy', False) - self.slave_nak = kwargs.get('slave_nak', False) + """Initialize a new event instance.""" + self.read = kwargs.get('read', False) + self.slave_abort = kwargs.get('slave_abort', False) + self.slave_busy = kwargs.get('slave_busy', False) + self.slave_nak = kwargs.get('slave_nak', False) self.write_timeout = kwargs.get('write_timeout', False) - self.listen = kwargs.get('listen', False) + self.listen = kwargs.get('listen', False) def encode(self): - """ Encodes the status bits to an event message + """Encode the status bits to an event message. :returns: The encoded event message """ bits = [self.read, self.slave_abort, self.slave_busy, - self.slave_nak, self.write_timeout, self.listen] - bits += [True, False] + self.slave_nak, self.write_timeout, self.listen] + bits += [True, False] packet = pack_bitstring(bits) return packet def decode(self, event): - """ Decodes the event message to its status bits + """Decode the event message to its status bits. :param event: The event to decode """ - #NOSONAR todo fix the start byte count + # NOSONAR todo fix the start byte count bits = unpack_bitstring(event) - self.read = bits[0] - self.slave_abort = bits[1] - self.slave_busy = bits[2] - self.slave_nak = bits[3] + self.read = bits[0] + self.slave_abort = bits[1] + self.slave_busy = bits[2] + self.slave_nak = bits[3] self.write_timeout = bits[4] - self.listen = bits[5] + self.listen = bits[5] class EnteredListenModeEvent(ModbusEvent): - """ Remote device Entered Listen Only Mode + """Enter Remote device Listen Only Mode The remote device stores this type of event byte when it enters the Listen Only Mode. The event is defined by a content of 04 hex. @@ -146,14 +143,14 @@ class EnteredListenModeEvent(ModbusEvent): __encoded = b'\x04' def encode(self): - """ Encodes the status bits to an event message + """Encode the status bits to an event message. :returns: The encoded event message """ return self.__encoded def decode(self, event): - """ Decodes the event message to its status bits + """Decode the event message to its status bits. :param event: The event to decode """ @@ -162,7 +159,7 @@ def decode(self, event): class CommunicationRestartEvent(ModbusEvent): - """ Remote device Initiated Communication Restart + """Restart remote device Initiated Communication. The remote device stores this type of event byte when its communications port is restarted. The remote device can be restarted by the Diagnostics @@ -182,14 +179,14 @@ class CommunicationRestartEvent(ModbusEvent): __encoded = b'\x00' def encode(self): - """ Encodes the status bits to an event message + """Encode the status bits to an event message. :returns: The encoded event message """ return self.__encoded def decode(self, event): - """ Decodes the event message to its status bits + """Decode the event message to its status bits. :param event: The event to decode """ diff --git a/pymodbus/exceptions.py b/pymodbus/exceptions.py index 365e4376b..da969b230 100644 --- a/pymodbus/exceptions.py +++ b/pymodbus/exceptions.py @@ -1,33 +1,35 @@ -""" Pymodbus Exceptions --------------------- +"""Pymodbus Exceptions. Custom exceptions to be used in the Modbus code. """ class ModbusException(Exception): - """ Base modbus exception """ + """Base modbus exception.""" def __init__(self, string): - """ Initialize the exception + """Initialize the exception. + :param string: The message to append to the error """ self.string = string super().__init__() def __str__(self): + """Return string representation.""" return f'Modbus Error: {self.string}' - def isError(self): # pylint: disable=no-self-use,(invalid-name + def isError(self): # pylint: disable=no-self-use,(invalid-name """Error""" return True class ModbusIOException(ModbusException): - """ Error resulting from data i/o """ + """Error resulting from data i/o.""" def __init__(self, string="", function_code=None): - """ Initialize the exception + """Initialize the exception. + :param string: The message to append to the error """ self.fcode = function_code @@ -36,10 +38,10 @@ def __init__(self, string="", function_code=None): class ParameterException(ModbusException): - """ Error resulting from invalid parameter """ + """Error resulting from invalid parameter.""" def __init__(self, string=""): - """ Initialize the exception + """Initialize the exception. :param string: The message to append to the error """ @@ -48,11 +50,10 @@ def __init__(self, string=""): class NoSuchSlaveException(ModbusException): - """ Error resulting from making a request to a slave - that does not exist """ + """Error resulting from making a request to a slave that does not exist.""" def __init__(self, string=""): - """ Initialize the exception + """Initialize the exception. :param string: The message to append to the error """ @@ -61,10 +62,11 @@ def __init__(self, string=""): class NotImplementedException(ModbusException): - """ Error resulting from not implemented function """ + """Error resulting from not implemented function.""" def __init__(self, string=""): - """ Initialize the exception + """Initialize the exception. + :param string: The message to append to the error """ message = f"[Not Implemented] {string}" @@ -72,10 +74,10 @@ def __init__(self, string=""): class ConnectionException(ModbusException): - """ Error resulting from a bad connection """ + """Error resulting from a bad connection.""" def __init__(self, string=""): - """ Initialize the exception + """Initialize the exception. :param string: The message to append to the error """ @@ -84,10 +86,10 @@ def __init__(self, string=""): class InvalidMessageReceivedException(ModbusException): - """ Error resulting from invalid response received or decoded. """ + """Error resulting from invalid response received or decoded.""" def __init__(self, string=""): - """ Initialize the exception + """Initialize the exception. :param string: The message to append to the error """ @@ -96,17 +98,19 @@ def __init__(self, string=""): class MessageRegisterException(ModbusException): - """ Error resulting from failing to register a custom message request/response. """ + """Error resulting from failing to register a custom message request/response.""" + def __init__(self, string=""): + """Initialize.""" message = f'[Error registering message] {string}' ModbusException.__init__(self, message) class TimeOutException(ModbusException): - """ Error resulting from modbus response timeout """ + """Error resulting from modbus response timeout.""" def __init__(self, string=""): - """ Initialize the exception + """Initialize the exception. :param string: The message to append to the error """ diff --git a/pymodbus/factory.py b/pymodbus/factory.py index 4b140cb8e..0cd9f9106 100644 --- a/pymodbus/factory.py +++ b/pymodbus/factory.py @@ -1,5 +1,4 @@ -""" Modbus Request/Response Decoder Factories -------------------------------------------- +"""Modbus Request/Response Decoder Factories. The following factories make it easy to decode request/response messages. To add a new request/response pair to be decodeable by the library, simply @@ -117,62 +116,63 @@ # Server Decoder # --------------------------------------------------------------------------- # class ServerDecoder(IModbusDecoder): - """ Request Message Factory (Server) + """Request Message Factory (Server). To add more implemented functions, simply add them to the list """ + __function_table = [ - ReadHoldingRegistersRequest, - ReadDiscreteInputsRequest, - ReadInputRegistersRequest, - ReadCoilsRequest, - WriteMultipleCoilsRequest, - WriteMultipleRegistersRequest, - WriteSingleRegisterRequest, - WriteSingleCoilRequest, - ReadWriteMultipleRegistersRequest, - DiagnosticStatusRequest, - ReadExceptionStatusRequest, - GetCommEventCounterRequest, - GetCommEventLogRequest, - ReportSlaveIdRequest, - ReadFileRecordRequest, - WriteFileRecordRequest, - MaskWriteRegisterRequest, - ReadFifoQueueRequest, - ReadDeviceInformationRequest, + ReadHoldingRegistersRequest, + ReadDiscreteInputsRequest, + ReadInputRegistersRequest, + ReadCoilsRequest, + WriteMultipleCoilsRequest, + WriteMultipleRegistersRequest, + WriteSingleRegisterRequest, + WriteSingleCoilRequest, + ReadWriteMultipleRegistersRequest, + DiagnosticStatusRequest, + ReadExceptionStatusRequest, + GetCommEventCounterRequest, + GetCommEventLogRequest, + ReportSlaveIdRequest, + ReadFileRecordRequest, + WriteFileRecordRequest, + MaskWriteRegisterRequest, + ReadFifoQueueRequest, + ReadDeviceInformationRequest, ] __sub_function_table = [ - ReturnQueryDataRequest, - RestartCommunicationsOptionRequest, - ReturnDiagnosticRegisterRequest, - ChangeAsciiInputDelimiterRequest, - ForceListenOnlyModeRequest, - ClearCountersRequest, - ReturnBusMessageCountRequest, - ReturnBusCommunicationErrorCountRequest, - ReturnBusExceptionErrorCountRequest, - ReturnSlaveMessageCountRequest, - ReturnSlaveNoResponseCountRequest, - ReturnSlaveNAKCountRequest, - ReturnSlaveBusyCountRequest, - ReturnSlaveBusCharacterOverrunCountRequest, - ReturnIopOverrunCountRequest, - ClearOverrunCountRequest, - GetClearModbusPlusRequest, - ReadDeviceInformationRequest, + ReturnQueryDataRequest, + RestartCommunicationsOptionRequest, + ReturnDiagnosticRegisterRequest, + ChangeAsciiInputDelimiterRequest, + ForceListenOnlyModeRequest, + ClearCountersRequest, + ReturnBusMessageCountRequest, + ReturnBusCommunicationErrorCountRequest, + ReturnBusExceptionErrorCountRequest, + ReturnSlaveMessageCountRequest, + ReturnSlaveNoResponseCountRequest, + ReturnSlaveNAKCountRequest, + ReturnSlaveBusyCountRequest, + ReturnSlaveBusCharacterOverrunCountRequest, + ReturnIopOverrunCountRequest, + ClearOverrunCountRequest, + GetClearModbusPlusRequest, + ReadDeviceInformationRequest, ] def __init__(self): - """ Initializes the client lookup tables. """ + """Initialize the client lookup tables.""" functions = set(f.function_code for f in self.__function_table) - self.__lookup = dict([(f.function_code, f) for f in self.__function_table]) # pylint: disable=consider-using-dict-comprehension + self.__lookup = dict([(f.function_code, f) for f in self.__function_table]) # pylint: disable=R1717 self.__sub_lookup = dict((f, {}) for f in functions) for f in self.__sub_function_table: self.__sub_lookup[f.function_code][f.sub_function_code] = f def decode(self, message): - """ Wrapper to decode a request packet + """Decode a request packet :param message: The raw modbus request packet :return: The decoded modbus message or None if error @@ -185,7 +185,7 @@ def decode(self, message): return None def lookupPduClass(self, function_code): - """ Use `function_code` to determine the class of the PDU. + """Use `function_code` to determine the class of the PDU. :param function_code: The function code specified in a frame. :returns: The class of the PDU that has a matching `function_code`. @@ -193,9 +193,9 @@ def lookupPduClass(self, function_code): return self.__lookup.get(function_code, ExceptionResponse) def _helper(self, data): - """ This factory is used to generate the correct request object - from a valid request packet. This decodes from a list of the - currently implemented request types. + """Generate the correct request object from a valid request packet. + + This decodes from a list of the currently implemented request types. :param data: The request packet to decode :returns: The decoded request or illegal function request object @@ -206,8 +206,8 @@ def _helper(self, data): _logger.debug(txt) request = IllegalFunctionRequest(function_code) else: - fc_string = "%s: %s" % ( # pylint: disable=consider-using-f-string - str(self.__lookup[function_code]).split('.')[-1].rstrip( # pylint: disable=use-maxsplit-arg + fc_string = "%s: %s" % ( # pylint: disable=consider-using-f-string + str(self.__lookup[function_code]).split('.')[-1].rstrip( # pylint: disable=use-maxsplit-arg "'>"), function_code ) @@ -223,15 +223,16 @@ def _helper(self, data): return request def register(self, function=None): - """ Registers a function and sub function class with the decoder + """Register a function and sub function class with the decoder. + :param function: Custom function class to register :return: """ if function and not issubclass(function, ModbusRequest): raise MessageRegisterException( f"'{function.__class__.__name__}' is Not a valid Modbus Message" - ". Class needs to be derived from " - "`pymodbus.pdu.ModbusRequest` ") + ". Class needs to be derived from " + "`pymodbus.pdu.ModbusRequest` ") self.__lookup[function.function_code] = function if hasattr(function, "sub_function_code"): if function.function_code not in self.__sub_lookup: @@ -244,63 +245,64 @@ def register(self, function=None): # Client Decoder # --------------------------------------------------------------------------- # class ClientDecoder(IModbusDecoder): - """ Response Message Factory (Client) + """Response Message Factory (Client). To add more implemented functions, simply add them to the list """ + __function_table = [ - ReadHoldingRegistersResponse, - ReadDiscreteInputsResponse, - ReadInputRegistersResponse, - ReadCoilsResponse, - WriteMultipleCoilsResponse, - WriteMultipleRegistersResponse, - WriteSingleRegisterResponse, - WriteSingleCoilResponse, - ReadWriteMultipleRegistersResponse, - DiagnosticStatusResponse, - ReadExceptionStatusResponse, - GetCommEventCounterResponse, - GetCommEventLogResponse, - ReportSlaveIdResponse, - ReadFileRecordResponse, - WriteFileRecordResponse, - MaskWriteRegisterResponse, - ReadFifoQueueResponse, - ReadDeviceInformationResponse, + ReadHoldingRegistersResponse, + ReadDiscreteInputsResponse, + ReadInputRegistersResponse, + ReadCoilsResponse, + WriteMultipleCoilsResponse, + WriteMultipleRegistersResponse, + WriteSingleRegisterResponse, + WriteSingleCoilResponse, + ReadWriteMultipleRegistersResponse, + DiagnosticStatusResponse, + ReadExceptionStatusResponse, + GetCommEventCounterResponse, + GetCommEventLogResponse, + ReportSlaveIdResponse, + ReadFileRecordResponse, + WriteFileRecordResponse, + MaskWriteRegisterResponse, + ReadFifoQueueResponse, + ReadDeviceInformationResponse, ] __sub_function_table = [ - ReturnQueryDataResponse, - RestartCommunicationsOptionResponse, - ReturnDiagnosticRegisterResponse, - ChangeAsciiInputDelimiterResponse, - ForceListenOnlyModeResponse, - ClearCountersResponse, - ReturnBusMessageCountResponse, - ReturnBusCommunicationErrorCountResponse, - ReturnBusExceptionErrorCountResponse, - ReturnSlaveMessageCountResponse, - ReturnSlaveNoReponseCountResponse, - ReturnSlaveNAKCountResponse, - ReturnSlaveBusyCountResponse, - ReturnSlaveBusCharacterOverrunCountResponse, - ReturnIopOverrunCountResponse, - ClearOverrunCountResponse, - GetClearModbusPlusResponse, - ReadDeviceInformationResponse, + ReturnQueryDataResponse, + RestartCommunicationsOptionResponse, + ReturnDiagnosticRegisterResponse, + ChangeAsciiInputDelimiterResponse, + ForceListenOnlyModeResponse, + ClearCountersResponse, + ReturnBusMessageCountResponse, + ReturnBusCommunicationErrorCountResponse, + ReturnBusExceptionErrorCountResponse, + ReturnSlaveMessageCountResponse, + ReturnSlaveNoReponseCountResponse, + ReturnSlaveNAKCountResponse, + ReturnSlaveBusyCountResponse, + ReturnSlaveBusCharacterOverrunCountResponse, + ReturnIopOverrunCountResponse, + ClearOverrunCountResponse, + GetClearModbusPlusResponse, + ReadDeviceInformationResponse, ] def __init__(self): - """ Initializes the client lookup tables. """ + """Initialize the client lookup tables.""" functions = set(f.function_code for f in self.__function_table) - self.__lookup = dict([(f.function_code, f) # pylint: disable=consider-using-dict-comprehension + self.__lookup = dict([(f.function_code, f) # pylint: disable=consider-using-dict-comprehension for f in self.__function_table]) self.__sub_lookup = dict((f, {}) for f in functions) for f in self.__sub_function_table: self.__sub_lookup[f.function_code][f.sub_function_code] = f def lookupPduClass(self, function_code): - """ Use `function_code` to determine the class of the PDU. + """Use `function_code` to determine the class of the PDU. :param function_code: The function code specified in a frame. :returns: The class of the PDU that has a matching `function_code`. @@ -308,7 +310,7 @@ def lookupPduClass(self, function_code): return self.__lookup.get(function_code, ExceptionResponse) def decode(self, message): - """ Wrapper to decode a response packet + """Decode a response packet. :param message: The raw packet to decode :return: The decoded modbus message or None if error @@ -319,22 +321,22 @@ def decode(self, message): txt = f"Unable to decode response {exc}" _logger.error(txt) - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except _logger.error(exc) return None def _helper(self, data): - """ This factory is used to generate the correct response object - from a valid response packet. This decodes from a list of the - currently implemented request types. + """Generate the correct response object from a valid response packet. + + This decodes from a list of the currently implemented request types. :param data: The response packet to decode :returns: The decoded request or an exception response object """ fc_string = function_code = int(data[0]) if function_code in self.__lookup: - fc_string = "%s: %s" % ( # pylint: disable=consider-using-f-string - str(self.__lookup[function_code]).split('.')[-1].rstrip("'>"), # pylint: disable=use-maxsplit-arg + fc_string = "%s: %s" % ( # pylint: disable=consider-using-f-string + str(self.__lookup[function_code]).split('.')[-1].rstrip("'>"), # pylint: disable=use-maxsplit-arg function_code ) txt = f"Factory Response[{fc_string}]" @@ -354,8 +356,9 @@ def _helper(self, data): return response - def register(self, function=None, sub_function=None, force=False): # pylint: disable=unused-argument - """ Registers a function and sub function class with the decoder + def register(self, function=None, sub_function=None, force=False): # pylint: disable=unused-argument + """Register a function and sub function class with the decoder. + :param function: Custom function class to register :param sub_function: Custom sub function class to register :param force: Force update the existing class @@ -364,8 +367,8 @@ def register(self, function=None, sub_function=None, force=False): # pylint: dis if function and not issubclass(function, ModbusResponse): raise MessageRegisterException( f"'{function.__class__.__name__}' is Not a valid Modbus Message" - ". Class needs to be derived from " - "`pymodbus.pdu.ModbusResponse` ") + ". Class needs to be derived from " + "`pymodbus.pdu.ModbusResponse` ") self.__lookup[function.function_code] = function if hasattr(function, "sub_function_code"): if function.function_code not in self.__sub_lookup: diff --git a/pymodbus/file_message.py b/pymodbus/file_message.py index 3de1abd84..8e654d824 100644 --- a/pymodbus/file_message.py +++ b/pymodbus/file_message.py @@ -1,5 +1,4 @@ -""" File Record Read/Write Messages -------------------------------- +"""File Record Read/Write Messages. Currently none of these messages are implemented """ @@ -9,14 +8,14 @@ from pymodbus.pdu import ModbusExceptions as merror -#---------------------------------------------------------------------------# -# File Record Types -#---------------------------------------------------------------------------# -class FileRecord: # pylint: disable=eq-without-hash - """ Represents a file record and its relevant data. """ +# ---------------------------------------------------------------------------# +# File Record Types +# ---------------------------------------------------------------------------# +class FileRecord: # pylint: disable=eq-without-hash + """Represents a file record and its relevant data.""" def __init__(self, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :params reference_type: Defaults to 0x06 (must be) :params file_number: Indicates which file number we are reading @@ -25,38 +24,39 @@ def __init__(self, **kwargs): :params record_length: The length in registers of the record :params response_length: The length in bytes of the record """ - self.reference_type = kwargs.get('reference_type', 0x06) - self.file_number = kwargs.get('file_number', 0x00) - self.record_number = kwargs.get('record_number', 0x00) - self.record_data = kwargs.get('record_data', '') + self.reference_type = kwargs.get('reference_type', 0x06) + self.file_number = kwargs.get('file_number', 0x00) + self.record_number = kwargs.get('record_number', 0x00) + self.record_data = kwargs.get('record_data', '') - self.record_length = kwargs.get('record_length', len(self.record_data) // 2) + self.record_length = kwargs.get('record_length', len(self.record_data) // 2) self.response_length = kwargs.get('response_length', len(self.record_data) + 1) def __eq__(self, relf): - """ Compares the left object to the right. """ + """Compare the left object to the right.""" return self.reference_type == relf.reference_type \ - and self.file_number == relf.file_number \ - and self.record_number == relf.record_number \ - and self.record_length == relf.record_length \ - and self.record_data == relf.record_data + and self.file_number == relf.file_number \ + and self.record_number == relf.record_number \ + and self.record_length == relf.record_length \ + and self.record_data == relf.record_data def __ne__(self, relf): - """ Compares the left object to the right. """ + """Compare the left object to the right.""" return not self.__eq__(relf) def __repr__(self): - """ Gives a representation of the file record - """ + """Give a representation of the file record.""" params = (self.file_number, self.record_number, self.record_length) - return 'FileRecord(file=%d, record=%d, length=%d)' % params # pylint: disable=consider-using-f-string + return 'FileRecord(file=%d, record=%d, length=%d)' % params # pylint: disable=consider-using-f-string -#---------------------------------------------------------------------------# -# File Requests/Responses -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# File Requests/Responses +# ---------------------------------------------------------------------------# class ReadFileRecordRequest(ModbusRequest): - """ This function code is used to perform a file record read. All request + """Read file record request. + + This function code is used to perform a file record read. All request data lengths are provided in terms of number of bytes and all record lengths are provided in terms of registers. @@ -76,44 +76,45 @@ class ReadFileRecordRequest(ModbusRequest): in the expected response, must not exceed the allowable length of the MODBUS PDU: 235 bytes. """ + function_code = 0x14 _rtu_byte_count_pos = 2 def __init__(self, records=None, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param records: The file record requests to be read """ ModbusRequest.__init__(self, **kwargs) - self.records = records or [] + self.records = records or [] def encode(self): - """ Encodes the request packet + """Encode the request packet. :returns: The byte encoded packet """ packet = struct.pack('B', len(self.records) * 7) for record in self.records: packet += struct.pack('>BHHH', 0x06, record.file_number, - record.record_number, record.record_length) + record.record_number, record.record_length) return packet def decode(self, data): - """ Decodes the incoming request + """Decode the incoming request. :param data: The data to decode into the address """ self.records = [] byte_count = int(data[0]) for count in range(1, byte_count, 7): - decoded = struct.unpack('>BHHH', data[count:count+7]) - record = FileRecord(file_number=decoded[1], - record_number=decoded[2], record_length=decoded[3]) + decoded = struct.unpack('>BHHH', data[count:count + 7]) + record = FileRecord(file_number=decoded[1], + record_number=decoded[2], record_length=decoded[3]) if decoded[0] == 0x06: self.records.append(record) - def execute(self, context): #NOSONAR pylint: disable=unused-argument,no-self-use - """ Run a read exception status request against the store + def execute(self, context): # NOSONAR pylint: disable=unused-argument,no-self-use + """Run a read exception status request against the store. :param context: The datastore to request from :returns: The populated response @@ -126,16 +127,19 @@ def execute(self, context): #NOSONAR pylint: disable=unused-argument,no-self-use class ReadFileRecordResponse(ModbusResponse): - """ The normal response is a series of 'sub-responses,' one for each + """Read file record response. + + The normal response is a series of 'sub-responses,' one for each 'sub-request.' The byte count field is the total combined count of bytes in all 'sub-responses.' In addition, each 'sub-response' contains a field that shows its own byte count. """ + function_code = 0x14 _rtu_byte_count_pos = 2 def __init__(self, records=None, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param records: The requested file records """ @@ -143,11 +147,11 @@ def __init__(self, records=None, **kwargs): self.records = records or [] def encode(self): - """ Encodes the response + """Encode the response. :returns: The byte encoded message """ - total = sum(record.response_length + 1 for record in self.records) + total = sum(record.response_length + 1 for record in self.records) packet = struct.pack('B', total) for record in self.records: packet += struct.pack('>BB', 0x06, record.record_length) @@ -155,40 +159,43 @@ def encode(self): return packet def decode(self, data): - """ Decodes a the response + """Decode the response. :param data: The packet data to decode """ count, self.records = 1, [] byte_count = int(data[0]) while count < byte_count: - response_length, reference_type = struct.unpack('>BB', data[count:count+2]) - count += response_length + 1 # the count is not included + response_length, reference_type = struct.unpack('>BB', data[count:count + 2]) + count += response_length + 1 # the count is not included record = FileRecord(response_length=response_length, - record_data=data[count - response_length + 1:count]) + record_data=data[count - response_length + 1:count]) if reference_type == 0x06: self.records.append(record) class WriteFileRecordRequest(ModbusRequest): - """ This function code is used to perform a file record write. All + """Write file record request. + + This function code is used to perform a file record write. All request data lengths are provided in terms of number of bytes and all record lengths are provided in terms of the number of 16 bit words. """ + function_code = 0x15 _rtu_byte_count_pos = 2 def __init__(self, records=None, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param records: The file record requests to be read """ ModbusRequest.__init__(self, **kwargs) - self.records = records or [] + self.records = records or [] def encode(self): - """ Encodes the request packet + """Encode the request packet. :returns: The byte encoded packet """ @@ -197,29 +204,29 @@ def encode(self): for record in self.records: packet += struct.pack('>BHHH', 0x06, record.file_number, - record.record_number, record.record_length) + record.record_number, record.record_length) packet += record.record_data return packet def decode(self, data): - """ Decodes the incoming request + """Decode the incoming request. :param data: The data to decode into the address """ byte_count = int(data[0]) count, self.records = 1, [] while count < byte_count: - decoded = struct.unpack('>BHHH', data[count:count+7]) + decoded = struct.unpack('>BHHH', data[count:count + 7]) response_length = decoded[3] * 2 - count += response_length + 7 - record = FileRecord(record_length=decoded[3], - file_number=decoded[1], record_number=decoded[2], - record_data=data[count - response_length:count]) + count += response_length + 7 + record = FileRecord(record_length=decoded[3], + file_number=decoded[1], record_number=decoded[2], + record_data=data[count - response_length:count]) if decoded[0] == 0x06: self.records.append(record) - def execute(self, context): #NOSONAR pylint: disable=unused-argument - """ Run the write file record request against the context + def execute(self, context): # NOSONAR pylint: disable=unused-argument + """Run the write file record request against the context. :param context: The datastore to request from :returns: The populated response @@ -231,20 +238,21 @@ def execute(self, context): #NOSONAR pylint: disable=unused-argument class WriteFileRecordResponse(ModbusResponse): - """ The normal response is an echo of the request. """ + """The normal response is an echo of the request.""" + function_code = 0x15 _rtu_byte_count_pos = 2 def __init__(self, records=None, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param records: The file record requests to be read """ ModbusResponse.__init__(self, **kwargs) - self.records = records or [] + self.records = records or [] def encode(self): - """ Encodes the response + """Encode the response. :returns: The byte encoded message """ @@ -252,30 +260,32 @@ def encode(self): packet = struct.pack('B', total_length) for record in self.records: packet += struct.pack('>BHHH', 0x06, record.file_number, - record.record_number, record.record_length) + record.record_number, record.record_length) packet += record.record_data return packet def decode(self, data): - """ Decodes the incoming request + """Decode the incoming request. :param data: The data to decode into the address """ count, self.records = 1, [] byte_count = int(data[0]) while count < byte_count: - decoded = struct.unpack('>BHHH', data[count:count+7]) + decoded = struct.unpack('>BHHH', data[count:count + 7]) response_length = decoded[3] * 2 - count += response_length + 7 - record = FileRecord(record_length=decoded[3], - file_number=decoded[1], record_number=decoded[2], - record_data=data[count - response_length:count]) + count += response_length + 7 + record = FileRecord(record_length=decoded[3], + file_number=decoded[1], record_number=decoded[2], + record_data=data[count - response_length:count]) if decoded[0] == 0x06: self.records.append(record) class ReadFifoQueueRequest(ModbusRequest): - """ This function code allows to read the contents of a First-In-First-Out + """Read fifo queue request. + + This function code allows to read the contents of a First-In-First-Out (FIFO) queue of register in a remote device. The function returns a count of the registers in the queue, followed by the queued data. Up to 32 registers can be read: the count, plus up to 31 queued data @@ -285,11 +295,12 @@ class ReadFifoQueueRequest(ModbusRequest): registers. The function reads the queue contents, but does not clear them. """ + function_code = 0x18 _rtu_frame_size = 6 def __init__(self, address=0x0000, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param address: The fifo pointer address (0x0000 to 0xffff) """ @@ -298,21 +309,21 @@ def __init__(self, address=0x0000, **kwargs): self.values = [] # this should be added to the context def encode(self): - """ Encodes the request packet + """Encode the request packet. :returns: The byte encoded packet """ return struct.pack('>H', self.address) def decode(self, data): - """ Decodes the incoming request + """Decode the incoming request. :param data: The data to decode into the address """ self.address = struct.unpack('>H', data)[0] - def execute(self, context): #NOSONAR pylint: disable=unused-argument - """ Run a read exception status request against the store + def execute(self, context): # NOSONAR pylint: disable=unused-argument + """Run a read exception status request against the store. :param context: The datastore to request from :returns: The populated response @@ -326,7 +337,9 @@ def execute(self, context): #NOSONAR pylint: disable=unused-argument class ReadFifoQueueResponse(ModbusResponse): - """ In a normal response, the byte count shows the quantity of bytes to + """Read Fifo queue response. + + In a normal response, the byte count shows the quantity of bytes to follow, including the queue count bytes and value register bytes (but not including the error check field). The queue count is the quantity of data registers in the queue (not including the count register). @@ -334,11 +347,12 @@ class ReadFifoQueueResponse(ModbusResponse): If the queue count exceeds 31, an exception response is returned with an error code of 03 (Illegal Data Value). """ + function_code = 0x18 @classmethod def calculateRtuFrameSize(cls, buffer): - """ Calculates the size of the message + """Calculate the size of the message. :param buffer: A buffer containing the data that have been received. :returns: The number of bytes in the response. @@ -348,7 +362,7 @@ def calculateRtuFrameSize(cls, buffer): return (hi_byte << 16) + lo_byte + 6 def __init__(self, values=None, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param values: The list of values of the fifo to return """ @@ -356,7 +370,7 @@ def __init__(self, values=None, **kwargs): self.values = values or [] def encode(self): - """ Encodes the response + """Encode the response. :returns: The byte encoded message """ @@ -367,7 +381,7 @@ def encode(self): return packet def decode(self, data): - """ Decodes a the response + """Decode a the response. :param data: The packet data to decode """ @@ -377,9 +391,10 @@ def decode(self, data): idx = 4 + index * 2 self.values.append(struct.unpack('>H', data[idx:idx + 2])[0]) -#---------------------------------------------------------------------------# -# Exported symbols -#---------------------------------------------------------------------------# + +# ---------------------------------------------------------------------------# +# Exported symbols +# ---------------------------------------------------------------------------# __all__ = [ "FileRecord", "ReadFileRecordRequest", "ReadFileRecordResponse", diff --git a/pymodbus/framer/__init__.py b/pymodbus/framer/__init__.py index 35cdf45e5..6182ec609 100644 --- a/pymodbus/framer/__init__.py +++ b/pymodbus/framer/__init__.py @@ -1,5 +1,4 @@ -""" Framer start. """ -import struct +"""Framer start.""" from pymodbus.interfaces import IModbusFramer # Unit ID, Function Code @@ -12,33 +11,39 @@ # Function Code TLS_FRAME_HEADER = BYTE_ORDER + 'B' + class ModbusFramer(IModbusFramer): - """ Base Framer class. """ + """Base Framer class.""" def _validate_unit_id(self, units, single): - """ Validates if the received data is valid for the client + """Validate if the received data is valid for the client. + :param units: list of unit id for which the transaction is valid :param single: Set to true to treat this as a single context - :return: """ - + :return: + """ if single: return True if 0 in units or 0xFF in units: # Handle Modbus TCP unit identifier (0x00 0r 0xFF) # in asynchronous requests return True - return self._header['uid'] in units # pylint: disable=no-member + return self._header['uid'] in units # pylint: disable=no-member + + def sendPacket(self, message): # pylint: disable=invalid-name + """Send packets on the bus. - def sendPacket(self, message): # pylint: disable=invalid-name - """ Sends packets on the bus with 3.5char delay between frames + With 3.5char delay between frames :param message: Message to be sent over the bus :return: """ - return self.client.send(message) # pylint: disable=no-member + return self.client.send(message) # pylint: disable=no-member + + def recvPacket(self, size): # pylint: disable=invalid-name + """Receive packet from the bus. - def recvPacket(self, size): # pylint: disable=invalid-name - """ Receives packet from the bus with specified len + With specified len :param size: Number of bytes to read :return: """ - return self.client.recv(size) # pylint: disable=no-member + return self.client.recv(size) # pylint: disable=no-member diff --git a/pymodbus/framer/ascii_framer.py b/pymodbus/framer/ascii_framer.py index 290ed9253..abf9db0f7 100644 --- a/pymodbus/framer/ascii_framer.py +++ b/pymodbus/framer/ascii_framer.py @@ -20,7 +20,7 @@ # Modbus ASCII Message # --------------------------------------------------------------------------- # class ModbusAsciiFramer(ModbusFramer): - """ Modbus ASCII Frame Controller:: + r"""Modbus ASCII Frame Controller. [ Start ][Address ][ Function ][ Data ][ LRC ][ End ] 1c 2c 2c Nc 2c 2c @@ -35,7 +35,7 @@ class ModbusAsciiFramer(ModbusFramer): """ def __init__(self, decoder, client=None): - """ Initializes a new instance of the framer + """Initialize a new instance of the framer. :param decoder: The decoder implementation to use """ @@ -50,7 +50,7 @@ def __init__(self, decoder, client=None): # ----------------------------------------------------------------------- # # Private Helper Functions # ----------------------------------------------------------------------- # - def decode_data(self, data): # pylint: disable=no-self-use + def decode_data(self, data): # pylint: disable=no-self-use """Decode data.""" if len(data) > 1: uid = int(data[1:3], 16) @@ -59,7 +59,7 @@ def decode_data(self, data): # pylint: disable=no-self-use return {} def checkFrame(self): - """ Check and decode the next frame + """Check and decode the next frame. :returns: True if we successful, False otherwise """ @@ -79,7 +79,8 @@ def checkFrame(self): return False def advanceFrame(self): - """ Skip over the current framed message + """Skip over the current framed message. + This allows us to skip over the current message after we have processed it or determined that it contains an error. It also has to reset the current frame header handle @@ -88,7 +89,8 @@ def advanceFrame(self): self._header = {'lrc': '0000', 'len': 0, 'uid': 0x00} def isFrameReady(self): - """ Check if we should continue decode logic + """Check if we should continue decode logic. + This is meant to be used in a while loop in the decoding phase to let the decoder know that there is still data in the buffer. @@ -97,7 +99,8 @@ def isFrameReady(self): return len(self._buffer) > 1 def addToFrame(self, message): - """ Add the next message to the frame buffer + """Add the next message to the frame buffer. + This should be used before the decoding while loop to add the received data to the buffer handle. @@ -106,7 +109,7 @@ def addToFrame(self, message): self._buffer += message def getFrame(self): - """ Get the next frame from the buffer + """Get the next frame from the buffer. :returns: The frame data or '' """ @@ -117,8 +120,9 @@ def getFrame(self): return a2b_hex(buffer) return b'' - def resetFrame(self): # pylint: disable=invalid-name - """ Reset the entire message frame. + def resetFrame(self): # pylint: disable=invalid-name + """Reset the entire message frame. + This allows us to skip ovver errors that may be in the stream. It is hard to know if we are simply out of sync or if there is an error in the stream as we have no way to check the start or @@ -129,7 +133,7 @@ def resetFrame(self): # pylint: disable=invalid-name self._header = {'lrc': '0000', 'len': 0, 'uid': 0x00} def populateResult(self, result): - """ Populates the modbus result header + """Populate the modbus result header. The serial packets do not have any header information that is copied. @@ -141,8 +145,8 @@ def populateResult(self, result): # ----------------------------------------------------------------------- # # Public Member Functions # ----------------------------------------------------------------------- # - def processIncomingPacket(self, data, callback, unit, **kwargs): # pylint: disable=arguments-differ - """ The new packet processing pattern + def processIncomingPacket(self, data, callback, unit, **kwargs): # pylint: disable=arguments-differ + """Process new packet pattern. This takes in a new request packet, adds it to the current packet stream, and performs framing on it. That is, checks @@ -181,7 +185,8 @@ def processIncomingPacket(self, data, callback, unit, **kwargs): # pylint: disab break def buildPacket(self, message): - """ Creates a ready to send modbus packet + """Create a ready to send modbus packet. + Built off of a modbus request/response :param message: The request/response to send @@ -195,9 +200,9 @@ def buildPacket(self, message): packet = bytearray() params = (message.unit_id, message.function_code) packet.extend(self._start) - packet.extend(('%02x%02x' % params).encode()) # pylint: disable=consider-using-f-string + packet.extend(('%02x%02x' % params).encode()) # pylint: disable=consider-using-f-string packet.extend(b2a_hex(encoded)) - packet.extend(('%02x' % checksum).encode())# pylint: disable=consider-using-f-string + packet.extend(('%02x' % checksum).encode()) # pylint: disable=consider-using-f-string packet.extend(self._end) return bytes(packet).upper() diff --git a/pymodbus/framer/binary_framer.py b/pymodbus/framer/binary_framer.py index d77c67d72..53a87c16d 100644 --- a/pymodbus/framer/binary_framer.py +++ b/pymodbus/framer/binary_framer.py @@ -1,4 +1,4 @@ -""" Binary framer. """ +"""Binary framer.""" import logging import struct from pymodbus.exceptions import ModbusIOException @@ -18,7 +18,7 @@ class ModbusBinaryFramer(ModbusFramer): - """ Modbus Binary Frame Controller:: + """Modbus Binary Frame Controller. [ Start ][Address ][ Function ][ Data ][ CRC ][ End ] 1b 1b 1b Nb 2b 1b @@ -42,7 +42,7 @@ class ModbusBinaryFramer(ModbusFramer): """ def __init__(self, decoder, client=None): - """ Initializes a new instance of the framer + """Initialize a new instance of the framer. :param decoder: The decoder implementation to use """ @@ -51,7 +51,7 @@ def __init__(self, decoder, client=None): self._hsize = 0x01 self._start = b'\x7b' # { self._end = b'\x7d' # } - self._repeat = [b'}'[0], b'{'[0]] # python3 hack + self._repeat = [b'}'[0], b'{'[0]] # python3 hack self.decoder = decoder self.client = client @@ -59,7 +59,7 @@ def __init__(self, decoder, client=None): # Private Helper Functions # ----------------------------------------------------------------------- # def decode_data(self, data): - """ Decode data. """ + """Decode data.""" if len(data) > self._hsize: uid = struct.unpack('>B', data[1:2])[0] fcode = struct.unpack('>B', data[2:3])[0] @@ -67,7 +67,7 @@ def decode_data(self, data): return {} def checkFrame(self): - """ Check and decode the next frame + """Check and decode the next frame. :returns: True if we are successful, False otherwise """ @@ -86,16 +86,18 @@ def checkFrame(self): return False def advanceFrame(self): - """ Skip over the current framed message + """Skip over the current framed message. + This allows us to skip over the current message after we have processed it or determined that it contains an error. It also has to reset the current frame header handle """ self._buffer = self._buffer[self._header['len'] + 2:] - self._header = {'crc':0x0000, 'len':0, 'uid':0x00} + self._header = {'crc': 0x0000, 'len': 0, 'uid': 0x00} def isFrameReady(self): - """ Check if we should continue decode logic + """Check if we should continue decode logic. + This is meant to be used in a while loop in the decoding phase to let the decoder know that there is still data in the buffer. @@ -104,7 +106,8 @@ def isFrameReady(self): return len(self._buffer) > 1 def addToFrame(self, message): - """ Add the next message to the frame buffer + """Add the next message to the frame buffer. + This should be used before the decoding while loop to add the received data to the buffer handle. @@ -113,7 +116,7 @@ def addToFrame(self, message): self._buffer += message def getFrame(self): - """ Get the next frame from the buffer + """Get the next frame from the buffer. :returns: The frame data or '' """ @@ -125,7 +128,7 @@ def getFrame(self): return b'' def populateResult(self, result): - """ Populates the modbus result header + """Populate the modbus result header. The serial packets do not have any header information that is copied. @@ -137,8 +140,8 @@ def populateResult(self, result): # ----------------------------------------------------------------------- # # Public Member Functions # ----------------------------------------------------------------------- # - def processIncomingPacket(self, data, callback, unit, **kwargs): # pylint: disable=arguments-differ - """ The new packet processing pattern + def processIncomingPacket(self, data, callback, unit, **kwargs): # pylint: disable=arguments-differ + """Process new packet pattern. This takes in a new request packet, adds it to the current packet stream, and performs framing on it. That is, checks @@ -180,7 +183,7 @@ def processIncomingPacket(self, data, callback, unit, **kwargs): # pylint: disab break def buildPacket(self, message): - """ Creates a ready to send modbus packet + """Create a ready to send modbus packet. :param message: The request/response to send :returns: The encoded packet @@ -194,7 +197,7 @@ def buildPacket(self, message): return packet def _preflight(self, data): - """ Preflight buffer test + """Do preflight buffer test. This basically scans the buffer for start and end tags and if found, escapes them. @@ -209,8 +212,9 @@ def _preflight(self, data): array.append(item) return bytes(array) - def resetFrame(self): # pylint: disable=invalid-name - """ Reset the entire message frame. + def resetFrame(self): # pylint: disable=invalid-name + """Reset the entire message frame. + This allows us to skip ovver errors that may be in the stream. It is hard to know if we are simply out of sync or if there is an error in the stream as we have no way to check the start or diff --git a/pymodbus/framer/rtu_framer.py b/pymodbus/framer/rtu_framer.py index 0ad693b05..3ee38b49a 100644 --- a/pymodbus/framer/rtu_framer.py +++ b/pymodbus/framer/rtu_framer.py @@ -1,4 +1,4 @@ -""" RTU framer. """ +"""RTU framer.""" import logging import struct import time @@ -21,7 +21,7 @@ # Modbus RTU Message # --------------------------------------------------------------------------- # class ModbusRtuFramer(ModbusFramer): - """ Modbus RTU Frame controller:: + """Modbus RTU Frame controller. [ Start Wait ] [Address ][ Function Code] [ Data ][ CRC ][ End Wait ] 3.5 chars 1b 1b Nb 2b 3.5 chars @@ -54,7 +54,7 @@ class ModbusRtuFramer(ModbusFramer): """ def __init__(self, decoder, client=None): - """ Initializes a new instance of the framer + """Initialize a new instance of the framer. :param decoder: The decoder factory implementation to use """ @@ -70,7 +70,7 @@ def __init__(self, decoder, client=None): # Private Helper Functions # ----------------------------------------------------------------------- # def decode_data(self, data): - """ Decode data. """ + """Decode data.""" if len(data) > self._hsize: uid = int(data[0]) fcode = int(data[1]) @@ -78,7 +78,8 @@ def decode_data(self, data): return {} def checkFrame(self): - """ Check if the next frame is available. + """Check if the next frame is available. + Return True if we were successful. 1. Populate header @@ -95,18 +96,19 @@ def checkFrame(self): return False def advanceFrame(self): - """ Skip over the current framed message + """Skip over the current framed message. + This allows us to skip over the current message after we have processed it or determined that it contains an error. It also has to reset the current frame header handle """ - self._buffer = self._buffer[self._header['len']:] _logger.debug("Frame advanced, resetting header!!") self._header = {'uid': 0x00, 'len': 0, 'crc': b'\x00\x00'} - def resetFrame(self): # pylint: disable=invalid-name - """ Reset the entire message frame. + def resetFrame(self): # pylint: disable=invalid-name + """Reset the entire message frame. + This allows us to skip over errors that may be in the stream. It is hard to know if we are simply out of sync or if there is an error in the stream as we have no way to check the start or @@ -120,7 +122,8 @@ def resetFrame(self): # pylint: disable=invalid-name self._header = {'uid': 0x00, 'len': 0, 'crc': b'\x00\x00'} def isFrameReady(self): - """ Check if we should continue decode logic + """Check if we should continue decode logic. + This is meant to be used in a while loop in the decoding phase to let the decoder know that there is still data in the buffer. @@ -139,8 +142,8 @@ def isFrameReady(self): return True - def populateHeader(self, data=None): # pylint: disable=invalid-name - """ Try to set the headers `uid`, `len` and `crc`. + def populateHeader(self, data=None): # pylint: disable=invalid-name + """Try to set the headers `uid`, `len` and `crc`. This method examines `self._buffer` and writes meta information into `self._header`. @@ -161,15 +164,14 @@ def populateHeader(self, data=None): # pylint: disable=invalid-name self._header['crc'] = data[size - 2:size] def addToFrame(self, message): - """ This should be used before the decoding while loop to add the received - data to the buffer handle. + """Add the received data to the buffer handle. :param message: The most recent packet """ self._buffer += message def getFrame(self): - """ Get the next frame from the buffer + """Get the next frame from the buffer. :returns: The frame data or '' """ @@ -183,7 +185,7 @@ def getFrame(self): return b'' def populateResult(self, result): - """ Populates the modbus result header + """Populate the modbus result header. The serial packets do not have any header information that is copied. @@ -196,8 +198,8 @@ def populateResult(self, result): # ----------------------------------------------------------------------- # # Public Member Functions # ----------------------------------------------------------------------- # - def processIncomingPacket(self, data, callback, unit, **kwargs): # pylint: disable=arguments-differ - """ The new packet processing pattern + def processIncomingPacket(self, data, callback, unit, **kwargs): # pylint: disable=arguments-differ + """Process new packet pattern. This takes in a new request packet, adds it to the current packet stream, and performs framing on it. That is, checks @@ -235,7 +237,7 @@ def processIncomingPacket(self, data, callback, unit, **kwargs): # pylint: disab _logger.debug(txt) def buildPacket(self, message): - """ Creates a ready to send modbus packet + """Create a ready to send modbus packet. :param message: The populated request/response to send """ @@ -249,7 +251,8 @@ def buildPacket(self, message): return packet def sendPacket(self, message): - """ Sends packets on the bus with 3.5char delay between frames + """Send packets on the bus with 3.5char delay between frames. + :param message: Message to be sent over the bus :return: """ @@ -290,7 +293,8 @@ def sendPacket(self, message): return size def recvPacket(self, size): - """ Receives packet from the bus with specified len + """Receive packet from the bus with specified len. + :param size: Number of bytes to read :return: """ @@ -299,7 +303,7 @@ def recvPacket(self, size): return result def _process(self, callback, error=False): - """ Process incoming packets irrespective error condition. """ + """Process incoming packets irrespective error condition.""" data = self.getRawFrame() if error else self.getFrame() if (result := self.decoder.decode(data)) is None: raise ModbusIOException("Unable to decode request") @@ -309,8 +313,8 @@ def _process(self, callback, error=False): self.advanceFrame() callback(result) # defer or push to a thread? - def getRawFrame(self): # pylint: disable=invalid-name - """ Returns the complete buffer. """ + def getRawFrame(self): # pylint: disable=invalid-name + """Return the complete buffer.""" txt = f"Getting Raw Frame - {hexlify_packets(self._buffer)}" _logger.debug(txt) return self._buffer diff --git a/pymodbus/framer/socket_framer.py b/pymodbus/framer/socket_framer.py index 3a1704344..c3ab8b0ff 100644 --- a/pymodbus/framer/socket_framer.py +++ b/pymodbus/framer/socket_framer.py @@ -1,4 +1,4 @@ -""" Socket framer. """ +"""Socket framer.""" import logging import struct from pymodbus.exceptions import ModbusIOException @@ -17,7 +17,7 @@ class ModbusSocketFramer(ModbusFramer): - """ Modbus Socket Frame controller + """Modbus Socket Frame controller. Before each modbus TCP message is an MBAP header which is used as a message frame. It allows us to easily separate messages as follows:: @@ -36,7 +36,7 @@ class ModbusSocketFramer(ModbusFramer): """ def __init__(self, decoder, client=None): - """ Initializes a new instance of the framer + """Initialize a new instance of the framer. :param decoder: The decoder factory implementation to use """ @@ -50,7 +50,10 @@ def __init__(self, decoder, client=None): # Private Helper Functions # ----------------------------------------------------------------------- # def checkFrame(self): - """ Check and decode the next frame Return true if we were successful. """ + """Check and decode the next frame. + + Return true if we were successful. + """ if self.isFrameReady(): (self._header['tid'], self._header['pid'], self._header['len'], self._header['uid']) = struct.unpack( @@ -66,7 +69,8 @@ def checkFrame(self): return False def advanceFrame(self): - """ Skip over the current framed message + """Skip over the current framed message. + This allows us to skip over the current message after we have processed it or determined that it contains an error. It also has to reset the current frame header handle @@ -76,7 +80,8 @@ def advanceFrame(self): self._header = {'tid': 0, 'pid': 0, 'len': 0, 'uid': 0} def isFrameReady(self): - """ Check if we should continue decode logic + """Check if we should continue decode logic. + This is meant to be used in a while loop in the decoding phase to let the decoder factory know that there is still data in the buffer. @@ -85,14 +90,14 @@ def isFrameReady(self): return len(self._buffer) > self._hsize def addToFrame(self, message): - """ Adds new packet data to the current frame buffer + """Add new packet data to the current frame buffer. :param message: The most recent packet """ self._buffer += message def getFrame(self): - """ Return the next frame from the buffered data + """Return the next frame from the buffered data. :returns: The next full frame buffer """ @@ -100,7 +105,9 @@ def getFrame(self): return self._buffer[self._hsize:length] def populateResult(self, result): - """ Populates the modbus result with the transport specific header + """Populate the modbus result. + + With the transport specific header information (pid, tid, uid, checksum, etc) :param result: The response packet @@ -113,15 +120,15 @@ def populateResult(self, result): # Public Member Functions # ----------------------------------------------------------------------- # def decode_data(self, data): - """ Decode data. """ + """Decode data.""" if len(data) > self._hsize: tid, pid, length, uid, fcode = struct.unpack(SOCKET_FRAME_HEADER, - data[0:self._hsize+1]) + data[0:self._hsize + 1]) return dict(tid=tid, pid=pid, length=length, unit=uid, fcode=fcode) return {} - def processIncomingPacket(self, data, callback, unit, **kwargs): #NOSONAR pylint: disable=arguments-differ - """ The new packet processing pattern + def processIncomingPacket(self, data, callback, unit, **kwargs): # NOSONAR pylint: disable=arguments-differ + """Process new packet pattern. This takes in a new request packet, adds it to the current packet stream, and performs framing on it. That is, checks @@ -165,7 +172,7 @@ def processIncomingPacket(self, data, callback, unit, **kwargs): #NOSONAR pylint break def _process(self, callback, error=False): - """ Process incoming packets irrespective error condition. """ + """Process incoming packets irrespective error condition.""" data = self.getRawFrame() if error else self.getFrame() if (result := self.decoder.decode(data)) is None: raise ModbusIOException("Unable to decode request") @@ -173,10 +180,11 @@ def _process(self, callback, error=False): raise InvalidMessageReceivedException(result) self.populateResult(result) self.advanceFrame() - callback(result) # defer or push to a thread? + callback(result) # defer or push to a thread? + + def resetFrame(self): # pylint: disable=invalid-name + """Reset the entire message frame. - def resetFrame(self): # pylint: disable=invalid-name - """ Reset the entire message frame. This allows us to skip ovver errors that may be in the stream. It is hard to know if we are simply out of sync or if there is an error in the stream as we have no way to check the start or @@ -186,12 +194,12 @@ def resetFrame(self): # pylint: disable=invalid-name self._buffer = b'' self._header = {'tid': 0, 'pid': 0, 'len': 0, 'uid': 0} - def getRawFrame(self): # pylint: disable=invalid-name - """ Returns the complete buffer. """ + def getRawFrame(self): # pylint: disable=invalid-name + """Return the complete buffer.""" return self._buffer def buildPacket(self, message): - """ Creates a ready to send modbus packet + """Create a ready to send modbus packet. :param message: The populated request/response to send """ diff --git a/pymodbus/framer/tls_framer.py b/pymodbus/framer/tls_framer.py index e9f81163a..7f861fa97 100644 --- a/pymodbus/framer/tls_framer.py +++ b/pymodbus/framer/tls_framer.py @@ -1,4 +1,4 @@ -""" TLS framer. """ +"""TLS framer.""" import logging import struct from pymodbus.exceptions import ModbusIOException @@ -17,7 +17,7 @@ class ModbusTlsFramer(ModbusFramer): - """ Modbus TLS Frame controller + """Modbus TLS Frame controller No prefix MBAP header before decrypted PDU is used as a message frame for Modbus Security Application Protocol. It allows us to easily separate @@ -28,7 +28,7 @@ class ModbusTlsFramer(ModbusFramer): """ def __init__(self, decoder, client=None): - """ Initializes a new instance of the framer + """Initialize a new instance of the framer. :param decoder: The decoder factory implementation to use """ @@ -42,7 +42,10 @@ def __init__(self, decoder, client=None): # Private Helper Functions # ----------------------------------------------------------------------- # def checkFrame(self): - """ Check and decode the next frame Return true if we were successful. """ + """Check and decode the next frame. + + Return true if we were successful. + """ if self.isFrameReady(): # we have at least a complete message, continue if len(self._buffer) - self._hsize >= 1: @@ -51,7 +54,8 @@ def checkFrame(self): return False def advanceFrame(self): - """ Skip over the current framed message + """Skip over the current framed message. + This allows us to skip over the current message after we have processed it or determined that it contains an error. It also has to reset the current frame header handle @@ -60,7 +64,8 @@ def advanceFrame(self): self._header = {} def isFrameReady(self): - """ Check if we should continue decode logic + """Check if we should continue decode logic. + This is meant to be used in a while loop in the decoding phase to let the decoder factory know that there is still data in the buffer. @@ -69,21 +74,23 @@ def isFrameReady(self): return len(self._buffer) > self._hsize def addToFrame(self, message): - """ Adds new packet data to the current frame buffer + """Add new packet data to the current frame buffer. :param message: The most recent packet """ self._buffer += message def getFrame(self): - """ Return the next frame from the buffered data + """Return the next frame from the buffered data. :returns: The next full frame buffer """ return self._buffer[self._hsize:] def populateResult(self, result): - """ Populates the modbus result with the transport specific header + """Populate the modbus result. + + With the transport specific header information (no header before PDU in decrypted message) :param result: The response packet @@ -94,14 +101,14 @@ def populateResult(self, result): # Public Member Functions # ----------------------------------------------------------------------- # def decode_data(self, data): - """ Decode data. """ + """Decode data.""" if len(data) > self._hsize: - (fcode,) = struct.unpack(TLS_FRAME_HEADER, data[0:self._hsize+1]) + (fcode,) = struct.unpack(TLS_FRAME_HEADER, data[0:self._hsize + 1]) return dict(fcode=fcode) return {} - def processIncomingPacket(self, data, callback, unit, **kwargs): # pylint: disable=arguments-differ - """ The new packet processing pattern + def processIncomingPacket(self, data, callback, unit, **kwargs): # pylint: disable=arguments-differ + """Process new packet pattern. This takes in a new request packet, adds it to the current packet stream, and performs framing on it. That is, checks @@ -140,7 +147,7 @@ def processIncomingPacket(self, data, callback, unit, **kwargs): # pylint: disab self.resetFrame() def _process(self, callback, error=False): - """ Process incoming packets irrespective error condition. """ + """Process incoming packets irrespective error condition.""" data = self.getRawFrame() if error else self.getFrame() if (result := self.decoder.decode(data)) is None: raise ModbusIOException("Unable to decode request") @@ -150,8 +157,9 @@ def _process(self, callback, error=False): self.advanceFrame() callback(result) # defer or push to a thread? - def resetFrame(self): # pylint: disable=invalid-name - """ Reset the entire message frame. + def resetFrame(self): # pylint: disable=invalid-name + """Reset the entire message frame. + This allows us to skip ovver errors that may be in the stream. It is hard to know if we are simply out of sync or if there is an error in the stream as we have no way to check the start or @@ -160,12 +168,12 @@ def resetFrame(self): # pylint: disable=invalid-name """ self._buffer = b'' - def getRawFrame(self): # pylint: disable=invalid-name - """ Returns the complete buffer. """ + def getRawFrame(self): # pylint: disable=invalid-name + """Return the complete buffer.""" return self._buffer def buildPacket(self, message): - """ Creates a ready to send modbus packet + """Create a ready to send modbus packet. :param message: The populated request/response to send """ diff --git a/pymodbus/interfaces.py b/pymodbus/interfaces.py index f6a97427a..fe92a85c0 100644 --- a/pymodbus/interfaces.py +++ b/pymodbus/interfaces.py @@ -1,5 +1,4 @@ -""" Pymodbus Interfaces ---------------------- +"""Pymodbus Interfaces. A collection of base classes that are used throughout the pymodbus library. @@ -10,12 +9,14 @@ # --------------------------------------------------------------------------- # # Generic # --------------------------------------------------------------------------- # -class Singleton: # pylint: disable=too-few-public-methods - """ Singleton base class +class Singleton: # pylint: disable=too-few-public-methods + """Singleton base class. + http://mail.python.org/pipermail/python-list/2007-July/450681.html """ - def __new__(cls, *args, **kwargs): # pylint: disable=unused-argument - """ Create a new instance""" + + def __new__(cls, *args, **kwargs): # pylint: disable=unused-argument + """Create a new instance.""" if '_inst' not in vars(cls): cls._inst = object.__new__(cls) return cls._inst @@ -25,7 +26,7 @@ def __new__(cls, *args, **kwargs): # pylint: disable=unused-argument # Project Specific # --------------------------------------------------------------------------- # class IModbusDecoder: - """ Modbus Decoder Base Class + """Modbus Decoder Base Class. This interface must be implemented by a modbus message decoder factory. These factories are responsible for @@ -33,8 +34,8 @@ class IModbusDecoder: message object. """ - def decode(self, message): # pylint: disable=no-self-use - """ Wrapper to decode a given packet + def decode(self, message): # pylint: disable=no-self-use + """Decode a given packet. :param message: The raw modbus request packet :return: The decoded modbus message or None if error @@ -42,8 +43,8 @@ def decode(self, message): # pylint: disable=no-self-use raise NotImplementedException( "Method not implemented by derived class") - def lookupPduClass(self, function_code): #NOSONAR pylint: disable=no-self-use,invalid-name - """ Use `function_code` to determine the class of the PDU. + def lookupPduClass(self, function_code): # NOSONAR pylint: disable=no-self-use,invalid-name + """Use `function_code` to determine the class of the PDU. :param function_code: The function code specified in a frame. :returns: The class of the PDU that has a matching `function_code`. @@ -51,8 +52,9 @@ def lookupPduClass(self, function_code): #NOSONAR pylint: disable=no-self-use,in raise NotImplementedException( "Method not implemented by derived class") - def register(self, function=None): # pylint: disable=no-self-use - """ Registers a function and sub function class with the decoder + def register(self, function=None): # pylint: disable=no-self-use + """Register a function and sub function class with the decoder. + :param function: Custom function class to register :return: """ @@ -61,22 +63,25 @@ def register(self, function=None): # pylint: disable=no-self-use class IModbusFramer: - """ A framer strategy interface. The idea is that we abstract away all the + """A framer strategy interface. + + The idea is that we abstract away all the detail about how to detect if a current message frame exists, decoding it, sending it, etc so that we can plug in a new Framer object (tcp, rtu, ascii). """ - def checkFrame(self): #NOSONAR pylint: disable=no-self-use,invalid-name - """ Check and decode the next frame + def checkFrame(self): # NOSONAR pylint: disable=no-self-use,invalid-name + """Check and decode the next frame. :returns: True if we successful, False otherwise """ raise NotImplementedException( "Method not implemented by derived class") - def advanceFrame(self): #NOSONAR pylint: disable=no-self-use,invalid-name - """ Skip over the current framed message + def advanceFrame(self): # NOSONAR pylint: disable=no-self-use,invalid-name + """Skip over the current framed message. + This allows us to skip over the current message after we have processed it or determined that it contains an error. It also has to reset the current frame header handle @@ -84,8 +89,8 @@ def advanceFrame(self): #NOSONAR pylint: disable=no-self-use,invalid-name raise NotImplementedException( "Method not implemented by derived class") - def addToFrame(self, message): #NOSONAR pylint: disable=no-self-use,invalid-name - """ Add the next message to the frame buffer + def addToFrame(self, message): # NOSONAR pylint: disable=no-self-use,invalid-name + """Add the next message to the frame buffer. This should be used before the decoding while loop to add the received data to the buffer handle. @@ -95,8 +100,8 @@ def addToFrame(self, message): #NOSONAR pylint: disable=no-self-use,invalid-name raise NotImplementedException( "Method not implemented by derived class") - def isFrameReady(self): #NOSONAR pylint: disable=no-self-use,invalid-name - """ Check if we should continue decode logic + def isFrameReady(self): # NOSONAR pylint: disable=no-self-use,invalid-name + """Check if we should continue decode logic. This is meant to be used in a while loop in the decoding phase to let the decoder know that there is still data in the buffer. @@ -106,16 +111,16 @@ def isFrameReady(self): #NOSONAR pylint: disable=no-self-use,invalid-name raise NotImplementedException( "Method not implemented by derived class") - def getFrame(self): #NOSONAR pylint: disable=no-self-use,invalid-name - """ Get the next frame from the buffer + def getFrame(self): # NOSONAR pylint: disable=no-self-use,invalid-name + """Get the next frame from the buffer. :returns: The frame data or '' """ raise NotImplementedException( "Method not implemented by derived class") - def populateResult(self, result): #NOSONAR pylint: disable=no-self-use,invalid-name - """ Populates the modbus result with current frame header + def populateResult(self, result): # NOSONAR pylint: disable=no-self-use,invalid-name + """Populate the modbus result with current frame header. We basically copy the data back over from the current header to the result header. This may not be needed for serial messages. @@ -125,8 +130,8 @@ def populateResult(self, result): #NOSONAR pylint: disable=no-self-use,invalid-n raise NotImplementedException( "Method not implemented by derived class") - def processIncomingPacket(self, data, callback): #NOSONAR pylint: disable=no-self-use,invalid-name - """ The new packet processing pattern + def processIncomingPacket(self, data, callback): # NOSONAR pylint: disable=no-self-use,invalid-name + """Process new packet pattern. This takes in a new request packet, adds it to the current packet stream, and performs framing on it. That is, checks @@ -143,8 +148,8 @@ def processIncomingPacket(self, data, callback): #NOSONAR pylint: disable=no-sel raise NotImplementedException( "Method not implemented by derived class") - def buildPacket(self, message): #NOSONAR pylint: disable=no-self-use,invalid-name - """ Creates a ready to send modbus packet + def buildPacket(self, message): # NOSONAR pylint: disable=no-self-use,invalid-name + """Create a ready to send modbus packet. The raw packet is built off of a fully populated modbus request / response message. @@ -157,7 +162,7 @@ def buildPacket(self, message): #NOSONAR pylint: disable=no-self-use,invalid-nam class IModbusSlaveContext: - """ Interface for a modbus slave data context + """Interface for a modbus slave data context. Derived classes must implemented the following methods: reset(self) @@ -165,25 +170,25 @@ class IModbusSlaveContext: getValues(self, fx, address, count=1) setValues(self, fx, address, values) """ + __fx_mapper = {2: 'd', 4: 'i'} __fx_mapper.update([(i, 'h') for i in (3, 6, 16, 22, 23)]) __fx_mapper.update([(i, 'c') for i in (1, 5, 15)]) - def decode(self, fx): # pylint: disable=invalid-name - """ Converts the function code to the datastore to + def decode(self, fx): # pylint: disable=invalid-name + """Convert the function code to the datastore to. :param fx: The function we are working with :returns: one of [d(iscretes),i(nputs),h(olding),c(oils) """ return self.__fx_mapper[fx] - def reset(self): # pylint: disable=no-self-use - """ Resets all the datastores to their default values - """ + def reset(self): # pylint: disable=no-self-use + """Reset all the datastores to their default values.""" raise NotImplementedException("Context Reset") - def validate(self, fx, address, count=1): # pylint: disable=no-self-use,invalid-name - """ Validates the request to make sure it is in range + def validate(self, fx, address, count=1): # pylint: disable=no-self-use,invalid-name + """Validate the request to make sure it is in range. :param fx: The function we are working with :param address: The starting address @@ -192,8 +197,8 @@ def validate(self, fx, address, count=1): # pylint: disable=no-self-use,invalid- """ raise NotImplementedException("validate context values") - def getValues(self, fx, address, count=1): #NOSONAR pylint: disable=no-self-use,invalid-name - """ Get `count` values from datastore + def getValues(self, fx, address, count=1): # NOSONAR pylint: disable=no-self-use,invalid-name + """Get `count` values from datastore. :param fx: The function we are working with :param address: The starting address @@ -202,8 +207,8 @@ def getValues(self, fx, address, count=1): #NOSONAR pylint: disable=no-self-use, """ raise NotImplementedException("get context values") - def setValues(self, fx, address, values): #NOSONAR pylint: disable=no-self-use,invalid-name - """ Sets the datastore with the supplied values + def setValues(self, fx, address, values): # NOSONAR pylint: disable=no-self-use,invalid-name + """Set the datastore with the supplied values. :param fx: The function we are working with :param address: The starting address @@ -212,15 +217,15 @@ def setValues(self, fx, address, values): #NOSONAR pylint: disable=no-self-use,i raise NotImplementedException("set context values") -class IPayloadBuilder: # pylint: disable=too-few-public-methods - """ This is an interface to a class that can build a payload - for a modbus register write command. It should abstract - the codec for encoding data to the required format +class IPayloadBuilder: # pylint: disable=too-few-public-methods + """This is an interface to a class that can build a payload for a modbus register write command. + + It should abstract the codec for encoding data to the required format (bcd, binary, char, etc). """ - def build(self): # pylint: disable=no-self-use - """ Return the payload buffer as a list + def build(self): # pylint: disable=no-self-use + """Return the payload buffer as a list. This list is two bytes per element and can thus be treated as a list of registers. diff --git a/pymodbus/mei_message.py b/pymodbus/mei_message.py index e04c46e95..392be8f09 100644 --- a/pymodbus/mei_message.py +++ b/pymodbus/mei_message.py @@ -1,7 +1,4 @@ -""" Encapsulated Interface (MEI) Transport Messages ------------------------------------------------ - -""" +"""Encapsulated Interface (MEI) Transport Messages.""" import struct from pymodbus.constants import DeviceInformation, MoreData from pymodbus.pdu import ModbusRequest @@ -14,7 +11,8 @@ class _OutOfSpaceException(Exception): - """ Internal out of space exception. """ + """Internal out of space exception.""" + # This exception exists here as a simple, local way to manage response # length control for the only MODBUS command which requires it under # standard, non-error conditions. It and the structures associated with @@ -25,16 +23,19 @@ class _OutOfSpaceException(Exception): # restricted to 253 bytes, irrespective of the transport used. # # See Page 5/50 of MODBUS Application Protocol Specification V1.1b3. + def __init__(self, oid): self.oid = oid super().__init__() -#---------------------------------------------------------------------------# -# Read Device Information -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Read Device Information +# ---------------------------------------------------------------------------# class ReadDeviceInformationRequest(ModbusRequest): - """ This function code allows reading the identification and additional + """Read device information. + + This function code allows reading the identification and additional information relative to the physical and functional description of a remote device, only. @@ -42,12 +43,13 @@ class ReadDeviceInformationRequest(ModbusRequest): composed of a set of addressable data elements. The data elements are called objects and an object Id identifies them. """ + function_code = 0x2b sub_function_code = 0x0e _rtu_frame_size = 7 def __init__(self, read_code=None, object_id=0x00, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param read_code: The device information read code :param object_id: The object to read from @@ -57,24 +59,24 @@ def __init__(self, read_code=None, object_id=0x00, **kwargs): self.object_id = object_id def encode(self): - """ Encodes the request packet + """Encode the request packet. :returns: The byte encoded packet """ packet = struct.pack('>BBB', self.sub_function_code, - self.read_code, self.object_id) + self.read_code, self.object_id) return packet def decode(self, data): - """ Decodes data part of the message. + """Decode data part of the message. :param data: The incoming data """ params = struct.unpack('>BBB', data) self.sub_function_code, self.read_code, self.object_id = params - def execute(self, context): #NOSONAR pylint: disable=unused-argument - """ Run a read exception status request against the store + def execute(self, context): # NOSONAR pylint: disable=unused-argument + """Run a read exception status request against the store. :param context: The datastore to request from :returns: The populated response @@ -85,41 +87,42 @@ def execute(self, context): #NOSONAR pylint: disable=unused-argument return self.doException(merror.IllegalValue) information = DeviceInformationFactory.get(_MCB, - self.read_code, self.object_id) + self.read_code, self.object_id) return ReadDeviceInformationResponse(self.read_code, information) def __str__(self): - """ Builds a representation of the request + """Build a representation of the request. :returns: The string representation of the request """ params = (self.read_code, self.object_id) - return "ReadDeviceInformationRequest(%d,%d)" % params # pylint: disable=consider-using-f-string + return "ReadDeviceInformationRequest(%d,%d)" % params # pylint: disable=consider-using-f-string class ReadDeviceInformationResponse(ModbusResponse): """Read device information response.""" + function_code = 0x2b sub_function_code = 0x0e @classmethod def calculateRtuFrameSize(cls, buffer): - """ Calculates the size of the message + """Calculate the size of the message :param buffer: A buffer containing the data that have been received. :returns: The number of bytes in the response. """ - size = 8 # skip the header information + size = 8 # skip the header information count = int(buffer[7]) while count > 0: - _, object_length = struct.unpack('>BB', buffer[size:size+2]) + _, object_length = struct.unpack('>BB', buffer[size:size + 2]) size += object_length + 2 count -= 1 return size + 2 def __init__(self, read_code=None, information=None, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param read_code: The device information read code :param information: The requested information request @@ -134,7 +137,7 @@ def __init__(self, read_code=None, information=None, **kwargs): self.space_left = None def _encode_object(self, object_id, data): - """ Internal encode object. """ + """Encode object.""" self.space_left -= (2 + len(data)) if self.space_left <= 0: raise _OutOfSpaceException(object_id) @@ -147,7 +150,7 @@ def _encode_object(self, object_id, data): return encoded_obj def encode(self): - """ Encodes the response + """Encode the response. :returns: The byte encoded message """ @@ -172,7 +175,7 @@ def encode(self): return packet def decode(self, data): - """ Decodes a the response + """Decode a the response. :param data: The packet data to decode """ @@ -180,29 +183,30 @@ def decode(self, data): self.sub_function_code, self.read_code = params[0:2] self.conformity, self.more_follows = params[2:4] self.next_object_id, self.number_of_objects = params[4:6] - self.information, count = {}, 6 # skip the header information + self.information, count = {}, 6 # skip the header information while count < len(data): - object_id, object_length = struct.unpack('>BB', data[count:count+2]) + object_id, object_length = struct.unpack('>BB', data[count:count + 2]) count += object_length + 2 if object_id not in self.information.keys(): - self.information[object_id] = data[count-object_length:count] + self.information[object_id] = data[count - object_length:count] elif isinstance(self.information[object_id], list): - self.information[object_id].append(data[count-object_length:count]) + self.information[object_id].append(data[count - object_length:count]) else: self.information[object_id] = [self.information[object_id], data[count - object_length:count]] def __str__(self): - """ Builds a representation of the response + """Build a representation of the response. :returns: The string representation of the response """ return f"ReadDeviceInformationResponse({self.read_code})" -#---------------------------------------------------------------------------# -# Exported symbols -#---------------------------------------------------------------------------# + +# ---------------------------------------------------------------------------# +# Exported symbols +# ---------------------------------------------------------------------------# __all__ = [ "ReadDeviceInformationRequest", "ReadDeviceInformationResponse", ] diff --git a/pymodbus/other_message.py b/pymodbus/other_message.py index de51ea699..f609643c7 100644 --- a/pymodbus/other_message.py +++ b/pymodbus/other_message.py @@ -1,4 +1,4 @@ -""" Diagnostic record read/write +"""Diagnostic record read/write. Currently not all implemented """ @@ -11,34 +11,36 @@ _MCB = ModbusControlBlock() -#---------------------------------------------------------------------------# -# TODO Make these only work on serial # pylint: disable=fixme -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# TODO Make these only work on serial # pylint: disable=fixme +# ---------------------------------------------------------------------------# class ReadExceptionStatusRequest(ModbusRequest): - """ This function code is used to read the contents of eight Exception Status - outputs in a remote device. The function provides a simple method for + """This function code is used to read the contents of eight Exception Status outputs in a remote device. + + The function provides a simple method for accessing this information, because the Exception Output references are known (no output reference is needed in the function). """ + function_code = 0x07 _rtu_frame_size = 4 def __init__(self, **kwargs): - """ Initializes a new instance. """ + """Initialize a new instance.""" ModbusRequest.__init__(self, **kwargs) def encode(self): - """ Encodes the message. """ + """Encode the message.""" return b'' def decode(self, data): - """ Decodes data part of the message. + """Decode data part of the message. :param data: The incoming data """ - def execute(self, context=None): #NOSONAR pylint: disable=no-self-use,unused-argument - """ Run a read exception status request against the store + def execute(self, context=None): # NOSONAR pylint: disable=no-self-use,unused-argument + """Run a read exception status request against the store. :returns: The populated response """ @@ -46,7 +48,7 @@ def execute(self, context=None): #NOSONAR pylint: disable=no-self-use,unused-arg return ReadExceptionStatusResponse(status) def __str__(self): - """ Builds a representation of the request + """Build a representation of the request. :returns: The string representation of the request """ @@ -54,17 +56,19 @@ def __str__(self): class ReadExceptionStatusResponse(ModbusResponse): - """ The normal response contains the status of the eight Exception Status - outputs. The outputs are packed into one data byte, with one bit + """The normal response contains the status of the eight Exception Status outputs. + + The outputs are packed into one data byte, with one bit per output. The status of the lowest output reference is contained in the least significant bit of the byte. The contents of the eight Exception Status outputs are device specific. """ + function_code = 0x07 _rtu_frame_size = 5 def __init__(self, status=0x00, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param status: The status response to report """ @@ -72,37 +76,38 @@ def __init__(self, status=0x00, **kwargs): self.status = status def encode(self): - """ Encodes the response + """Encode the response. :returns: The byte encoded message """ return struct.pack('>B', self.status) def decode(self, data): - """ Decodes a the response + """Decode a the response. :param data: The packet data to decode """ self.status = int(data[0]) def __str__(self): - """ Builds a representation of the response + """Build a representation of the response. :returns: The string representation of the response """ arguments = (self.function_code, self.status) - return "ReadExceptionStatusResponse(%d, %s)" % arguments # pylint: disable=consider-using-f-string + return "ReadExceptionStatusResponse(%d, %s)" % arguments # pylint: disable=consider-using-f-string # Encapsulate interface transport 43, 14 # CANopen general reference 43, 13 -#---------------------------------------------------------------------------# -# TODO Make these only work on serial #NOSONAR pylint: disable=fixme -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# TODO Make these only work on serial #NOSONAR pylint: disable=fixme +# ---------------------------------------------------------------------------# class GetCommEventCounterRequest(ModbusRequest): - """ This function code is used to get a status word and an event count from - the remote device's communication event counter. + """This function code is used to get a status word. + + And an event count from the remote device's communication event counter. By fetching the current count before and after a series of messages, a client can determine whether the messages were handled normally by the @@ -116,25 +121,26 @@ class GetCommEventCounterRequest(ModbusRequest): (code 08), with a subfunction of Restart Communications Option (code 00 01) or Clear Counters and Diagnostic Register (code 00 0A). """ + function_code = 0x0b _rtu_frame_size = 4 def __init__(self, **kwargs): - """ Initializes a new instance. """ + """Initialize a new instance.""" ModbusRequest.__init__(self, **kwargs) def encode(self): - """ Encodes the message. """ + """Encode the message.""" return b'' def decode(self, data): - """ Decodes data part of the message. + """Decode data part of the message. :param data: The incoming data """ - def execute(self, context=None): #NOSONAR pylint: disable=no-self-use,unused-argument - """ Run a read exception status request against the store + def execute(self, context=None): # NOSONAR pylint: disable=no-self-use,unused-argument + """Run a read exception status request against the store. :returns: The populated response """ @@ -142,7 +148,7 @@ def execute(self, context=None): #NOSONAR pylint: disable=no-self-use,unused-ar return GetCommEventCounterResponse(status) def __str__(self): - """ Builds a representation of the request + """Build a representation of the request. :returns: The string representation of the request """ @@ -150,17 +156,20 @@ def __str__(self): class GetCommEventCounterResponse(ModbusResponse): - """ The normal response contains a two-byte status word, and a two-byte + """Get comm event counter response. + + The normal response contains a two-byte status word, and a two-byte event count. The status word will be all ones (FF FF hex) if a previously-issued program command is still being processed by the remote device (a busy condition exists). Otherwise, the status word will be all zeros. """ + function_code = 0x0b _rtu_frame_size = 8 def __init__(self, count=0x0000, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param count: The current event counter value """ @@ -169,17 +178,18 @@ def __init__(self, count=0x0000, **kwargs): self.status = True # this means we are ready, not waiting def encode(self): - """ Encodes the response + """Encode the response. :returns: The byte encoded message """ if self.status: ready = ModbusStatus.Ready - else: ready = ModbusStatus.Waiting + else: + ready = ModbusStatus.Waiting return struct.pack('>HH', ready, self.count) def decode(self, data): - """ Decodes a the response + """Decode a the response. :param data: The packet data to decode """ @@ -187,20 +197,21 @@ def decode(self, data): self.status = (ready == ModbusStatus.Ready) def __str__(self): - """ Builds a representation of the response + """Build a representation of the response. :returns: The string representation of the response """ arguments = (self.function_code, self.count, self.status) - return "GetCommEventCounterResponse(%d, %d, %d)" % arguments # pylint: disable=consider-using-f-string + return "GetCommEventCounterResponse(%d, %d, %d)" % arguments # pylint: disable=consider-using-f-string -#---------------------------------------------------------------------------# -# TODO Make these only work on serial #NOSONAR pylint: disable=fixme -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# TODO Make these only work on serial #NOSONAR pylint: disable=fixme +# ---------------------------------------------------------------------------# class GetCommEventLogRequest(ModbusRequest): - """ This function code is used to get a status word, event count, message - count, and a field of event bytes from the remote device. + """This function code is used to get a status word. + + Event count, message count, and a field of event bytes from the remote device. The status word and event counts are identical to that returned by the Get Communications Event Counter function (11, 0B hex). @@ -217,38 +228,39 @@ class GetCommEventLogRequest(ModbusRequest): chronological order. Byte 0 is the most recent event. Each new byte flushes the oldest byte from the field. """ + function_code = 0x0c _rtu_frame_size = 4 def __init__(self, **kwargs): - """ Initializes a new instance. """ + """Initialize a new instance.""" ModbusRequest.__init__(self, **kwargs) def encode(self): - """ Encodes the message. """ + """Encode the message.""" return b'' def decode(self, data): - """ Decodes data part of the message. + """Decode data part of the message. :param data: The incoming data """ - def execute(self, context=None): #NOSONAR pylint: disable=no-self-use,unused-argument - """ Run a read exception status request against the store + def execute(self, context=None): # NOSONAR pylint: disable=no-self-use,unused-argument + """Run a read exception status request against the store. :returns: The populated response """ results = { - 'status' : True, - 'message_count' : _MCB.Counter.BusMessage, - 'event_count' : _MCB.Counter.Event, - 'events' : _MCB.getEvents(), + 'status': True, + 'message_count': _MCB.Counter.BusMessage, + 'event_count': _MCB.Counter.Event, + 'events': _MCB.getEvents(), } return GetCommEventLogResponse(**results) def __str__(self): - """ Builds a representation of the request + """Build a representation of the request. :returns: The string representation of the request """ @@ -256,16 +268,19 @@ def __str__(self): class GetCommEventLogResponse(ModbusResponse): - """ The normal response contains a two-byte status word field, + """Get Comm event log response. + + The normal response contains a two-byte status word field, a two-byte event count field, a two-byte message count field, and a field containing 0-64 bytes of events. A byte count field defines the total length of the data in these four field """ + function_code = 0x0c _rtu_byte_count_pos = 2 def __init__(self, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param status: The status response to report :param message_count: The current message count @@ -279,21 +294,22 @@ def __init__(self, **kwargs): self.events = kwargs.get('events', []) def encode(self): - """ Encodes the response + """Encode the response. :returns: The byte encoded message """ if self.status: ready = ModbusStatus.Ready - else: ready = ModbusStatus.Waiting - packet = struct.pack('>B', 6 + len(self.events)) + else: + ready = ModbusStatus.Waiting + packet = struct.pack('>B', 6 + len(self.events)) packet += struct.pack('>H', ready) packet += struct.pack('>HH', self.event_count, self.message_count) packet += b''.join(struct.pack('>B', e) for e in self.events) return packet def decode(self, data): - """ Decodes a the response + """Decode a the response. :param data: The packet data to decode """ @@ -308,42 +324,42 @@ def decode(self, data): self.events.append(int(data[i])) def __str__(self): - """ Builds a representation of the response + """Build a representation of the response. :returns: The string representation of the response """ arguments = (self.function_code, self.status, self.message_count, self.event_count) - return "GetCommEventLogResponse(%d, %d, %d, %d)" % arguments # pylint: disable=consider-using-f-string + return "GetCommEventLogResponse(%d, %d, %d, %d)" % arguments # pylint: disable=consider-using-f-string -#---------------------------------------------------------------------------# -# TODO Make these only work on serial #NOSONAR pylint: disable=fixme -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# TODO Make these only work on serial #NOSONAR pylint: disable=fixme +# ---------------------------------------------------------------------------# class ReportSlaveIdRequest(ModbusRequest): - """ This function code is used to read the description of the type, the - current status, and other information specific to a remote device. + """This function code is used to read the description of the type. + + The current status, and other information specific to a remote device. """ + function_code = 0x11 _rtu_frame_size = 4 def __init__(self, **kwargs): - """ Initializes a new instance - """ + """Initialize a new instance.""" ModbusRequest.__init__(self, **kwargs) def encode(self): - """ Encodes the message - """ + """Encode the message.""" return b'' def decode(self, data): - """ Decodes data part of the message. + """Decode data part of the message. :param data: The incoming data """ - def execute(self, context=None): # pylint: disable=no-self-use - """ Run a report slave id request against the store + def execute(self, context=None): # pylint: disable=no-self-use + """Run a report slave id request against the store. :returns: The populated response """ @@ -367,7 +383,7 @@ def execute(self, context=None): # pylint: disable=no-self-use return ReportSlaveIdResponse(report_slave_id_data) def __str__(self): - """ Builds a representation of the request + """Build a representation of the request. :returns: The string representation of the request """ @@ -375,14 +391,16 @@ def __str__(self): class ReportSlaveIdResponse(ModbusResponse): - """ The format of a normal response is shown in the following example. + """Show response. + The data contents are specific to each type of device. """ + function_code = 0x11 _rtu_byte_count_pos = 2 def __init__(self, identifier=b'\x00', status=True, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param identifier: The identifier of the slave :param status: The status response to report @@ -393,7 +411,7 @@ def __init__(self, identifier=b'\x00', status=True, **kwargs): self.byte_count = None def encode(self): - """ Encodes the response + """Encode the response. :returns: The byte encoded message """ @@ -401,14 +419,14 @@ def encode(self): status = ModbusStatus.SlaveOn else: status = ModbusStatus.SlaveOff - length = len(self.identifier) + 1 - packet = struct.pack(">B", length) + length = len(self.identifier) + 1 + packet = struct.pack(">B", length) packet += self.identifier # we assume it is already encoded packet += struct.pack(">B", status) return packet def decode(self, data): - """ Decodes a the response + """Decode a the response. Since the identifier is device dependent, we just return the raw value that a user can decode to whatever it should be. @@ -421,21 +439,22 @@ def decode(self, data): self.status = status == ModbusStatus.SlaveOn def __str__(self): - """ Builds a representation of the response + """Build a representation of the response. :returns: The string representation of the response """ arguments = (self.function_code, self.identifier, self.status) - return "ReportSlaveIdResponse(%s, %s, %s)" % arguments # pylint: disable=consider-using-f-string + return "ReportSlaveIdResponse(%s, %s, %s)" % arguments # pylint: disable=consider-using-f-string -#---------------------------------------------------------------------------# -# TODO Make these only work on serial #NOSONAR pylint: disable=fixme -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# TODO Make these only work on serial #NOSONAR pylint: disable=fixme +# ---------------------------------------------------------------------------# # report device identification 43, 14 -#---------------------------------------------------------------------------# -# Exported symbols -#---------------------------------------------------------------------------# + +# ---------------------------------------------------------------------------# +# Exported symbols +# ---------------------------------------------------------------------------# __all__ = [ "ReadExceptionStatusRequest", "ReadExceptionStatusResponse", "GetCommEventCounterRequest", "GetCommEventCounterResponse", diff --git a/pymodbus/payload.py b/pymodbus/payload.py index ede7b31da..e10f418e9 100644 --- a/pymodbus/payload.py +++ b/pymodbus/payload.py @@ -1,10 +1,7 @@ -""" Modbus Payload Builders ------------------------- +"""Modbus Payload Builders. A collection of utilities for building and decoding modbus messages payloads. - - """ import logging @@ -34,11 +31,11 @@ class BinaryPayloadBuilder(IPayloadBuilder): - """ A utility that helps build payload messages to be - written with the various modbus messages. It really is just - a simple wrapper around the struct module, however it saves - time looking up the format strings. What follows is a simple - example:: + """A utility that helps build payload messages to be written with the various modbus messages. + + It really is just a simple wrapper around the struct module, + however it saves time looking up the format strings. + What follows is a simple example:: builder = BinaryPayloadBuilder(byteorder=Endian.Little) builder.add_8bit_uint(1) @@ -48,7 +45,7 @@ class BinaryPayloadBuilder(IPayloadBuilder): def __init__(self, payload=None, byteorder=Endian.Little, wordorder=Endian.Big, repack=False): - """ Initialize a new instance of the payload builder + """Initialize a new instance of the payload builder. :param payload: Raw binary payload data to initialize with :param byteorder: The endianness of the bytes in the words @@ -61,7 +58,7 @@ def __init__(self, payload=None, byteorder=Endian.Little, self._repack = repack def _pack_words(self, fstring, value): - """ Packs Words based on the word order and byte order + """Pack words based on the word order and byte order. # ---------------------------------------------- # # pack in to network ordered value # @@ -73,8 +70,8 @@ def _pack_words(self, fstring, value): :param value: Value to be packed :return: """ - value = pack("!{}".format(fstring), value) # pylint: disable=consider-using-f-string - wordorder = WC.get(fstring.lower())//2 + value = pack("!{}".format(fstring), value) # pylint: disable=consider-using-f-string + wordorder = WC.get(fstring.lower()) // 2 upperbyte = f"!{wordorder}H" payload = unpack(upperbyte, value) @@ -88,26 +85,25 @@ def _pack_words(self, fstring, value): return payload def to_string(self): - """ Return the payload buffer as a string + """Return the payload buffer as a string. :returns: The payload buffer as a string """ return b''.join(self._payload) def __str__(self): - """ Return the payload buffer as a string + """Return the payload buffer as a string. :returns: The payload buffer as a string """ return self.to_string().decode('utf-8') def reset(self): - """ Reset the payload buffer. """ + """Reset the payload buffer.""" self._payload = [] def to_registers(self): - """ Convert the payload buffer into a register - layout that can be used as a context block. + """Convert the payload buffer to register layout that can be used as a context block. :returns: The register layout to use as a block """ @@ -115,15 +111,14 @@ def to_registers(self): fstring = '!H' payload = self.build() if self._repack: - payload = [unpack(self._byteorder+"H", value)[0] for value in payload] + payload = [unpack(self._byteorder + "H", value)[0] for value in payload] else: payload = [unpack(fstring, value)[0] for value in payload] _logger.debug(payload) return payload def to_coils(self): - """Convert the payload buffer into a coil - layout that can be used as a context block. + """Convert the payload buffer into a coil layout that can be used as a context block. :returns: The coil layout to use as a block """ @@ -133,7 +128,7 @@ def to_coils(self): return coils def build(self): - """ Return the payload buffer as a list + """Return the payload buffer as a list. This list is two bytes per element and can thus be treated as a list of registers. @@ -143,10 +138,10 @@ def build(self): string = self.to_string() length = len(string) string = string + (b'\x00' * (length % 2)) - return [string[i:i+2] for i in range(0, length, 2)] + return [string[i:i + 2] for i in range(0, length, 2)] def add_bits(self, values): - """ Adds a collection of bits to be encoded + """Add a collection of bits to be encoded. If these are less than a multiple of eight, they will be left padded with 0 bits to make @@ -158,7 +153,7 @@ def add_bits(self, values): self._payload.append(value) def add_8bit_uint(self, value): - """ Adds a 8 bit unsigned int to the buffer + """Add a 8 bit unsigned int to the buffer. :param value: The value to add to the buffer """ @@ -166,7 +161,7 @@ def add_8bit_uint(self, value): self._payload.append(pack(fstring, value)) def add_16bit_uint(self, value): - """ Adds a 16 bit unsigned int to the buffer + """Add a 16 bit unsigned int to the buffer. :param value: The value to add to the buffer """ @@ -174,7 +169,7 @@ def add_16bit_uint(self, value): self._payload.append(pack(fstring, value)) def add_32bit_uint(self, value): - """ Adds a 32 bit unsigned int to the buffer + """Add a 32 bit unsigned int to the buffer. :param value: The value to add to the buffer """ @@ -184,7 +179,7 @@ def add_32bit_uint(self, value): self._payload.append(p_string) def add_64bit_uint(self, value): - """ Adds a 64 bit unsigned int to the buffer + """Add a 64 bit unsigned int to the buffer. :param value: The value to add to the buffer """ @@ -193,7 +188,7 @@ def add_64bit_uint(self, value): self._payload.append(p_string) def add_8bit_int(self, value): - """ Adds a 8 bit signed int to the buffer + """Add a 8 bit signed int to the buffer. :param value: The value to add to the buffer """ @@ -201,7 +196,7 @@ def add_8bit_int(self, value): self._payload.append(pack(fstring, value)) def add_16bit_int(self, value): - """ Adds a 16 bit signed int to the buffer + """Add a 16 bit signed int to the buffer. :param value: The value to add to the buffer """ @@ -209,7 +204,7 @@ def add_16bit_int(self, value): self._payload.append(pack(fstring, value)) def add_32bit_int(self, value): - """ Adds a 32 bit signed int to the buffer + """Add a 32 bit signed int to the buffer. :param value: The value to add to the buffer """ @@ -218,7 +213,7 @@ def add_32bit_int(self, value): self._payload.append(p_string) def add_64bit_int(self, value): - """ Adds a 64 bit signed int to the buffer + """Add a 64 bit signed int to the buffer. :param value: The value to add to the buffer """ @@ -227,7 +222,7 @@ def add_64bit_int(self, value): self._payload.append(p_string) def add_16bit_float(self, value): - """ Adds a 16 bit float to the buffer + """Add a 16 bit float to the buffer. :param value: The value to add to the buffer """ @@ -235,9 +230,8 @@ def add_16bit_float(self, value): p_string = self._pack_words(fstring, value) self._payload.append(p_string) - def add_32bit_float(self, value): - """ Adds a 32 bit float to the buffer + """Add a 32 bit float to the buffer. :param value: The value to add to the buffer """ @@ -246,7 +240,7 @@ def add_32bit_float(self, value): self._payload.append(p_string) def add_64bit_float(self, value): - """ Adds a 64 bit float(double) to the buffer + """Add a 64 bit float(double) to the buffer. :param value: The value to add to the buffer """ @@ -255,7 +249,7 @@ def add_64bit_float(self, value): self._payload.append(p_string) def add_string(self, value): - """ Adds a string to the buffer + """Add a string to the buffer. :param value: The value to add to the buffer """ @@ -265,8 +259,9 @@ def add_string(self, value): class BinaryPayloadDecoder: - """ A utility that helps decode payload messages from a modbus - response message. It really is just a simple wrapper around + """A utility that helps decode payload messages from a modbus response message. + + It really is just a simple wrapper around the struct module, however it saves time looking up the format strings. What follows is a simple example:: @@ -276,7 +271,7 @@ class BinaryPayloadDecoder: """ def __init__(self, payload, byteorder=Endian.Little, wordorder=Endian.Big): - """ Initialize a new payload decoder + """Initialize a new payload decoder. :param payload: The payload to decode with :param byteorder: The endianness of the payload @@ -288,10 +283,11 @@ def __init__(self, payload, byteorder=Endian.Little, wordorder=Endian.Big): self._wordorder = wordorder @classmethod - def fromRegisters(cls, registers, byteorder=Endian.Little, # pylint: disable=invalid-name + def fromRegisters(cls, registers, byteorder=Endian.Little, # pylint: disable=invalid-name wordorder=Endian.Big): - """ Initialize a payload decoder with the result of - reading a collection of registers from a modbus device. + """Initialize a payload decoder. + + With the result of reading a collection of registers from a modbus device. The registers are treated as a list of 2 byte values. We have to do this because of how the data has already @@ -310,14 +306,13 @@ def fromRegisters(cls, registers, byteorder=Endian.Little, # pylint: disable=inv @classmethod def bit_chunks(cls, coils, size=8): - """ Return bit chunks. """ + """Return bit chunks.""" chunks = [coils[i: i + size] for i in range(0, len(coils), size)] return chunks @classmethod - def fromCoils(cls, coils, byteorder=Endian.Little, wordorder=Endian.Big): #NOSONAR pylint: disable=unused-argument,invalid-name - """ Initialize a payload decoder with the result of - reading a collection of coils from a modbus device. + def fromCoils(cls, coils, byteorder=Endian.Little, wordorder=Endian.Big): # NOSONAR pylint: disable=C0103,W0613 + """Initialize a payload decoder with the result of reading of coils. The coils are treated as a list of bit(boolean) values. @@ -337,7 +332,7 @@ def fromCoils(cls, coils, byteorder=Endian.Little, wordorder=Endian.Big): #NOSON raise ParameterException('Invalid collection of coils supplied') def _unpack_words(self, fstring, handle): - """ Un Packs Words based on the word order and byte order + """Unpack words based on the word order and byte order. # ---------------------------------------------- # # Unpack in to network ordered unsigned integer # @@ -360,11 +355,11 @@ def _unpack_words(self, fstring, handle): return handle def reset(self): - """ Reset the decoder pointer back to the start. """ + """Reset the decoder pointer back to the start.""" self._pointer = 0x00 def decode_8bit_uint(self): - """ Decodes a 8 bit unsigned int from the buffer. """ + """Decode a 8 bit unsigned int from the buffer.""" self._pointer += 1 fstring = self._byteorder + 'B' handle = self._payload[self._pointer - 1:self._pointer] @@ -372,7 +367,7 @@ def decode_8bit_uint(self): return unpack(fstring, handle)[0] def decode_bits(self): - """ Decodes a byte worth of bits from the buffer. """ + """Decode a byte worth of bits from the buffer.""" self._pointer += 1 # fstring = self._endian + 'B' handle = self._payload[self._pointer - 1:self._pointer] @@ -380,7 +375,7 @@ def decode_bits(self): return unpack_bitstring(handle) def decode_16bit_uint(self): - """ Decodes a 16 bit unsigned int from the buffer. """ + """Decode a 16 bit unsigned int from the buffer.""" self._pointer += 2 fstring = self._byteorder + 'H' handle = self._payload[self._pointer - 2:self._pointer] @@ -388,24 +383,24 @@ def decode_16bit_uint(self): return unpack(fstring, handle)[0] def decode_32bit_uint(self): - """ Decodes a 32 bit unsigned int from the buffer. """ + """Decode a 32 bit unsigned int from the buffer.""" self._pointer += 4 fstring = 'I' # fstring = 'I' handle = self._payload[self._pointer - 4:self._pointer] handle = self._unpack_words(fstring, handle) - return unpack("!"+fstring, handle)[0] + return unpack("!" + fstring, handle)[0] def decode_64bit_uint(self): - """ Decodes a 64 bit unsigned int from the buffer. """ + """Decode a 64 bit unsigned int from the buffer.""" self._pointer += 8 fstring = 'Q' handle = self._payload[self._pointer - 8:self._pointer] handle = self._unpack_words(fstring, handle) - return unpack("!"+fstring, handle)[0] + return unpack("!" + fstring, handle)[0] def decode_8bit_int(self): - """ Decodes a 8 bit signed int from the buffer. """ + """Decode a 8 bit signed int from the buffer.""" self._pointer += 1 fstring = self._byteorder + 'b' handle = self._payload[self._pointer - 1:self._pointer] @@ -413,7 +408,7 @@ def decode_8bit_int(self): return unpack(fstring, handle)[0] def decode_16bit_int(self): - """ Decodes a 16 bit signed int from the buffer. """ + """Decode a 16 bit signed int from the buffer.""" self._pointer += 2 fstring = self._byteorder + 'h' handle = self._payload[self._pointer - 2:self._pointer] @@ -421,51 +416,47 @@ def decode_16bit_int(self): return unpack(fstring, handle)[0] def decode_32bit_int(self): - """ Decodes a 32 bit signed int from the buffer. """ + """Decode a 32 bit signed int from the buffer.""" self._pointer += 4 fstring = 'i' handle = self._payload[self._pointer - 4:self._pointer] handle = self._unpack_words(fstring, handle) - return unpack("!"+fstring, handle)[0] + return unpack("!" + fstring, handle)[0] def decode_64bit_int(self): - """ Decodes a 64 bit signed int from the buffer. """ + """Decode a 64 bit signed int from the buffer.""" self._pointer += 8 fstring = 'q' handle = self._payload[self._pointer - 8:self._pointer] handle = self._unpack_words(fstring, handle) - return unpack("!"+fstring, handle)[0] + return unpack("!" + fstring, handle)[0] def decode_16bit_float(self): - """ Decodes a 16 bit float from the buffer - """ + """Decode a 16 bit float from the buffer.""" self._pointer += 2 fstring = 'e' handle = self._payload[self._pointer - 2:self._pointer] handle = self._unpack_words(fstring, handle) - return unpack("!"+fstring, handle)[0] - + return unpack("!" + fstring, handle)[0] def decode_32bit_float(self): - """ Decodes a 32 bit float from the buffer - """ + """Decode a 32 bit float from the buffer.""" self._pointer += 4 fstring = 'f' handle = self._payload[self._pointer - 4:self._pointer] handle = self._unpack_words(fstring, handle) - return unpack("!"+fstring, handle)[0] + return unpack("!" + fstring, handle)[0] def decode_64bit_float(self): - """ Decodes a 64 bit float(double) from the buffer - """ + """Decode a 64 bit float(double) from the buffer.""" self._pointer += 8 fstring = 'd' handle = self._payload[self._pointer - 8:self._pointer] handle = self._unpack_words(fstring, handle) - return unpack("!"+fstring, handle)[0] + return unpack("!" + fstring, handle)[0] def decode_string(self, size=1): - """ Decodes a string from the buffer + """Decode a string from the buffer. :param size: The size of the string to decode """ @@ -473,13 +464,14 @@ def decode_string(self, size=1): return self._payload[self._pointer - size:self._pointer] def skip_bytes(self, nbytes): - """ Skip n bytes in the buffer + """Skip n bytes in the buffer. :param nbytes: The number of bytes to skip """ self._pointer += nbytes -#---------------------------------------------------------------------------# -# Exported Identifiers -#---------------------------------------------------------------------------# + +# ---------------------------------------------------------------------------# +# Exported Identifiers +# ---------------------------------------------------------------------------# __all__ = ["BinaryPayloadBuilder", "BinaryPayloadDecoder"] diff --git a/pymodbus/pdu.py b/pymodbus/pdu.py index 7a7450e29..71a87c7d9 100644 --- a/pymodbus/pdu.py +++ b/pymodbus/pdu.py @@ -1,4 +1,4 @@ -""" Contains base classes for modbus request/response/error packets. """ +"""Contains base classes for modbus request/response/error packets.""" import logging import struct @@ -17,7 +17,7 @@ # Base PDU's # --------------------------------------------------------------------------- # class ModbusPDU: - """ Base class for all Modbus messages + """Base class for all Modbus messages. .. attribute:: transaction_id @@ -51,22 +51,22 @@ class ModbusPDU: """ def __init__(self, **kwargs): - """ Initializes the base data for a modbus request """ + """Initialize the base data for a modbus request.""" self.transaction_id = kwargs.get('transaction', Defaults.TransactionId) self.protocol_id = kwargs.get('protocol', Defaults.ProtocolId) self.unit_id = kwargs.get('unit', Defaults.UnitId) self.skip_encode = kwargs.get('skip_encode', False) self.check = 0x0000 - def encode(self): # pylint: disable=no-self-use - """ Encodes the message + def encode(self): # pylint: disable=no-self-use + """Encode the message. :raises: A not implemented exception """ raise NotImplementedException() - def decode(self, data): # pylint: disable=no-self-use - """ Decodes data part of the message. + def decode(self, data): # pylint: disable=no-self-use + """Decode data part of the message. :param data: is a string object :raises: A not implemented exception @@ -74,8 +74,8 @@ def decode(self, data): # pylint: disable=no-self-use raise NotImplementedException() @classmethod - def calculateRtuFrameSize(cls, buffer): #NOSONAR pylint: disable=invalid-name - """ Calculates the size of a PDU. + def calculateRtuFrameSize(cls, buffer): # NOSONAR pylint: disable=invalid-name + """Calculate the size of a PDU. :param buffer: A buffer containing the data that have been received. :returns: The number of bytes in the PDU. @@ -89,25 +89,25 @@ def calculateRtuFrameSize(cls, buffer): #NOSONAR pylint: disable=invalid-name class ModbusRequest(ModbusPDU): - """ Base class for a modbus request PDU """ + """Base class for a modbus request PDU.""" def __init__(self, **kwargs): - """ Proxy to the lower level initializer """ + """Proxy to the lower level initializer.""" ModbusPDU.__init__(self, **kwargs) - def doException(self, exception): # pylint: disable=invalid-name - """ Builds an error response based on the function + def doException(self, exception): # pylint: disable=invalid-name + """Build an error response based on the function. :param exception: The exception to return :raises: An exception response """ - exc = ExceptionResponse(self.function_code, exception) # pylint: disable=no-member + exc = ExceptionResponse(self.function_code, exception) # pylint: disable=no-member _logger.error(exc) return exc class ModbusResponse(ModbusPDU): - """ Base class for a modbus response PDU + """Base class for a modbus response PDU. .. attribute:: should_respond @@ -123,49 +123,49 @@ class ModbusResponse(ModbusPDU): should_respond = True def __init__(self, **kwargs): - """ Proxy to the lower level initializer """ + """Proxy the lower level initializer.""" ModbusPDU.__init__(self, **kwargs) - def isError(self): # pylint: disable=invalid-name - """Checks if the error is a success or failure""" - return self.function_code > 0x80 # pylint: disable=no-member + def isError(self): # pylint: disable=invalid-name + """Check if the error is a success or failure.""" + return self.function_code > 0x80 # pylint: disable=no-member # --------------------------------------------------------------------------- # # Exception PDU's # --------------------------------------------------------------------------- # -class ModbusExceptions(Singleton): # pylint: disable=too-few-public-methods - """ An enumeration of the valid modbus exceptions. """ - - IllegalFunction = 0x01 - IllegalAddress = 0x02 - IllegalValue = 0x03 - SlaveFailure = 0x04 - Acknowledge = 0x05 - SlaveBusy = 0x06 - MemoryParityError = 0x08 - GatewayPathUnavailable = 0x0A - GatewayNoResponse = 0x0B +class ModbusExceptions(Singleton): # pylint: disable=too-few-public-methods + """An enumeration of the valid modbus exceptions.""" + + IllegalFunction = 0x01 + IllegalAddress = 0x02 + IllegalValue = 0x03 + SlaveFailure = 0x04 + Acknowledge = 0x05 + SlaveBusy = 0x06 + MemoryParityError = 0x08 + GatewayPathUnavailable = 0x0A + GatewayNoResponse = 0x0B @classmethod def decode(cls, code): - """ Given an error code, translate it to a - string error name. + """Give an error code, translate it to a string error name. :param code: The code number to translate """ values = dict((v, k) for k, v in iter(cls.__dict__.items()) - if not k.startswith('__') and not callable(v)) + if not k.startswith('__') and not callable(v)) return values.get(code, None) class ExceptionResponse(ModbusResponse): - """ Base class for a modbus exception PDU """ + """Base class for a modbus exception PDU.""" + ExceptionOffset = 0x80 _rtu_frame_size = 5 def __init__(self, function_code, exception_code=None, **kwargs): - """ Initializes the modbus exception response + """Initialize the modbus exception response. :param function_code: The function to build an exception response for :param exception_code: The specific modbus exception to return @@ -176,40 +176,42 @@ def __init__(self, function_code, exception_code=None, **kwargs): self.exception_code = exception_code def encode(self): - """ Encodes a modbus exception response + """Encode a modbus exception response. :returns: The encoded exception packet """ return struct.pack('>B', self.exception_code) def decode(self, data): - """ Decodes a modbus exception response + """Decode a modbus exception response. :param data: The packet data to decode """ self.exception_code = int(data[0]) def __str__(self): - """ Builds a representation of an exception response + """Build a representation of an exception response. :returns: The string representation of an exception response """ message = ModbusExceptions.decode(self.exception_code) parameters = (self.function_code, self.original_code, message) - return "Exception Response(%d, %d, %s)" % parameters # pylint: disable=consider-using-f-string + return "Exception Response(%d, %d, %s)" % parameters # pylint: disable=consider-using-f-string class IllegalFunctionRequest(ModbusRequest): - """ Defines the Modbus slave exception type 'Illegal Function' + """Define the Modbus slave exception type 'Illegal Function'. + This exception code is returned if the slave:: - does not implement the function code **or** - is not in a state that allows it to process the function """ + ErrorCode = 1 def __init__(self, function_code, **kwargs): - """ Initializes a IllegalFunctionRequest + """Initialize a IllegalFunctionRequest. :param function_code: The function we are erroring on """ @@ -217,13 +219,13 @@ def __init__(self, function_code, **kwargs): self.function_code = function_code def decode(self, data): - """ This is here so this failure will run correctly + """Decode so this failure will run correctly. :param data: Not used """ - def execute(self, context): # pylint: disable=unused-argument - """ Builds an illegal function request error response + def execute(self, context): # pylint: disable=unused-argument + """Build an illegal function request error response. :param context: The current context for the message :returns: The error response packet @@ -237,4 +239,4 @@ def execute(self, context): # pylint: disable=unused-argument __all__ = [ 'ModbusRequest', 'ModbusResponse', 'ModbusExceptions', - 'ExceptionResponse', 'IllegalFunctionRequest',] + 'ExceptionResponse', 'IllegalFunctionRequest', ] diff --git a/pymodbus/register_read_message.py b/pymodbus/register_read_message.py index f78119e46..a22962dd6 100644 --- a/pymodbus/register_read_message.py +++ b/pymodbus/register_read_message.py @@ -1,6 +1,4 @@ -""" Register Reading Request/Response ---------------------------------- -""" +"""Register Reading Request/Response.""" import struct from pymodbus.pdu import ModbusRequest from pymodbus.pdu import ModbusResponse @@ -8,11 +6,12 @@ class ReadRegistersRequestBase(ModbusRequest): - """ Base class for reading a modbus register. """ + """Base class for reading a modbus register.""" + _rtu_frame_size = 8 def __init__(self, address, count, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param address: The address to start the read from :param count: The number of registers to read @@ -22,25 +21,28 @@ def __init__(self, address, count, **kwargs): self.count = count def encode(self): - """ Encodes the request packet + """Encode the request packet. :return: The encoded packet """ return struct.pack('>HH', self.address, self.count) def decode(self, data): - """ Decode a register request packet + """Decode a register request packet. :param data: The request to decode """ self.address, self.count = struct.unpack('>HH', data) def get_response_pdu_size(self): - """ Func_code (1 byte) + Byte Count(1 byte) + 2 * Quantity of Coils (n Bytes). """ + """Get response pdu size. + + Func_code (1 byte) + Byte Count(1 byte) + 2 * Quantity of Coils (n Bytes). + """ return 1 + 1 + 2 * self.count def __str__(self): - """ Returns a string representation of the instance + """Return a string representation of the instance. :returns: A string representation of the instance """ @@ -48,12 +50,12 @@ def __str__(self): class ReadRegistersResponseBase(ModbusResponse): - """ Base class for responding to a modbus register read. """ + """Base class for responding to a modbus register read.""" _rtu_byte_count_pos = 2 def __init__(self, values, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param values: The values to write to """ @@ -61,7 +63,7 @@ def __init__(self, values, **kwargs): self.registers = values or [] def encode(self): - """ Encodes the response packet + """Encode the response packet. :returns: The encoded packet """ @@ -71,7 +73,7 @@ def encode(self): return result def decode(self, data): - """ Decode a register response packet + """Decode a register response packet. :param data: The request to decode """ @@ -80,8 +82,8 @@ def decode(self, data): for i in range(1, byte_count + 1, 2): self.registers.append(struct.unpack('>H', data[i:i + 2])[0]) - def getRegister(self, index): # pylint: disable=(invalid-name - """ Get the requested register + def getRegister(self, index): # pylint: disable=(invalid-name + """Get the requested register. :param index: The indexed register to retrieve :returns: The request register @@ -89,7 +91,7 @@ def getRegister(self, index): # pylint: disable=(invalid-name return self.registers[index] def __str__(self): - """ Returns a string representation of the instance + """Return a string representation of the instance. :returns: A string representation of the instance """ @@ -97,16 +99,19 @@ def __str__(self): class ReadHoldingRegistersRequest(ReadRegistersRequestBase): - """ This function code is used to read the contents of a contiguous block + """Read holding registers. + + This function code is used to read the contents of a contiguous block of holding registers in a remote device. The Request PDU specifies the starting register address and the number of registers. In the PDU Registers are addressed starting at zero. Therefore registers numbered 1-16 are addressed as 0-15. """ + function_code = 3 def __init__(self, address=None, count=None, **kwargs): - """ Initializes a new instance of the request + """Initialize a new instance of the request. :param address: The starting address to read from :param count: The number of registers to read from address @@ -114,7 +119,7 @@ def __init__(self, address=None, count=None, **kwargs): ReadRegistersRequestBase.__init__(self, address, count, **kwargs) def execute(self, context): - """ Run a read holding request against a datastore + """Run a read holding request against a datastore. :param context: The datastore to request from :returns: An initialized response, exception message otherwise @@ -128,16 +133,19 @@ def execute(self, context): class ReadHoldingRegistersResponse(ReadRegistersResponseBase): - """ This function code is used to read the contents of a contiguous block + """Read holding registers. + + This function code is used to read the contents of a contiguous block of holding registers in a remote device. The Request PDU specifies the starting register address and the number of registers. In the PDU Registers are addressed starting at zero. Therefore registers numbered 1-16 are addressed as 0-15. """ + function_code = 3 def __init__(self, values=None, **kwargs): - """ Initializes a new response instance + """Initialize a new response instance. :param values: The resulting register values """ @@ -145,16 +153,19 @@ def __init__(self, values=None, **kwargs): class ReadInputRegistersRequest(ReadRegistersRequestBase): - """ This function code is used to read from 1 to approx. 125 contiguous + """Read input registers. + + This function code is used to read from 1 to approx. 125 contiguous input registers in a remote device. The Request PDU specifies the starting register address and the number of registers. In the PDU Registers are addressed starting at zero. Therefore input registers numbered 1-16 are addressed as 0-15. """ + function_code = 4 def __init__(self, address=None, count=None, **kwargs): - """ Initializes a new instance of the request + """Initialize a new instance of the request. :param address: The starting address to read from :param count: The number of registers to read from address @@ -162,7 +173,7 @@ def __init__(self, address=None, count=None, **kwargs): ReadRegistersRequestBase.__init__(self, address, count, **kwargs) def execute(self, context): - """ Run a read input request against a datastore + """Run a read input request against a datastore. :param context: The datastore to request from :returns: An initialized response, exception message otherwise @@ -176,16 +187,19 @@ def execute(self, context): class ReadInputRegistersResponse(ReadRegistersResponseBase): - """ This function code is used to read from 1 to approx. 125 contiguous + """Read/write input registers. + + This function code is used to read from 1 to approx. 125 contiguous input registers in a remote device. The Request PDU specifies the starting register address and the number of registers. In the PDU Registers are addressed starting at zero. Therefore input registers numbered 1-16 are addressed as 0-15. """ + function_code = 4 def __init__(self, values=None, **kwargs): - """ Initializes a new response instance + """Initialize a new response instance. :param values: The resulting register values """ @@ -193,7 +207,9 @@ def __init__(self, values=None, **kwargs): class ReadWriteMultipleRegistersRequest(ModbusRequest): - """ This function code performs a combination of one read operation and one + """Read/write multiple registers. + + This function code performs a combination of one read operation and one write operation in a single MODBUS transaction. The write operation is performed before the read. @@ -205,11 +221,12 @@ class ReadWriteMultipleRegistersRequest(ModbusRequest): registers, and the data to be written. The byte count specifies the number of bytes to follow in the write data field." """ + function_code = 23 _rtu_byte_count_pos = 10 def __init__(self, **kwargs): - """ Initializes a new request message + """Initialize a new request message. :param read_address: The address to start reading from :param read_count: The number of registers to read from address @@ -217,9 +234,9 @@ def __init__(self, **kwargs): :param write_registers: The registers to write to the specified address """ ModbusRequest.__init__(self, **kwargs) - self.read_address = kwargs.get('read_address', 0x00) - self.read_count = kwargs.get('read_count', 0) - self.write_address = kwargs.get('write_address', 0x00) + self.read_address = kwargs.get('read_address', 0x00) + self.read_count = kwargs.get('read_count', 0) + self.write_address = kwargs.get('write_address', 0x00) self.write_registers = kwargs.get('write_registers', None) if not hasattr(self.write_registers, '__iter__'): self.write_registers = [self.write_registers] @@ -227,32 +244,32 @@ def __init__(self, **kwargs): self.write_byte_count = self.write_count * 2 def encode(self): - """ Encodes the request packet + """Encode the request packet. :returns: The encoded packet """ result = struct.pack('>HHHHB', - self.read_address, self.read_count, \ - self.write_address, self.write_count, self.write_byte_count) + self.read_address, self.read_count, + self.write_address, self.write_count, self.write_byte_count) for register in self.write_registers: result += struct.pack('>H', register) return result def decode(self, data): - """ Decode the register request packet + """Decode the register request packet. :param data: The request to decode """ - self.read_address, self.read_count, \ - self.write_address, self.write_count, \ - self.write_byte_count = struct.unpack('>HHHHB', data[:9]) - self.write_registers = [] + self.read_address, self.read_count, \ + self.write_address, self.write_count, \ + self.write_byte_count = struct.unpack('>HHHHB', data[:9]) + self.write_registers = [] for i in range(9, self.write_byte_count + 9, 2): register = struct.unpack('>H', data[i:i + 2])[0] self.write_registers.append(register) def execute(self, context): - """ Run a write single register request against a datastore + """Run a write single register request against a datastore. :param context: The datastore to request from :returns: An initialized response, exception message otherwise @@ -276,31 +293,36 @@ def execute(self, context): return ReadWriteMultipleRegistersResponse(registers) def get_response_pdu_size(self): - """ Func_code (1 byte) + Byte Count(1 byte) + 2 * Quantity of Coils (n Bytes) + """Get response pdu size. + + Func_code (1 byte) + Byte Count(1 byte) + 2 * Quantity of Coils (n Bytes) :return: """ return 1 + 1 + 2 * self.read_count def __str__(self): - """ Returns a string representation of the instance + """Return a string representation of the instance. :returns: A string representation of the instance """ params = (self.read_address, self.read_count, self.write_address, self.write_count) - return "ReadWriteNRegisterRequest R(%d,%d) W(%d,%d)" % params # pylint: disable=consider-using-f-string + return "ReadWriteNRegisterRequest R(%d,%d) W(%d,%d)" % params # pylint: disable=consider-using-f-string class ReadWriteMultipleRegistersResponse(ModbusResponse): - """ The normal response contains the data from the group of registers that + """Read/write multiple registers. + + The normal response contains the data from the group of registers that were read. The byte count field specifies the quantity of bytes to follow in the read data field. """ + function_code = 23 _rtu_byte_count_pos = 2 def __init__(self, values=None, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param values: The register values to write """ @@ -308,17 +330,17 @@ def __init__(self, values=None, **kwargs): self.registers = values or [] def encode(self): - """ Encodes the response packet + """Encode the response packet. :returns: The encoded packet """ - result = struct.pack('>B',len(self.registers) * 2) + result = struct.pack('>B', len(self.registers) * 2) for register in self.registers: result += struct.pack('>H', register) return result def decode(self, data): - """ Decode the register response packet + """Decode the register response packet. :param data: The response to decode """ @@ -327,15 +349,16 @@ def decode(self, data): self.registers.append(struct.unpack('>H', data[i:i + 2])[0]) def __str__(self): - """ Returns a string representation of the instance + """Return a string representation of the instance. :returns: A string representation of the instance """ return f"ReadWriteNRegisterResponse ({len(self.registers)})" -#---------------------------------------------------------------------------# -# Exported symbols -#---------------------------------------------------------------------------# + +# ---------------------------------------------------------------------------# +# Exported symbols +# ---------------------------------------------------------------------------# __all__ = [ "ReadHoldingRegistersRequest", "ReadHoldingRegistersResponse", "ReadInputRegistersRequest", "ReadInputRegistersResponse", diff --git a/pymodbus/register_write_message.py b/pymodbus/register_write_message.py index 30db39076..9ab59a222 100644 --- a/pymodbus/register_write_message.py +++ b/pymodbus/register_write_message.py @@ -1,6 +1,4 @@ -""" Register Writing Request/Response Messages -------------------------------------------- -""" +"""Register Writing Request/Response Messages.""" import struct from pymodbus.pdu import ModbusRequest from pymodbus.pdu import ModbusResponse @@ -8,18 +6,18 @@ class WriteSingleRegisterRequest(ModbusRequest): - """ This function code is used to write a single holding register in a - remote device. + """This function code is used to write a single holding register in a remote device. The Request PDU specifies the address of the register to be written. Registers are addressed starting at zero. Therefore register numbered 1 is addressed as 0. """ + function_code = 6 _rtu_frame_size = 8 def __init__(self, address=None, value=None, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param address: The address to start writing add :param value: The values to write @@ -29,7 +27,7 @@ def __init__(self, address=None, value=None, **kwargs): self.value = value def encode(self): - """ Encode a write single register packet packet request + """Encode a write single register packet packet request. :returns: The encoded packet """ @@ -41,14 +39,14 @@ def encode(self): return packet def decode(self, data): - """ Decode a write single register packet packet request + """Decode a write single register packet packet request. :param data: The request to decode """ self.address, self.value = struct.unpack('>HH', data) def execute(self, context): - """ Run a write single register request against a datastore + """Run a write single register request against a datastore. :param context: The datastore to request from :returns: An initialized response, exception message otherwise @@ -62,14 +60,16 @@ def execute(self, context): values = context.getValues(self.function_code, self.address, 1) return WriteSingleRegisterResponse(self.address, values[0]) - def get_response_pdu_size(self): # pylint: disable=no-self-use - """ Func_code (1 byte) + Register Address(2 byte) + Register Value (2 bytes) + def get_response_pdu_size(self): # pylint: disable=no-self-use + """Get response pdu size. + + Func_code (1 byte) + Register Address(2 byte) + Register Value (2 bytes) :return: """ return 1 + 2 + 2 def __str__(self): - """ Returns a string representation of the instance + """Return a string representation of the instance. :returns: A string representation of the instance """ @@ -77,14 +77,16 @@ def __str__(self): class WriteSingleRegisterResponse(ModbusResponse): - """ The normal response is an echo of the request, returned after the - register contents have been written. + """The normal response is an echo of the request. + + Returned after the register contents have been written. """ + function_code = 6 _rtu_frame_size = 8 def __init__(self, address=None, value=None, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param address: The address to start writing add :param value: The values to write @@ -94,44 +96,46 @@ def __init__(self, address=None, value=None, **kwargs): self.value = value def encode(self): - """ Encode a write single register packet packet request + """Encode a write single register packet packet request. :returns: The encoded packet """ return struct.pack('>HH', self.address, self.value) def decode(self, data): - """ Decode a write single register packet packet request + """Decode a write single register packet packet request. :param data: The request to decode """ self.address, self.value = struct.unpack('>HH', data) def __str__(self): - """ Returns a string representation of the instance + """Return a string representation of the instance. :returns: A string representation of the instance """ params = (self.address, self.value) - return "WriteRegisterResponse %d => %d" % params # pylint: disable=consider-using-f-string + return "WriteRegisterResponse %d => %d" % params # pylint: disable=consider-using-f-string -#---------------------------------------------------------------------------# -# Write Multiple Registers -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Write Multiple Registers +# ---------------------------------------------------------------------------# class WriteMultipleRegistersRequest(ModbusRequest): - """ This function code is used to write a block of contiguous registers (1 - to approx. 120 registers) in a remote device. + """This function code is used to write a block. + + Of contiguous registers (1 to approx. 120 registers) in a remote device. The requested written values are specified in the request data field. Data is packed as two bytes per register. """ + function_code = 16 _rtu_byte_count_pos = 6 - _pdu_length = 5 #func + adress1 + adress2 + outputQuant1 + outputQuant2 + _pdu_length = 5 # func + adress1 + adress2 + outputQuant1 + outputQuant2 def __init__(self, address=None, values=None, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param address: The address to start writing to :param values: The values to write @@ -147,7 +151,7 @@ def __init__(self, address=None, values=None, **kwargs): self.byte_count = self.count * 2 def encode(self): - """ Encode a write single register packet packet request + """Encode a write single register packet packet request. :returns: The encoded packet """ @@ -161,18 +165,18 @@ def encode(self): return packet def decode(self, data): - """ Decode a write single register packet packet request + """Decode a write single register packet packet request. :param data: The request to decode """ self.address, self.count, \ - self.byte_count = struct.unpack('>HHB', data[:5]) + self.byte_count = struct.unpack('>HHB', data[:5]) self.values = [] # reset for idx in range(5, (self.count * 2) + 5, 2): self.values.append(struct.unpack('>H', data[idx:idx + 2])[0]) def execute(self, context): - """ Run a write single register request against a datastore + """Run a write single register request against a datastore. :param context: The datastore to request from :returns: An initialized response, exception message otherwise @@ -187,30 +191,34 @@ def execute(self, context): context.setValues(self.function_code, self.address, self.values) return WriteMultipleRegistersResponse(self.address, self.count) - def get_response_pdu_size(self): # pylint: disable=no-self-use - """ Func_code (1 byte) + Starting Address (2 byte) + Quantity of Reggisters (2 Bytes) + def get_response_pdu_size(self): # pylint: disable=no-self-use + """Get response pdu size. + + Func_code (1 byte) + Starting Address (2 byte) + Quantity of Reggisters (2 Bytes) :return: """ return 1 + 2 + 2 def __str__(self): - """ Returns a string representation of the instance + """Return a string representation of the instance. :returns: A string representation of the instance """ params = (self.address, self.count) - return "WriteMultipleRegisterRequest %d => %d" % params # pylint: disable=consider-using-f-string + return "WriteMultipleRegisterRequest %d => %d" % params # pylint: disable=consider-using-f-string class WriteMultipleRegistersResponse(ModbusResponse): - """ The normal response returns the function code, starting address, and - quantity of registers written. + """The normal response returns the function code. + + Starting address, and quantity of registers written. """ + function_code = 16 _rtu_frame_size = 8 def __init__(self, address=None, count=None, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param address: The address to start writing to :param count: The number of registers to write to @@ -220,39 +228,42 @@ def __init__(self, address=None, count=None, **kwargs): self.count = count def encode(self): - """ Encode a write single register packet packet request + """Encode a write single register packet packet request. :returns: The encoded packet """ return struct.pack('>HH', self.address, self.count) def decode(self, data): - """ Decode a write single register packet packet request + """Decode a write single register packet packet request. :param data: The request to decode """ self.address, self.count = struct.unpack('>HH', data) def __str__(self): - """ Returns a string representation of the instance + """Return a string representation of the instance. :returns: A string representation of the instance """ params = (self.address, self.count) - return "WriteMultipleRegisterResponse (%d,%d)" % params # pylint: disable=consider-using-f-string + return "WriteMultipleRegisterResponse (%d,%d)" % params # pylint: disable=consider-using-f-string + class MaskWriteRegisterRequest(ModbusRequest): - """ This function code is used to modify the contents of a specified holding - register using a combination of an AND mask, an OR mask, and the - register's current contents. The function can be used to set or clear - individual bits in the register. + """This function code is used to modify the contents. + + Of a specified holding register using a combination of an AND mask, + an OR mask, and the register's current contents. + The function can be used to set or clear individual bits in the register. """ + function_code = 0x16 _rtu_frame_size = 10 def __init__(self, address=0x0000, and_mask=0xffff, or_mask=0x0000, **kwargs): - """ Initializes a new instance + """Initialize a new instance. :param address: The mask pointer address (0x0000 to 0xffff) :param and_mask: The and bitmask to apply to the register address @@ -264,7 +275,7 @@ def __init__(self, address=0x0000, and_mask=0xffff, or_mask=0x0000, self.or_mask = or_mask def encode(self): - """ Encodes the request packet + """Encode the request packet. :returns: The byte encoded packet """ @@ -272,7 +283,7 @@ def encode(self): self.or_mask) def decode(self, data): - """ Decodes the incoming request + """Decode the incoming request. :param data: The data to decode into the address """ @@ -280,7 +291,7 @@ def decode(self, data): data) def execute(self, context): - """ Run a mask write register request against the store + """Run a mask write register request against the store. :param context: The datastore to request from :returns: The populated response @@ -299,15 +310,17 @@ def execute(self, context): class MaskWriteRegisterResponse(ModbusResponse): - """ The normal response is an echo of the request. The response is returned - after the register has been written. + """The normal response is an echo of the request. + + The response is returned after the register has been written. """ + function_code = 0x16 _rtu_frame_size = 10 def __init__(self, address=0x0000, and_mask=0xffff, or_mask=0x0000, **kwargs): - """ Initializes a new instance + """Initialize new instance. :param address: The mask pointer address (0x0000 to 0xffff) :param and_mask: The and bitmask applied to the register address @@ -319,7 +332,7 @@ def __init__(self, address=0x0000, and_mask=0xffff, or_mask=0x0000, self.or_mask = or_mask def encode(self): - """ Encodes the response + """Encode the response. :returns: The byte encoded message """ @@ -327,7 +340,7 @@ def encode(self): self.or_mask) def decode(self, data): - """ Decodes a the response + """Decode a the response. :param data: The packet data to decode """ @@ -335,9 +348,9 @@ def decode(self, data): data) -#---------------------------------------------------------------------------# -# Exported symbols -#---------------------------------------------------------------------------# +# ---------------------------------------------------------------------------# +# Exported symbols +# ---------------------------------------------------------------------------# __all__ = [ "WriteSingleRegisterRequest", "WriteSingleRegisterResponse", "WriteMultipleRegistersRequest", "WriteMultipleRegistersResponse", diff --git a/pymodbus/repl/__init__.py b/pymodbus/repl/__init__.py index ab7b3ce74..fa477a7ee 100644 --- a/pymodbus/repl/__init__.py +++ b/pymodbus/repl/__init__.py @@ -1,6 +1,5 @@ -""" Pymodbus REPL Module. +"""Pymodbus REPL Module. Copyright (c) 2018 Riptide IO, Inc. All Rights Reserved. - """ from __future__ import absolute_import, unicode_literals diff --git a/pymodbus/repl/client/__init__.py b/pymodbus/repl/client/__init__.py index 8feb11bcc..756fce8a2 100644 --- a/pymodbus/repl/client/__init__.py +++ b/pymodbus/repl/client/__init__.py @@ -1,3 +1,5 @@ -""" Copyright (c) 2020 by RiptideIO +"""Repl client. + +Copyright (c) 2020 by RiptideIO All rights reserved. """ diff --git a/pymodbus/repl/client/completer.py b/pymodbus/repl/client/completer.py index 3d9a2058f..0138717ff 100644 --- a/pymodbus/repl/client/completer.py +++ b/pymodbus/repl/client/completer.py @@ -1,4 +1,4 @@ -""" Command Completion for pymodbus REPL. +"""Command Completion for pymodbus REPL. Copyright (c) 2018 Riptide IO, Inc. All Rights Reserved. @@ -15,7 +15,7 @@ def has_selected_completion(): """Check for selected completion.""" complete_state = get_app().current_buffer.complete_state - return (complete_state is not None and + return (complete_state is not None and # noqa W504 complete_state.current_completion is not None) @@ -28,10 +28,10 @@ def has_selected_completion(): class CmdCompleter(Completer): - """ Completer for Pymodbus REPL. """ + """Completer for Pymodbus REPL.""" def __init__(self, client=None, commands=None, ignore_case=True): - """ Initialize. + """Initialize. :param client: Modbus Client :param commands: Commands to be added for Completion (list) @@ -44,16 +44,16 @@ def __init__(self, client=None, commands=None, ignore_case=True): @property def commands(self): - """ Return commands. """ + """Return commands.""" return self._commands @property def command_names(self): - """ Return command names. """ + """Return command names.""" return self._commands.keys() - def completing_command(self, words, word_before_cursor): # pylint: disable=no-self-use - """ Determine if we are dealing with supported command. + def completing_command(self, words, word_before_cursor): # pylint: disable=no-self-use + """Determine if we are dealing with supported command. :param words: Input text broken in to word tokens. :param word_before_cursor: The current word before the cursor, \ @@ -62,8 +62,8 @@ def completing_command(self, words, word_before_cursor): # pylint: disable=no-se """ return len(words) == 1 and len(word_before_cursor) - def completing_arg(self, words, word_before_cursor): # pylint: disable=no-self-use - """ Determine if we are currently completing an argument. + def completing_arg(self, words, word_before_cursor): # pylint: disable=no-self-use + """Determine if we are currently completing an argument. :param words: The input text broken into word tokens. :param word_before_cursor: The current word before the cursor, \ @@ -72,8 +72,8 @@ def completing_arg(self, words, word_before_cursor): # pylint: disable=no-self-u """ return len(words) > 1 and len(word_before_cursor) - def arg_completions(self, words, word_before_cursor): # pylint: disable=unused-argument - """ Generates arguments completions based on the input. + def arg_completions(self, words, word_before_cursor): # pylint: disable=unused-argument + """Generate arguments completions based on the input. :param words: The input text broken into word tokens. :param word_before_cursor: The current word before the cursor, \ @@ -85,13 +85,13 @@ def arg_completions(self, words, word_before_cursor): # pylint: disable=unused-a return cmd if cmd else None def _get_completions(self, word, word_before_cursor): - """ Internal get completions. """ + """Get completions.""" if self.ignore_case: word_before_cursor = word_before_cursor.lower() return self.word_matches(word, word_before_cursor) def word_matches(self, word, word_before_cursor): - """ Match the word and word before cursor + """Match the word and word before cursor. :param words: The input text broken into word tokens. :param word_before_cursor: The current word before the cursor, \ @@ -104,7 +104,7 @@ def word_matches(self, word, word_before_cursor): return word.startswith(word_before_cursor) def get_completions(self, document, complete_event): - """ Get completions for the current scope. + """Get completions for the current scope. :param document: An instance of `prompt_toolkit.Document`. :param complete_event: (Unused). diff --git a/pymodbus/repl/client/helper.py b/pymodbus/repl/client/helper.py index 1d15aad05..5ecab1575 100644 --- a/pymodbus/repl/client/helper.py +++ b/pymodbus/repl/client/helper.py @@ -1,4 +1,4 @@ -""" Helper Module for REPL actions. +"""Helper Module for REPL actions. Copyright (c) 2018 Riptide IO, Inc. All Rights Reserved. @@ -54,9 +54,10 @@ class Command: - """ Class representing Commands to be consumed by Completer. """ + """Class representing Commands to be consumed by Completer.""" + def __init__(self, name, signature, doc, unit=False): - """ Initialize + """Initialize. :param name: Name of the command :param signature: inspect object @@ -77,7 +78,7 @@ def __init__(self, name, signature, doc, unit=False): self.args.update(**DEFAULT_KWARGS) def _create_help(self): - """ Internal create help. """ + """Create help.""" doc = filter(lambda d: d, self.doc) cmd_help = list(filter( lambda x: not x.startswith(":param") and not x.startswith( @@ -85,7 +86,7 @@ def _create_help(self): return " ".join(cmd_help).strip() def _create_arg_help(self): - """ Internal create arg help. """ + """Create arg help.""" param_dict = {} params = list(filter(lambda d: d.strip().startswith(":param"), self.doc)) @@ -95,7 +96,7 @@ def _create_arg_help(self): return param_dict def create_completion(self): - """ Create command completion meta data. + """Create command completion meta data. :return: """ @@ -116,14 +117,14 @@ def _create(entry, default): return words def get_completion(self): - """ Gets a list of completions. + """Get a list of completions. :return: """ return self.args.keys() def get_meta(self, cmd): - """ Get Meta info of a given command. + """Get Meta info of a given command. :param cmd: Name of command. :return: Dict containing meta info. @@ -133,13 +134,14 @@ def get_meta(self, cmd): return cmd, self.param_help.get(cmd, '') def __str__(self): + """Return string representation.""" if self.doc: - return "Command {:>50}{:<20}".format(self.name, self.doc) # pylint: disable=consider-using-f-string + return "Command {:>50}{:<20}".format(self.name, self.doc) # pylint: disable=consider-using-f-string return f"Command {self.name}" def _get_requests(members): - """ Internal get requests. """ + """Get requests.""" commands = list(filter(lambda x: (x[0] not in EXCLUDE and x[0] not in CLIENT_METHODS and callable(x[1])), @@ -154,9 +156,8 @@ def _get_requests(members): def _get_client_methods(members): - """ Internal get client methods. """ - commands = list(filter(lambda x: (x[0] not in EXCLUDE - and x[0] in CLIENT_METHODS), + """Get client methods.""" + commands = list(filter(lambda x: (x[0] not in EXCLUDE and x[0] in CLIENT_METHODS), members)) commands = { "client.{c[0]}": @@ -168,22 +169,22 @@ def _get_client_methods(members): def _get_client_properties(members): - """ Internal get client properties. """ - global CLIENT_ATTRIBUTES # pylint: disable=global-variable-not-assigned + """Get client properties.""" + global CLIENT_ATTRIBUTES # pylint: disable=global-variable-not-assigned commands = list(filter(lambda x: not callable(x[1]), members)) commands = { f"client.{c[0]}": Command(f"client.{c[0]}", None, "Read Only!", unit=False) - for c in commands if (not c[0].startswith("_") - and isinstance(c[1], (str, int, float))) + for c in commands if (not c[0].startswith("_") and isinstance(c[1], (str, int, float))) } CLIENT_ATTRIBUTES.extend(list(commands.keys())) return commands def get_commands(client): - """ Helper method to retrieve all required methods and attributes of a client \ - object and convert it to commands. + """Retrieve all required methods and attributes. + + Of a client object and convert it to commands. :param client: Modbus Client object. :return: @@ -199,8 +200,7 @@ def get_commands(client): f"result.{c[0]}": Command(f"result.{c[0]}", argspec(c[1]), inspect.getdoc(c[1])) - for c in result_commands if (not c[0].startswith("_") - and c[0] != "print_result") + for c in result_commands if (not c[0].startswith("_") and c[0] != "print_result") } commands.update(requests) commands.update(client_methods) @@ -210,12 +210,14 @@ def get_commands(client): class Result: - """ Represent result command. """ + """Represent result command.""" + function_code = None data = None def __init__(self, result): - """ Initialize. + """Initialize. + :param result: Response of a modbus command. """ if isinstance(result, dict): # Modbus response @@ -225,7 +227,7 @@ def __init__(self, result): self.data = result def decode(self, formatters, byte_order='big', word_order='big'): - """ Decode the register response to known formatters. + """Decode the register response to known formatters. :param formatters: int8/16/32/64, uint8/16/32/64, float32/64 :param byte_order: little/big @@ -258,14 +260,14 @@ def decode(self, formatters, byte_order='big', word_order='big'): self.print_result(decoded) def raw(self): - """ Return raw result dict. + """Return raw result dict. :return: """ self.print_result() def _process_dict(self, use_dict): - """ Internal process dict. """ + """Process dict.""" new_dict = OrderedDict() for k, v_item in use_dict.items(): if isinstance(v_item, bytes): @@ -274,12 +276,12 @@ def _process_dict(self, use_dict): v_item = self._process_dict(v_item) elif isinstance(v_item, (list, tuple)): v_item = [v1.decode('utf-8') if isinstance(v1, bytes) else v1 - for v1 in v_item ] + for v1 in v_item] new_dict[k] = v_item return new_dict def print_result(self, data=None): - """ Prettu print result object. + """Print result object pretty. :param data: Data to be printed. :return: diff --git a/pymodbus/repl/client/main.py b/pymodbus/repl/client/main.py index 8ba26aa3c..a01d6c756 100644 --- a/pymodbus/repl/client/main.py +++ b/pymodbus/repl/client/main.py @@ -1,4 +1,4 @@ -""" Pymodbus REPL Entry point. +"""Pymodbus REPL Entry point. Copyright (c) 2018 Riptide IO, Inc. All Rights Reserved. @@ -40,15 +40,15 @@ click.disable_unicode_literals_warning = True TITLE = ( -'----------------------------------------------------------------------------' -'__________ _____ .___ __________ .__ ' -'\______ \___.__. / \ ____ __| _/ \______ \ ____ ______ | | ' # pylint: disable=anomalous-backslash-in-string -' | ___< | |/ \ / \ / _ \ / __ | | _// __ \\\____ \| | ' # pylint: disable=anomalous-backslash-in-string -' | | \___ / Y ( <_> ) /_/ | | | \ ___/| |_> > |__' # pylint: disable=anomalous-backslash-in-string -' |____| / ____\____|__ /\____/\____ | /\ |____|_ /\___ > __/|____/' # pylint: disable=anomalous-backslash-in-string -' \/ \/ \/ \/ \/ \/|__|' # pylint: disable=anomalous-backslash-in-string -f' v1.3.0 - {version}' -'----------------------------------------------------------------------------' + r'----------------------------------------------------------------------------' + r'__________ _____ .___ __________ .__ ' + r'\______ \___.__. / \ ____ __| _/ \______ \ ____ ______ | | ' # pylint: disable=C0209 + r' | ___< | |/ \ / \ / _ \ / __ | | _// __ \\\____ \| | ' # pylint: disable=C0209 + r' | | \___ / Y ( <_> ) /_/ | | | \ ___/| |_> > |__' # pylint: disable=C0209 + r' |____| / ____\____|__ /\____/\____ | /\ |____|_ /\___ > __/|____/' # pylint: disable=C0209 + r' \/ \/ \/ \/ \/ \/|__|' # pylint: disable=C0209 + f' v1.3.0 - {version}' + r'----------------------------------------------------------------------------' ) _logger = logging.getLogger(__name__) @@ -62,7 +62,8 @@ def bottom_toolbar(): - """ Console toolbar. + """Do console toolbar. + :return: """ return HTML('Press ' @@ -70,9 +71,10 @@ def bottom_toolbar(): class CaseInsenstiveChoice(click.Choice): - """ Case Insensitive choice for click commands and options. """ + """Do case Insensitive choice for click commands and options.""" + def convert(self, value, param, ctx): - """ Convert args to uppercase for evaluation. """ + """Convert args to uppercase for evaluation.""" if value is None: return None return super().convert( @@ -80,35 +82,38 @@ def convert(self, value, param, ctx): class NumericChoice(click.Choice): - """ Numeric choice for click arguments and options. """ + """Do numeric choice for click arguments and options.""" + def __init__(self, choices, typ): + """Initialize.""" self.typ = typ super().__init__(choices) def convert(self, value, param, ctx): + """Convert.""" # Exact match if value in self.choices: return self.typ(value) if ctx is not None and ctx.token_normalize_func is not None: value = ctx.token_normalize_func(value) - for choice in self.casted_choices: # pylint: disable=no-member + for choice in self.casted_choices: # pylint: disable=no-member if ctx.token_normalize_func(choice) == value: return choice - self.fail('invalid choice: %s. (choose from %s)' % # pylint: disable=consider-using-f-string + self.fail('invalid choice: %s. (choose from %s)' % # pylint: disable=consider-using-f-string (value, ', '.join(self.choices)), param, ctx) return None -def cli(client): #NOSONAR pylint: disable=too-complex - """Client definition.""" +def cli(client): # NOSONAR pylint: disable=too-complex + """Run client definition.""" use_keys = KeyBindings() history_file = os.path.normpath(os.path.expanduser("~/.pymodhis")) @use_keys.add('c-space') def _(event): - """ Initialize autocompletion, or select the next completion. """ + """Initialize autocompletion, or select the next completion.""" buff = event.app.current_buffer if buff.complete_state: buff.complete_next() @@ -117,8 +122,7 @@ def _(event): @use_keys.add('enter', filter=has_selected_completion) def _(event): - """ Makes the enter key work as the tab key only when showing the menu. """ - + """Make the enter key work as the tab key only when showing the menu.""" event.current_buffer.complete_state = None buffer = event.cli.current_buffer buffer.complete_state = None @@ -172,7 +176,7 @@ def _process_args(args, string=True): auto_suggest=AutoSuggestFromHistory()) click.secho(f"{TITLE}", fg='green') result = None - while True: # pylint: disable=too-many-nested-blocks + while True: # pylint: disable=too-many-nested-blocks try: text = session.prompt('> ', complete_while_typing=True) @@ -181,7 +185,7 @@ def _process_args(args, string=True): for cmd, obj in sorted(session.completer.commands.items()): if cmd != 'help': print_formatted_text( - HTML("{:45s}" # pylint: disable=consider-using-f-string + HTML("{:45s}" # pylint: disable=consider-using-f-string "{:100s}" "".format(cmd, obj.help_text))) @@ -236,11 +240,11 @@ def _process_args(args, string=True): @click.pass_context def main(ctx, verbose, broadcast_support, retry_on_empty, retry_on_error, retries, reset_socket): - """Main function.""" + """Run Main.""" if verbose: use_format = ('%(asctime)-15s %(threadName)-15s ' - '%(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s') - logging.basicConfig(format=use_format) #NOSONAR + '%(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s') + logging.basicConfig(format=use_format) # NOSONAR _logger.setLevel(logging.DEBUG) ctx.obj = { "broadcast": broadcast_support, @@ -295,11 +299,11 @@ def tcp(ctx, host, port, framer): help="Modbus RTU port", ) @click.option( - "--baudrate", - help="Modbus RTU serial baudrate to use. Defaults to 9600", - default=9600, - type=int - ) + "--baudrate", + help="Modbus RTU serial baudrate to use. Defaults to 9600", + default=9600, + type=int +) @click.option( "--bytesize", help="Modbus RTU serial Number of data bits. " @@ -358,7 +362,7 @@ def tcp(ctx, host, port, framer): default=2, type=float ) -def serial(ctx, method, port, baudrate, bytesize, parity, stopbits, xonxoff, # pylint: disable=too-many-arguments +def serial(ctx, method, port, baudrate, bytesize, parity, stopbits, xonxoff, # pylint: disable=too-many-arguments rtscts, dsrdtr, timeout, write_timeout): """Define serial communication.""" client = ModbusSerialClient(method=method, @@ -377,4 +381,4 @@ def serial(ctx, method, port, baudrate, bytesize, parity, stopbits, xonxoff, # p if __name__ == "__main__": - main() # pylint: disable=no-value-for-parameter + main() # pylint: disable=no-value-for-parameter diff --git a/pymodbus/repl/client/mclient.py b/pymodbus/repl/client/mclient.py index 96aee72fc..141e67269 100644 --- a/pymodbus/repl/client/mclient.py +++ b/pymodbus/repl/client/mclient.py @@ -1,4 +1,4 @@ -""" Modbus Clients to be used with REPL. +"""Modbus Clients to be used with REPL. Copyright (c) 2018 Riptide IO, Inc. All Rights Reserved. @@ -15,27 +15,27 @@ GetCommEventCounterRequest, GetCommEventLogRequest) from pymodbus.diag_message import ( - ReturnQueryDataRequest, - RestartCommunicationsOptionRequest, - ReturnDiagnosticRegisterRequest, - ChangeAsciiInputDelimiterRequest, - ForceListenOnlyModeRequest, - ClearCountersRequest, - ReturnBusMessageCountRequest, - ReturnBusCommunicationErrorCountRequest, - ReturnBusExceptionErrorCountRequest, - ReturnSlaveMessageCountRequest, - ReturnSlaveNoResponseCountRequest, - ReturnSlaveNAKCountRequest, - ReturnSlaveBusyCountRequest, - ReturnSlaveBusCharacterOverrunCountRequest, - ReturnIopOverrunCountRequest, - ClearOverrunCountRequest, - GetClearModbusPlusRequest) + ReturnQueryDataRequest, + RestartCommunicationsOptionRequest, + ReturnDiagnosticRegisterRequest, + ChangeAsciiInputDelimiterRequest, + ForceListenOnlyModeRequest, + ClearCountersRequest, + ReturnBusMessageCountRequest, + ReturnBusCommunicationErrorCountRequest, + ReturnBusExceptionErrorCountRequest, + ReturnSlaveMessageCountRequest, + ReturnSlaveNoResponseCountRequest, + ReturnSlaveNAKCountRequest, + ReturnSlaveBusyCountRequest, + ReturnSlaveBusCharacterOverrunCountRequest, + ReturnIopOverrunCountRequest, + ClearOverrunCountRequest, + GetClearModbusPlusRequest) def make_response_dict(resp): - """ Make response dict. """ + """Make response dict.""" resp_dict = { 'function_code': resp.function_code, 'address': resp.address @@ -50,7 +50,7 @@ def make_response_dict(resp): def handle_brodcast(func): - """ Handle broadcast. """ + """Handle broadcast.""" @functools.wraps(func) def _wrapper(*args, **kwargs): self = args[0] @@ -61,17 +61,17 @@ def _wrapper(*args, **kwargs): } if not resp.isError(): return make_response_dict(resp) - return ExtendedRequestSupport._process_exception(resp, **kwargs) # pylint: disable=protected-access + return ExtendedRequestSupport._process_exception(resp, **kwargs) # pylint: disable=protected-access return _wrapper -class ExtendedRequestSupport: # pylint: disable=(too-many-public-methods - """ Extended request support. """ +class ExtendedRequestSupport: # pylint: disable=(too-many-public-methods + """Extended request support.""" @staticmethod def _process_exception(resp, **kwargs): - """ Internal process exception. """ - if not (unit := kwargs.get("unit")): + """Process exception.""" + if not kwargs.get("unit"): err = { "message": "Broadcast message, ignoring errors!!!" } @@ -94,15 +94,15 @@ def _process_exception(resp, **kwargs): return err def read_coils(self, address, count=1, **kwargs): - """ Reads `count` coils from a given slave starting at `address`. + """Read `count` coils from a given slave starting at `address`. :param address: The starting address to read from :param count: The number of coils to read :param unit: The slave unit this request is targeting :returns: List of register values """ - resp = super().read_coils(address, # pylint: disable=no-member - count, **kwargs) + resp = super().read_coils(address, # pylint: disable=no-member + count, **kwargs) if not resp.isError(): return { 'function_code': resp.function_code, @@ -111,14 +111,14 @@ def read_coils(self, address, count=1, **kwargs): return ExtendedRequestSupport._process_exception(resp) def read_discrete_inputs(self, address, count=1, **kwargs): - """ Reads `count` number of discrete inputs starting at offset `address`. + """Read `count` number of discrete inputs starting at offset `address`. :param address: The starting address to read from :param count: The number of coils to read :param unit: The slave unit this request is targeting :return: List of bits """ - resp = super().read_discrete_inputs(address, count, **kwargs) # pylint: disable=no-member + resp = super().read_discrete_inputs(address, count, **kwargs) # pylint: disable=no-member if not resp.isError(): return { 'function_code': resp.function_code, @@ -128,65 +128,65 @@ def read_discrete_inputs(self, address, count=1, **kwargs): @handle_brodcast def write_coil(self, address, value, **kwargs): - """ Write `value` to coil at `address`. + """Write `value` to coil at `address`. :param address: coil offset to write to :param value: bit value to write :param unit: The slave unit this request is targeting :return: """ - resp = super().write_coil( # pylint: disable=no-member + resp = super().write_coil( # pylint: disable=no-member address, value, **kwargs) return resp @handle_brodcast def write_coils(self, address, values, **kwargs): - """ Write `value` to coil at `address`. + """Write `value` to coil at `address`. :param address: coil offset to write to :param values: list of bit values to write (comma separated) :param unit: The slave unit this request is targeting :return: """ - resp = super().write_coils( # pylint: disable=no-member + resp = super().write_coils( # pylint: disable=no-member address, values, **kwargs) return resp @handle_brodcast def write_register(self, address, value, **kwargs): - """ Write `value` to register at `address`. + """Write `value` to register at `address`. :param address: register offset to write to :param value: register value to write :param unit: The slave unit this request is targeting :return: """ - resp = super().write_register( # pylint: disable=no-member + resp = super().write_register( # pylint: disable=no-member address, value, **kwargs) return resp @handle_brodcast def write_registers(self, address, values, **kwargs): - """ Write list of `values` to registers starting at `address`. + """Write list of `values` to registers starting at `address`. :param address: register offset to write to :param values: list of register value to write (comma separated) :param unit: The slave unit this request is targeting :return: """ - resp = super().write_registers( # pylint: disable=no-member + resp = super().write_registers( # pylint: disable=no-member address, values, **kwargs) return resp def read_holding_registers(self, address, count=1, **kwargs): - """ Read `count` number of holding registers starting at `address`. + """Read `count` number of holding registers starting at `address`. :param address: starting register offset to read from :param count: Number of registers to read :param unit: The slave unit this request is targeting :return: """ - resp = super().read_holding_registers( # pylint: disable=no-member + resp = super().read_holding_registers( # pylint: disable=no-member address, count, **kwargs) if not resp.isError(): return { @@ -196,14 +196,14 @@ def read_holding_registers(self, address, count=1, **kwargs): return ExtendedRequestSupport._process_exception(resp) def read_input_registers(self, address, count=1, **kwargs): - """ Read `count` number of input registers starting at `address`. + """Read `count` number of input registers starting at `address`. :param address: starting register offset to read from to :param count: Number of registers to read :param unit: The slave unit this request is targeting :return: """ - resp = super().read_input_registers( # pylint: disable=no-member + resp = super().read_input_registers( # pylint: disable=no-member address, count, **kwargs) if not resp.isError(): return { @@ -214,9 +214,10 @@ def read_input_registers(self, address, count=1, **kwargs): def readwrite_registers(self, read_address, read_count, write_address, write_registers, **kwargs): - """ Read `read_count` number of holding registers starting at \ - `read_address` and write `write_registers` \ - starting at `write_address`. + """Read `read_count` number of holding registers. + + Starting at `read_address` + and write `write_registers` starting at `write_address`. :param read_address: register offset to read from :param read_count: Number of registers to read @@ -225,7 +226,7 @@ def readwrite_registers(self, read_address, read_count, write_address, :param unit: The slave unit this request is targeting :return: """ - resp = super().readwrite_registers( # pylint: disable=no-member + resp = super().readwrite_registers( # pylint: disable=no-member read_address=read_address, read_count=read_count, write_address=write_address, @@ -241,8 +242,7 @@ def readwrite_registers(self, read_address, read_count, write_address, def mask_write_register(self, address=0x0000, and_mask=0xffff, or_mask=0x0000, **kwargs): - """ Mask content of holding register at `address` \ - with `and_mask` and `or_mask`. + """Mask content of holding register at `address` with `and_mask` and `or_mask`. :param address: Reference address of register :param and_mask: And Mask @@ -250,7 +250,7 @@ def mask_write_register(self, address=0x0000, :param unit: The slave unit this request is targeting :return: """ - resp = super().mask_write_register( # pylint: disable=no-member + resp = super().mask_write_register( # pylint: disable=no-member address=address, and_mask=and_mask, or_mask=or_mask, **kwargs) if not resp.isError(): return { @@ -262,8 +262,8 @@ def mask_write_register(self, address=0x0000, return ExtendedRequestSupport._process_exception(resp) def read_device_information(self, read_code=None, - object_id=0x00, **kwargs): - """ Read the identification and additional information of remote slave. + object_id=0x00, **kwargs): + """Read the identification and additional information of remote slave. :param read_code: Read Device ID code (0x01/0x02/0x03/0x04) :param object_id: Identification of the first object to obtain. @@ -271,7 +271,7 @@ def read_device_information(self, read_code=None, :return: """ request = ReadDeviceInformationRequest(read_code, object_id, **kwargs) - resp = self.execute(request) # pylint: disable=no-member + resp = self.execute(request) # pylint: disable=no-member if not resp.isError(): return { 'function_code': resp.function_code, @@ -285,13 +285,13 @@ def read_device_information(self, read_code=None, return ExtendedRequestSupport._process_exception(resp) def report_slave_id(self, **kwargs): - """ Report information about remote slave ID. + """Report information about remote slave ID. :param unit: The slave unit this request is targeting :return: """ request = ReportSlaveIdRequest(**kwargs) - resp = self.execute(request) # pylint: disable=no-member + resp = self.execute(request) # pylint: disable=no-member if not resp.isError(): return { 'function_code': resp.function_code, @@ -302,8 +302,9 @@ def report_slave_id(self, **kwargs): return ExtendedRequestSupport._process_exception(resp) def read_exception_status(self, **kwargs): - """ Read the contents of eight Exception Status outputs in a remote \ - device. + """Read tcontents of eight Exception Status output. + + In a remote device. :param unit: The slave unit this request is targeting @@ -311,7 +312,7 @@ def read_exception_status(self, **kwargs): """ request = ReadExceptionStatusRequest(**kwargs) - resp = self.execute(request) # pylint: disable=no-member + resp = self.execute(request) # pylint: disable=no-member if not resp.isError(): return { 'function_code': resp.function_code, @@ -320,8 +321,9 @@ def read_exception_status(self, **kwargs): return ExtendedRequestSupport._process_exception(resp) def get_com_event_counter(self, **kwargs): - """ Read status word and an event count from the remote device's \ - communication event counter. + """Read status word and an event count. + + From the remote device's communication event counter. :param unit: The slave unit this request is targeting @@ -329,7 +331,7 @@ def get_com_event_counter(self, **kwargs): """ request = GetCommEventCounterRequest(**kwargs) - resp = self.execute(request) # pylint: disable=no-member + resp = self.execute(request) # pylint: disable=no-member if not resp.isError(): return { 'function_code': resp.function_code, @@ -339,14 +341,16 @@ def get_com_event_counter(self, **kwargs): return ExtendedRequestSupport._process_exception(resp) def get_com_event_log(self, **kwargs): - """ Read status word, event count, message count, and a field of event + """Read status word. + + Event count, message count, and a field of event bytes from the remote device. :param unit: The slave unit this request is targeting :return: """ request = GetCommEventLogRequest(**kwargs) - resp = self.execute(request) # pylint: disable=no-member + resp = self.execute(request) # pylint: disable=no-member if not resp.isError(): return { 'function_code': resp.function_code, @@ -358,8 +362,8 @@ def get_com_event_log(self, **kwargs): return ExtendedRequestSupport._process_exception(resp) def _execute_diagnostic_request(self, request): - """ Internal execute diagnostic request. """ - resp = self.execute(request) # pylint: disable=no-member + """Execute diagnostic request.""" + resp = self.execute(request) # pylint: disable=no-member if not resp.isError(): return { 'function code': resp.function_code, @@ -369,7 +373,7 @@ def _execute_diagnostic_request(self, request): return ExtendedRequestSupport._process_exception(resp) def return_query_data(self, message=0, **kwargs): - """ Diagnostic sub command , Loop back data sent in response. + """Loop back data sent in response. :param message: Message to be looped back :param unit: The slave unit this request is targeting @@ -379,8 +383,9 @@ def return_query_data(self, message=0, **kwargs): return self._execute_diagnostic_request(request) def restart_comm_option(self, toggle=False, **kwargs): - """ Diagnostic sub command, initialize and restart remote devices serial \ - interface and clear all of its communications event counters . + """Initialize and restart remote devices. + + Serial interface and clear all of its communications event counters. :param toggle: Toggle Status [ON(0xff00)/OFF(0x0000] :param unit: The slave unit this request is targeting @@ -390,7 +395,7 @@ def restart_comm_option(self, toggle=False, **kwargs): return self._execute_diagnostic_request(request) def return_diagnostic_register(self, data=0, **kwargs): - """ Diagnostic sub command, Read 16-bit diagnostic register. + """Read 16-bit diagnostic register. :param data: Data field (0x0000) :param unit: The slave unit this request is targeting @@ -400,7 +405,7 @@ def return_diagnostic_register(self, data=0, **kwargs): return self._execute_diagnostic_request(request) def change_ascii_input_delimiter(self, data=0, **kwargs): - """ Diagnostic sub command, Change message delimiter for future requests. + """Change message delimiter for future requests. :param data: New delimiter character :param unit: The slave unit this request is targeting @@ -410,8 +415,7 @@ def change_ascii_input_delimiter(self, data=0, **kwargs): return self._execute_diagnostic_request(request) def force_listen_only_mode(self, data=0, **kwargs): - """ Diagnostic sub command, Forces the addressed remote device to \ - its Listen Only Mode. + """Force addressed remote device to its Listen Only Mode. :param data: Data field (0x0000) :param unit: The slave unit this request is targeting @@ -421,7 +425,7 @@ def force_listen_only_mode(self, data=0, **kwargs): return self._execute_diagnostic_request(request) def clear_counters(self, data=0, **kwargs): - """ Diagnostic sub command, Clear all counters and diag registers. + """Clear all counters and diag registers. :param data: Data field (0x0000) :param unit: The slave unit this request is targeting @@ -431,8 +435,7 @@ def clear_counters(self, data=0, **kwargs): return self._execute_diagnostic_request(request) def return_bus_message_count(self, data=0, **kwargs): - """ Diagnostic sub command, Return count of message detected on bus \ - by remote slave. + """Return count of message detected on bus by remote slave. :param data: Data field (0x0000) :param unit: The slave unit this request is targeting @@ -442,8 +445,7 @@ def return_bus_message_count(self, data=0, **kwargs): return self._execute_diagnostic_request(request) def return_bus_com_error_count(self, data=0, **kwargs): - """ Diagnostic sub command, Return count of CRC errors \ - received by remote slave. + """Return count of CRC errors received by remote slave. :param data: Data field (0x0000) :param unit: The slave unit this request is targeting @@ -453,8 +455,7 @@ def return_bus_com_error_count(self, data=0, **kwargs): return self._execute_diagnostic_request(request) def return_bus_exception_error_count(self, data=0, **kwargs): - """ Diagnostic sub command, Return count of Modbus exceptions \ - returned by remote slave. + """Return count of Modbus exceptions returned by remote slave. :param data: Data field (0x0000) :param unit: The slave unit this request is targeting @@ -464,8 +465,7 @@ def return_bus_exception_error_count(self, data=0, **kwargs): return self._execute_diagnostic_request(request) def return_slave_message_count(self, data=0, **kwargs): - """ Diagnostic sub command, Return count of messages addressed to \ - remote slave. + """Return count of messages addressed to remote slave. :param data: Data field (0x0000) :param unit: The slave unit this request is targeting @@ -475,7 +475,7 @@ def return_slave_message_count(self, data=0, **kwargs): return self._execute_diagnostic_request(request) def return_slave_no_response_count(self, data=0, **kwargs): - """ Diagnostic sub command, Return count of No responses by remote slave. + """Return count of No responses by remote slave. :param data: Data field (0x0000) :param unit: The slave unit this request is targeting @@ -485,8 +485,7 @@ def return_slave_no_response_count(self, data=0, **kwargs): return self._execute_diagnostic_request(request) def return_slave_no_ack_count(self, data=0, **kwargs): - """ Diagnostic sub command, Return count of NO ACK exceptions sent \ - by remote slave. + """Return count of NO ACK exceptions sent by remote slave. :param data: Data field (0x0000) :param unit: The slave unit this request is targeting @@ -496,8 +495,7 @@ def return_slave_no_ack_count(self, data=0, **kwargs): return self._execute_diagnostic_request(request) def return_slave_busy_count(self, data=0, **kwargs): - """ Diagnostic sub command, Return count of server busy exceptions sent \ - by remote slave. + """Return count of server busy exceptions sent by remote slave. :param data: Data field (0x0000) :param unit: The slave unit this request is targeting @@ -507,8 +505,9 @@ def return_slave_busy_count(self, data=0, **kwargs): return self._execute_diagnostic_request(request) def return_slave_bus_char_overrun_count(self, data=0, **kwargs): - """ Diagnostic sub command, Return count of messages not handled \ - by remote slave due to character overrun condition. + """Return count of messages not handled. + + By remote slave due to character overrun condition. :param data: Data field (0x0000) :param unit: The slave unit this request is targeting @@ -518,8 +517,7 @@ def return_slave_bus_char_overrun_count(self, data=0, **kwargs): return self._execute_diagnostic_request(request) def return_iop_overrun_count(self, data=0, **kwargs): - """ Diagnostic sub command, Return count of iop overrun errors \ - by remote slave. + """Return count of iop overrun errors by remote slave. :param data: Data field (0x0000) :param unit: The slave unit this request is targeting @@ -529,7 +527,7 @@ def return_iop_overrun_count(self, data=0, **kwargs): return self._execute_diagnostic_request(request) def clear_overrun_count(self, data=0, **kwargs): - """ Diagnostic sub command, Clear over run counter. + """Clear over run counter. :param data: Data field (0x0000) :param unit: The slave unit this request is targeting @@ -539,33 +537,32 @@ def clear_overrun_count(self, data=0, **kwargs): return self._execute_diagnostic_request(request) def get_clear_modbus_plus(self, data=0, **kwargs): - """ Diagnostic sub command, Get or clear stats of remote \ - modbus plus device. + """Get/clear stats of remote modbus plus device. :param data: Data field (0x0000) :param unit: The slave unit this request is targeting :return: """ - request = GetClearModbusPlusRequest(data, **kwargs) # pylint: disable=too-many-function-args + request = GetClearModbusPlusRequest(data, **kwargs) # pylint: disable=too-many-function-args return self._execute_diagnostic_request(request) class ModbusSerialClient(ExtendedRequestSupport, _ModbusSerialClient): - """ Modbus serial client. """ + """Modbus serial client.""" def __init__(self, method, **kwargs): - """Setup class.""" + """Initialize.""" super().__init__(method, **kwargs) def get_port(self): - """ Serial Port. + """Get serial Port. :return: Current Serial port """ return self.port def set_port(self, value): - """ Serial Port setter. + """Set serial Port setter. :param value: New port """ @@ -574,14 +571,14 @@ def set_port(self, value): self.close() def get_stopbits(self): - """ Number of stop bits. + """Get number of stop bits. :return: Current Stop bits """ return self.stopbits def set_stopbits(self, value): - """ Stop bit setter. + """Set stop bit. :param value: Possible values (1, 1.5, 2) """ @@ -590,14 +587,14 @@ def set_stopbits(self, value): self.close() def get_bytesize(self): - """ Number of data bits. + """Get number of data bits. :return: Current bytesize """ return self.bytesize def set_bytesize(self, value): - """ Byte size setter. + """Set Byte size. :param value: Possible values (5, 6, 7, 8) @@ -607,14 +604,14 @@ def set_bytesize(self, value): self.close() def get_parity(self): - """ Enable Parity Checking. + """Enable Parity Checking. :return: Current parity setting """ return self.parity def set_parity(self, value): - """ Parity Setter. + """Set parity Setter. :param value: Possible values ('N', 'E', 'O', 'M', 'S') """ @@ -623,14 +620,14 @@ def set_parity(self, value): self.close() def get_baudrate(self): - """ Serial Port baudrate. + """Get serial Port baudrate. :return: Current baudrate """ return self.baudrate def set_baudrate(self, value): - """ Baudrate setter. + """Set baudrate setter. :param value: """ @@ -639,14 +636,14 @@ def set_baudrate(self, value): self.close() def get_timeout(self): - """ Serial Port Read timeout. + """Get serial Port Read timeout. :return: Current read imeout. """ return self.timeout def set_timeout(self, value): - """ Read timeout setter. + """Read timeout setter. :param value: Read Timeout in seconds """ @@ -655,7 +652,7 @@ def set_timeout(self, value): self.close() def get_serial_settings(self): - """ Gets Current Serial port settings. + """Get Current Serial port settings. :return: Current Serial settings as dict. """ @@ -673,5 +670,7 @@ def get_serial_settings(self): class ModbusTcpClient(ExtendedRequestSupport, _ModbusTcpClient): """TCP client.""" + def __init__(self, **kwargs): + """Initialize.""" super().__init__(**kwargs) diff --git a/pymodbus/repl/server/__init__.py b/pymodbus/repl/server/__init__.py index 8feb11bcc..032e8ae26 100644 --- a/pymodbus/repl/server/__init__.py +++ b/pymodbus/repl/server/__init__.py @@ -1,3 +1,5 @@ -""" Copyright (c) 2020 by RiptideIO +"""Repl server. + +Copyright (c) 2020 by RiptideIO All rights reserved. """ diff --git a/pymodbus/repl/server/cli.py b/pymodbus/repl/server/cli.py index f445ba0cc..4e9e4a763 100644 --- a/pymodbus/repl/server/cli.py +++ b/pymodbus/repl/server/cli.py @@ -1,4 +1,6 @@ -""" Copyright (c) 2020 by RiptideIO +"""Repl server cli. + +Copyright (c) 2020 by RiptideIO All rights reserved. """ import logging @@ -17,13 +19,13 @@ _logger = logging.getLogger(__name__) TITLE = ( -"__________ .______. _________" -"\______ \___.__. _____ ____ __| _/\_ |__ __ __ ______ / _____/ ______________ __ ___________" # pylint: disable=anomalous-backslash-in-string -" | ___< | |/ \ / _ \ / __ | | __ \| | \/ ___/ \_____ \_/ __ \_ __ \ \/ // __ \_ __ \\" # pylint: disable=anomalous-backslash-in-string -" | | \___ | Y Y ( <_> ) /_/ | | \_\ \ | /\___ \ / \ ___/| | \/\ /\ ___/| | \/" # pylint: disable=anomalous-backslash-in-string -" |____| / ____|__|_| /\____/\____ | |___ /____//____ > /_______ /\___ >__| \_/ \___ >__|" # pylint: disable=anomalous-backslash-in-string -" \/ \/ \/ \/ \/ \/ \/ \/" # pylint: disable=anomalous-backslash-in-string -" 1.0.0" + r"__________ .______. _________" + r"\______ \___.__. _____ ____ __| _/\_ |__ __ __ ______ / _____/ ______________ __ ___________" + r" | ___< | |/ \ / _ \ / __ | | __ \| | \/ ___/ \_____ \_/ __ \_ __ \ \/ // __ \_ __ \\" + r" | | \___ | Y Y ( <_> ) /_/ | | \_\ \ | /\___ \ / \ ___/| | \/\ /\ ___/| | \/" + r" |____| / ____|__|_| /\____/\____ | |___ /____//____ > /_______ /\___ >__| \_/ \___ >__|" + r" \/ \/ \/ \/ \/ \/ \/ \/" + r" 1.0.0" ) SMALL_TITLE = "Pymodbus server..." @@ -61,7 +63,7 @@ "5. To disable response manipulation\n\t" \ " manipulator response_type=normal" COMMAND_HELPS = { - "manipulator": f"Manipulate response from server.\nUsage: {USAGE}", + "manipulator": f"Manipulate response from server.\nUsage: {USAGE}", "clear": "Clears screen" } @@ -69,48 +71,49 @@ STYLE = Style.from_dict({"": "cyan"}) CUSTOM_FORMATTERS = [ - formatters.Label(suffix=": "), - formatters.Bar(start="|", end="|", sym_a="#", sym_b="#", sym_c="-"), - formatters.Text(" "), - formatters.Text(" "), - formatters.TimeElapsed(), - formatters.Text(" "), - ] + formatters.Label(suffix=": "), + formatters.Bar(start="|", end="|", sym_a="#", sym_b="#", sym_c="-"), + formatters.Text(" "), + formatters.Text(" "), + formatters.TimeElapsed(), + formatters.Text(" "), +] def info(message): - """ Show info. """ + """Show info.""" if not isinstance(message, str): message = str(message) click.secho(message, fg="green") def warning(message): - """ Show warning. """ + """Show warning.""" click.secho(str(message), fg="yellow") def error(message): - """ Show error. """ + """Show error.""" click.secho(str(message), fg="red") def get_terminal_width(): - """ Get terminal width. """ + """Get terminal width.""" return shutil.get_terminal_size()[0] def print_help(): - """ Print help. """ + """Print help.""" print_formatted_text(HTML("Available commands:")) for cmd, hlp in sorted(COMMAND_HELPS.items()): print_formatted_text( - HTML("{:45s}{:100s}".format(cmd, hlp)) # pylint: disable=consider-using-f-string + HTML("{:45s}{:100s}".format(cmd, hlp) # pylint: disable=C0209 + ) ) -async def interactive_shell(server): #NOSONAR pylint: disable=too-complex - """ CLI interactive shell. """ +async def interactive_shell(server): # NOSONAR pylint: disable=too-complex + """Run CLI interactive shell.""" col = get_terminal_width() max_len = max([len(t) for t in TITLE.split("\n")]) if col > max_len: @@ -124,7 +127,7 @@ async def interactive_shell(server): #NOSONAR pylint: disable=too-complex bottom_toolbar=BOTTOM_TOOLBAR) # Run echo loop. Read text from stdin, and reply it back. - while True: # pylint: disable=too-many-nested-blocks + while True: # pylint: disable=too-many-nested-blocks try: invalid_command = False result = await session.prompt_async() @@ -157,7 +160,7 @@ async def interactive_shell(server): #NOSONAR pylint: disable=too-complex arg, value = arg.split("=") elif arg in COMMAND_ARGS: try: - value = args[index+1] + value = args[index + 1] skip_next = True except IndexError: error(f"Missing value for argument - {arg}") @@ -169,8 +172,8 @@ async def interactive_shell(server): #NOSONAR pylint: disable=too-complex warning(f"Invalid response type request - {value}") warning(f"Choose from {RESPONSE_TYPES}") valid = False - elif arg in set(["error_code", "delay_by", # pylint: disable=confusing-consecutive-elif - "clear_after", "data_len"]): + elif arg in set(["error_code", "delay_by", # pylint: disable=confusing-consecutive-elif + "clear_after", "data_len"]): try: value = int(value) except ValueError: @@ -189,7 +192,7 @@ async def interactive_shell(server): #NOSONAR pylint: disable=too-complex async def main(server): - """Main to run.""" + """Run main.""" # with patch_stdout(): try: await interactive_shell(server) diff --git a/pymodbus/repl/server/main.py b/pymodbus/repl/server/main.py index 3d4b8b64b..75f10fe8a 100644 --- a/pymodbus/repl/server/main.py +++ b/pymodbus/repl/server/main.py @@ -1,4 +1,6 @@ -""" Copyright (c) 2020 by RiptideIO +"""Repl server main. + +Copyright (c) 2020 by RiptideIO All rights reserved. """ import sys @@ -15,7 +17,7 @@ if sys.version_info > (3, 7): CANCELLED_ERROR = asyncio.exceptions.CancelledError else: - CANCELLED_ERROR = asyncio.CancelledError # pylint: disable=invalid-name + CANCELLED_ERROR = asyncio.CancelledError # pylint: disable=invalid-name _logger = logging.getLogger(__name__) @@ -31,10 +33,10 @@ help="Run with debug logs enabled for pymodbus") @click.pass_context def server(ctx, host, web_port, broadcast_support, repl, verbose): - """Server code.""" - FORMAT = ('%(asctime)-15s %(threadName)-15s' # pylint: disable=invalid-name + """Run server code.""" + FORMAT = ('%(asctime)-15s %(threadName)-15s' # pylint: disable=invalid-name ' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s') - logging.basicConfig(format=FORMAT) #NOSONAR + logging.basicConfig(format=FORMAT) # NOSONAR if verbose: _logger.setLevel(logging.DEBUG) else: @@ -66,15 +68,16 @@ def server(ctx, host, web_port, broadcast_support, repl, verbose): @click.pass_context def run(ctx, modbus_server, modbus_framer, modbus_port, modbus_unit_id, modbus_config, randomize): - """ Run Reactive Modbus server exposing REST endpoint - for response manipulation. + """Run Reactive Modbus server. + + Exposing REST endpoint for response manipulation. """ repl = ctx.obj.pop("repl") web_app_config = ctx.obj loop = asyncio.get_event_loop() framer = DEFAULT_FRAMER.get(modbus_framer, ModbusSocketFramer) if modbus_config: - with open(modbus_config) as my_file: # pylint: disable=unspecified-encoding + with open(modbus_config) as my_file: # pylint: disable=unspecified-encoding modbus_config = json.load(my_file) else: modbus_config = DEFUALT_CONFIG @@ -107,4 +110,4 @@ def run(ctx, modbus_server, modbus_framer, modbus_port, modbus_unit_id, if __name__ == '__main__': - server() # pylint: disable=no-value-for-parameter + server() # pylint: disable=no-value-for-parameter diff --git a/pymodbus/server/__init__.py b/pymodbus/server/__init__.py index 217d7917f..43f970b52 100644 --- a/pymodbus/server/__init__.py +++ b/pymodbus/server/__init__.py @@ -1 +1 @@ -""" Nothing special. """ +"""Nothing special.""" diff --git a/pymodbus/server/async_io.py b/pymodbus/server/async_io.py index c991637e2..663dd949a 100755 --- a/pymodbus/server/async_io.py +++ b/pymodbus/server/async_io.py @@ -1,7 +1,4 @@ -""" Implementation of a Threaded Modbus Server ------------------------------------------- - -""" +"""Implementation of a Threaded Modbus Server.""" import logging import warnings from binascii import b2a_hex @@ -38,7 +35,8 @@ # --------------------------------------------------------------------------- # class ModbusBaseRequestHandler(asyncio.BaseProtocol): - """ Implements modbus slave wire protocol + """Implements modbus slave wire protocol. + This uses the asyncio.Protocol to implement the client handler. When a connection is established, the asyncio.Protocol.connection_made @@ -47,6 +45,7 @@ class ModbusBaseRequestHandler(asyncio.BaseProtocol): running_task will be canceled upon connection_lost event. """ + def __init__(self, owner): self.server = owner self.running = False @@ -54,7 +53,7 @@ def __init__(self, owner): self.handler_task = None # coroutine to be run on asyncio loop def _log_exception(self): - """ Internal log exception. """ + """Show log exception.""" if isinstance(self, ModbusConnectedRequestHandler): txt = f"Handler for stream [{self.client_address[:2]}] has been canceled" _logger.error(txt) @@ -62,12 +61,12 @@ def _log_exception(self): _logger.error( "Handler for serial port has been cancelled") else: - sock_name = self.protocol._sock.getsockname() # pylint: disable=protected-access,no-member + sock_name = self.protocol._sock.getsockname() # pylint: disable=protected-access,no-member txt = f"Handler for UDP socket [{sock_name[1]}] has been canceled" _logger.error(txt) def connection_made(self, transport): - """ asyncio.BaseProtocol callback for socket establish + """Call for socket establish For streamed protocols (TCP) this will also correspond to an entire conversation; however for datagram protocols (UDP) this @@ -85,18 +84,19 @@ def connection_made(self, transport): else: txt = f"Unable to get information about transport {transport}" _logger.warning(txt) - self.transport = transport # pylint: disable=attribute-defined-outside-init + self.transport = transport # pylint: disable=attribute-defined-outside-init self.running = True - self.framer = self.server.framer(self.server.decoder, client=None) # pylint: disable=attribute-defined-outside-init + self.framer = self.server.framer(self.server.decoder, # pylint: disable=attribute-defined-outside-init + client=None) # schedule the connection handler on the event loop self.handler_task = asyncio.create_task(self.handle()) - except Exception as exc: # pragma: no cover pylint: disable=broad-except + except Exception as exc: # pragma: no cover pylint: disable=broad-except txt = f"Datastore unable to fulfill request: {exc}; {traceback.format_exc()}" _logger.error(txt) def connection_lost(self, call_exc): - """ asyncio.BaseProtocol callback for socket tear down + """Call for socket tear down. For streamed protocols any break in the network connection will be reported here; for datagram protocols, only a teardown of the @@ -112,13 +112,14 @@ def connection_lost(self, call_exc): self.running = False - except Exception as exc: # pragma: no cover pylint: disable=broad-except + except Exception as exc: # pragma: no cover pylint: disable=broad-except txt = f"Datastore unable to fulfill request: {exc}; {traceback.format_exc()}" _logger.error(txt) - async def handle(self): #NOSONAR pylint: disable=too-complex - """ Asyncio coroutine which represents a single conversation between - the modbus slave and master + async def handle(self): # NOSONAR pylint: disable=too-complex + """Return Asyncio coroutine which represents a single conversation. + + between the modbus slave and master Once the client connection is established, the data chunks will be fed to this coroutine via the asyncio.Queue object which is fed by @@ -158,7 +159,7 @@ async def handle(self): #NOSONAR pylint: disable=too-complex units = [units] # if broadcast is enabled make sure to # process requests to address 0 - if self.server.broadcast_enable: # pragma: no cover + if self.server.broadcast_enable: # pragma: no cover if 0 not in units: units.append(0) @@ -174,7 +175,7 @@ async def handle(self): #NOSONAR pylint: disable=too-complex except asyncio.CancelledError: # catch and ignore cancellation errors self._log_exception() - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except # force TCP socket termination as processIncomingPacket # should handle application layer errors # for UDP sockets, simply reset the frame @@ -193,7 +194,7 @@ async def handle(self): #NOSONAR pylint: disable=too-complex reset_frame = False def execute(self, request, *addr): - """ The callback to call with the resulting message + """Call with the resulting message. :param request: The decoded request message """ @@ -214,7 +215,7 @@ def execute(self, request, *addr): if self.server.ignore_missing_slaves: return # the client will simply timeout waiting for a response response = request.doException(merror.GatewayNoResponse) - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except txt = f"Datastore unable to fulfill request: {exc}; {traceback.format_exc()}" _logger.error(txt) response = request.doException(merror.SlaveFailure) @@ -228,7 +229,7 @@ def execute(self, request, *addr): self.send(response, *addr, skip_encoding=skip_encoding) def send(self, message, *addr, **kwargs): - """ Send message. """ + """Send message.""" def __send(msg, *addr): if _logger.isEnabledFor(logging.DEBUG): txt = f"send: [{message}]- {b2a_hex(msg)}" @@ -237,7 +238,7 @@ def __send(msg, *addr): self._send_(msg) else: self._send_(msg, *addr) - if skip_encoding := kwargs.get("skip_encoding", False): + if kwargs.get("skip_encoding", False): __send(message, *addr) elif message.should_respond: # self.server.control.Counter.BusMessage += 1 @@ -250,16 +251,16 @@ def __send(msg, *addr): # Derived class implementations # ----------------------------------------------------------------------- # - def _send_(self, data): # pragma: no cover pylint: disable=no-self-use - """ Send a request (string) to the network + def _send_(self, data): # pragma: no cover pylint: disable=no-self-use + """Send a request (string) to the network. :param message: The unencoded modbus response """ raise NotImplementedException("Method not implemented " "by derived class") - async def _recv_(self): # pragma: no cover pylint: disable=no-self-use - """ Receive data from the network + async def _recv_(self): # pragma: no cover pylint: disable=no-self-use + """Receive data from the network. :return: """ @@ -267,24 +268,24 @@ async def _recv_(self): # pragma: no cover pylint: disable=no-self-use "by derived class") -class ModbusConnectedRequestHandler(ModbusBaseRequestHandler,asyncio.Protocol): - """ Implements the modbus server protocol +class ModbusConnectedRequestHandler(ModbusBaseRequestHandler, asyncio.Protocol): + """Implements the modbus server protocol This uses asyncio.Protocol to implement the client handler for a connected protocol (TCP). """ def connection_made(self, transport): - """ asyncio.BaseProtocol: Called when a connection is made. """ + """Call when a connection is made.""" super().connection_made(transport) - self.client_address = transport.get_extra_info('peername') # pylint: disable=attribute-defined-outside-init + self.client_address = transport.get_extra_info('peername') # pylint: disable=attribute-defined-outside-init self.server.active_connections[self.client_address] = self txt = f"TCP client connection established [{self.client_address[:2]}]" _logger.debug(txt) def connection_lost(self, call_exc): - """ asyncio.BaseProtocol: Called when the connection is lost or closed. """ + """Call when the connection is lost or closed.""" super().connection_lost(call_exc) client_addr = self.client_address[:2] txt = f"TCP client disconnected [{client_addr}]" @@ -293,7 +294,8 @@ def connection_lost(self, call_exc): self.server.active_connections.pop(self.client_address) def data_received(self, data): - """ asyncio.Protocol: (TCP) Called when some data is received. + """Call when some data is received. + data is a non-empty bytes object containing the incoming data. """ self.receive_queue.put_nowait(data) @@ -307,40 +309,42 @@ async def _recv_(self): return result def _send_(self, data): - """ tcp send """ + """Send tcp.""" self.transport.write(data) class ModbusDisconnectedRequestHandler(ModbusBaseRequestHandler, asyncio.DatagramProtocol): - """ Implements the modbus server protocol + """Implements the modbus server protocol This uses the socketserver.BaseRequestHandler to implement the client handler for a disconnected protocol (UDP). The only difference is that we have to specify who to send the resulting packet data to. """ - def __init__(self,owner): + + def __init__(self, owner): super().__init__(owner) _future = asyncio.get_event_loop().create_future() self.server.on_connection_terminated = _future - def connection_lost(self,call_exc): + def connection_lost(self, call_exc): super().connection_lost(call_exc) self.server.on_connection_terminated.set_result(True) - def datagram_received(self,data, addr): - """ asyncio.DatagramProtocol: Called when a datagram is received. - data is a bytes object containing the incoming data. addr - is the address of the peer sending the data; the exact - format depends on the transport. + def datagram_received(self, data, addr): + """Call when a datagram is received. + + data is a bytes object containing the incoming data. addr + is the address of the peer sending the data; the exact + format depends on the transport. """ self.receive_queue.put_nowait((data, addr)) - def error_received(self,exc): # pragma: no cover - """ asyncio.DatagramProtocol: Called when a previous send - or receive operation raises an OSError. exc is the - OSError instance. + def error_received(self, exc): # pragma: no cover + """Call when a previous send/receive raises an OSError. + + exc is the OSError instance. This method is called in rare conditions, when the transport (e.g. UDP) detects that a datagram could @@ -357,13 +361,13 @@ def _send_(self, data, addr=None): self.transport.sendto(data, addr=addr) -class ModbusServerFactory: # pylint: disable=too-few-public-methods - """ Builder class for a modbus server +class ModbusServerFactory: # pylint: disable=too-few-public-methods + """Build class for a modbus server. This also holds the server datastore so that it is persisted between connections """ - def __init__(self, store, framer=None, identity=None, **kwargs): # pylint: disable=unused-argument + def __init__(self, store, framer=None, identity=None, **kwargs): # pylint: disable=unused-argument warnings.warn("deprecated API for asyncio. ServerFactory's are a " "twisted construct and don't have an equivalent in " "asyncio", @@ -371,11 +375,12 @@ def __init__(self, store, framer=None, identity=None, **kwargs): # pylint: disab class ModbusSingleRequestHandler(ModbusBaseRequestHandler, asyncio.Protocol): - """ Implements the modbus server protocol + """Implement the modbus server protocol. This uses asyncio.Protocol to implement the client handler for a serial connection. """ + def connection_made(self, transport): super().connection_made(transport) _logger.debug("Serial connection established") @@ -400,15 +405,16 @@ def _send_(self, data): # Server Implementations # --------------------------------------------------------------------------- # -class ModbusTcpServer: # pylint: disable=too-many-instance-attributes - """ A modbus threaded tcp socket server + +class ModbusTcpServer: # pylint: disable=too-many-instance-attributes + """A modbus threaded tcp socket server. We inherit and overload the socket server so that we can control the client threads as well as have a single server context instance. """ - def __init__(self, # pylint: disable=too-many-arguments + def __init__(self, # pylint: disable=too-many-arguments context, framer=None, identity=None, @@ -420,7 +426,7 @@ def __init__(self, # pylint: disable=too-many-arguments backlog=20, loop=None, **kwargs): - """ Overloaded initializer for the socket server + """Initialize the socket server. If the identify structure is not passed in, the ModbusControlBlock uses its own empty structure. @@ -478,10 +484,10 @@ def __init__(self, # pylint: disable=too-many-arguments reuse_port=allow_reuse_port, backlog=backlog, start_serving=not defer_start - ) + ) async def serve_forever(self): - """ Start endless loop. """ + """Start endless loop.""" if self.server is None: self.server = await self.server_factory self.serving.set_result(True) @@ -491,7 +497,7 @@ async def serve_forever(self): "an already running server object") def server_close(self): - """ Close server. """ + """Close server.""" for k_item, v_item in self.active_connections.items(): txt = f"aborting active session {k_item}" _logger.warning(txt) @@ -500,15 +506,15 @@ def server_close(self): self.server.close() -class ModbusTlsServer(ModbusTcpServer): # pylint: disable=too-many-instance-attributes - """ A modbus threaded tls socket server +class ModbusTlsServer(ModbusTcpServer): # pylint: disable=too-many-instance-attributes + """A modbus threaded tls socket server. We inherit and overload the socket server so that we can control the client threads as well as have a single server context instance. """ - def __init__(self, #NOSONAR pylint: disable=too-many-arguments,super-init-not-called + def __init__(self, # NOSONAR pylint: disable=too-many-arguments,super-init-not-called context, framer=None, identity=None, @@ -524,8 +530,8 @@ def __init__(self, #NOSONAR pylint: disable=too-many-arguments,super-init-not-ca defer_start=False, backlog=20, loop=None, - **kwargs): #NOSONAR - """ Overloaded initializer for the socket server + **kwargs): # NOSONAR + """Overloaded initializer for the socket server. If the identify structure is not passed in, the ModbusControlBlock uses its own empty structure. @@ -597,22 +603,23 @@ def __init__(self, #NOSONAR pylint: disable=too-many-arguments,super-init-not-ca start_serving=not defer_start ) -class ModbusUdpServer: # pylint: disable=too-many-instance-attributes - """ A modbus threaded udp socket server + +class ModbusUdpServer: # pylint: disable=too-many-instance-attributes + """A modbus threaded udp socket server. We inherit and overload the socket server so that we can control the client threads as well as have a single server context instance. """ - def __init__(self, context, framer=None, identity=None, address=None, # pylint: disable=too-many-arguments + def __init__(self, context, framer=None, identity=None, address=None, # pylint: disable=too-many-arguments handler=None, allow_reuse_address=False, allow_reuse_port=False, - defer_start=False, # pylint: disable=unused-argument - backlog=20, # pylint: disable=unused-argument + defer_start=False, # pylint: disable=unused-argument + backlog=20, # pylint: disable=unused-argument loop=None, **kwargs): - """ Overloaded initializer for the socket server + """Overloaded initializer for the socket server. If the identify structure is not passed in, the ModbusControlBlock uses its own empty structure. @@ -632,7 +639,7 @@ def __init__(self, context, framer=None, identity=None, address=None, # pylint: """ self.loop = loop or asyncio.get_event_loop() self.decoder = ServerDecoder() - self.framer = framer or ModbusSocketFramer + self.framer = framer or ModbusSocketFramer self.context = context or ModbusServerContext() self.control = ModbusControlBlock() self.address = address or ("", Defaults.Port) @@ -661,7 +668,7 @@ def __init__(self, context, framer=None, identity=None, address=None, # pylint: ) async def serve_forever(self): - """ Start endless loop. """ + """Start endless loop.""" if self.protocol is None: self.protocol, self.endpoint = await self.server_factory self.serving.set_result(True) @@ -671,7 +678,7 @@ async def serve_forever(self): "already running server object") def server_close(self): - """ Close server. """ + """Close server.""" self.stop_serving.set_result(True) if self.endpoint.handler_task is not None: self.endpoint.handler_task.cancel() @@ -679,8 +686,9 @@ def server_close(self): self.protocol.close() -class ModbusSerialServer: # pylint: disable=too-many-instance-attributes - """ A modbus threaded serial socket server +class ModbusSerialServer: # pylint: disable=too-many-instance-attributes + """A modbus threaded serial socket server. + We inherit and overload the socket server so that we can control the client threads as well as have a single server context instance. @@ -689,7 +697,8 @@ class ModbusSerialServer: # pylint: disable=too-many-instance-attributes handler = None def __init__(self, context, framer=None, identity=None, **kwargs): # pragma: no cover - """ Overloaded initializer for the socket server + """Initialize the socket server. + If the identity structure is not passed in, the ModbusControlBlock uses its own empty structure. :param context: The ModbusServerContext datastore @@ -740,23 +749,21 @@ def __init__(self, context, framer=None, identity=None, **kwargs): # pragma: no if isinstance(identity, ModbusDeviceIdentification): self.control.Identity.update(identity) - async def start(self): - """ Start connecting. """ + """Start connecting.""" await self._connect() - def _protocol_factory(self): - """ Internal protocol factory. """ + """Return protocol factory.""" return self.handler(self) async def _delayed_connect(self): - """ Internal delayed connect. """ + """Delay connect.""" await asyncio.sleep(self.reconnect_delay) await self._connect() async def _connect(self): - """ Internal connect. """ + """Connect.""" if self.reconnecting_task is not None: self.reconnecting_task = None try: @@ -776,12 +783,12 @@ async def _connect(self): if not self.auto_reconnect: raise exc self._check_reconnect() - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except txt = f"Exception while create - {exc}" _logger.debug(txt) def on_connection_lost(self): - """ Lost connection. """ + """Call on lost connection.""" if self.transport is not None: self.transport.close() self.transport = None @@ -790,7 +797,7 @@ def on_connection_lost(self): self._check_reconnect() def _check_reconnect(self): - """ Internal check reconnect. """ + """Check reconnect.""" txt = f"checking autoreconnect {self.auto_reconnect} {self.reconnecting_task}" _logger.debug(txt) if self.auto_reconnect and (self.reconnecting_task is None): @@ -799,32 +806,23 @@ def _check_reconnect(self): self.reconnecting_task = loop.create_task(self._delayed_connect()) async def serve_forever(self): - """ Start endless loop. """ + """Start endless loop.""" while True: await asyncio.sleep(360) self.protocol = None self.transport = None - def _protocol_factory(self): - """ Run protocol factory. """ - return self.handler(self) - - def _check_reconnect(self): - """ Check if reconnect. """ - txt = f"checking auto-reconnect {self.auto_reconnect} {self.reconnecting_task}" - _logger.debug(txt) - if self.auto_reconnect and (self.reconnecting_task is None): - _logger.debug("Scheduling serial connection reconnect") - loop = asyncio.get_event_loop() - self.reconnecting_task = loop.create_task(self._delayed_connect()) # --------------------------------------------------------------------------- # # Creation Factories # --------------------------------------------------------------------------- # -async def StartTcpServer(context=None, identity=None, address=None, #NOSONAR pylint: disable=invalid-name,dangerous-default-value + + +async def StartTcpServer(context=None, # NOSONAR pylint: disable=invalid-name,dangerous-default-value + identity=None, address=None, custom_functions=[], defer_start=True, **kwargs): - """ A factory to start and run a tcp modbus server + """Start and run a tcp modbus server. :param context: The ModbusServerContext datastore :param identity: An optional identify structure @@ -850,15 +848,16 @@ async def StartTcpServer(context=None, identity=None, address=None, #NOSONAR pyl return server -async def StartTlsServer(context=None, identity=None, address=None, #NOSONAR pylint: disable=invalid-name,dangerous-default-value,too-many-arguments - sslctx=None, - certfile=None, keyfile=None, password=None, - reqclicert=False, - allow_reuse_address=False, - allow_reuse_port=False, - custom_functions=[], - defer_start=True, **kwargs): - """ A factory to start and run a tls modbus server +async def StartTlsServer( # NOSONAR pylint: disable=invalid-name,dangerous-default-value,too-many-arguments + context=None, identity=None, address=None, + sslctx=None, + certfile=None, keyfile=None, password=None, + reqclicert=False, + allow_reuse_address=False, + allow_reuse_port=False, + custom_functions=[], + defer_start=True, **kwargs): + """Start and run a tls modbus server. :param context: The ModbusServerContext datastore :param identity: An optional identify structure @@ -887,7 +886,7 @@ async def StartTlsServer(context=None, identity=None, address=None, #NOSONAR pyl allow_reuse_port=allow_reuse_port, **kwargs) for func in custom_functions: - server.decoder.register(func) # pragma: no cover + server.decoder.register(func) # pragma: no cover if not defer_start: await server.serve_forever() @@ -895,9 +894,10 @@ async def StartTlsServer(context=None, identity=None, address=None, #NOSONAR pyl return server -async def StartUdpServer(context=None, identity=None, address=None, #NOSONAR pylint: disable=invalid-name,dangerous-default-value +async def StartUdpServer(context=None, # NOSONAR pylint: disable=invalid-name,dangerous-default-value + identity=None, address=None, custom_functions=[], defer_start=True, **kwargs): - """ A factory to start and run a udp modbus server + """Start and run a udp modbus server. :param context: The ModbusServerContext datastore :param identity: An optional identify structure @@ -912,17 +912,17 @@ async def StartUdpServer(context=None, identity=None, address=None, #NOSONAR pyl server = ModbusUdpServer(context, framer, identity, address, **kwargs) for func in custom_functions: - server.decoder.register(func) # pragma: no cover + server.decoder.register(func) # pragma: no cover if not defer_start: - await server.serve_forever() # pragma: no cover + await server.serve_forever() # pragma: no cover return server -async def StartSerialServer(context=None, identity=None, #NOSONAR pylint: disable=invalid-name,dangerous-default-value - custom_functions=[], **kwargs): # pragma: no cover - """ A factory to start and run a serial modbus server +async def StartSerialServer(context=None, identity=None, # NOSONAR pylint: disable=invalid-name,dangerous-default-value + custom_functions=[], **kwargs): # pragma: no cover + """Start and run a serial modbus server. :param context: The ModbusServerContext datastore :param identity: An optional identify structure @@ -946,8 +946,8 @@ async def StartSerialServer(context=None, identity=None, #NOSONAR pylint: disabl await server.serve_forever() -def StopServer(): #NOSONAR pylint: disable=invalid-name - """ Helper method to stop Async Server """ +def StopServer(): # NOSONAR pylint: disable=invalid-name + """Stop Async Server.""" warnings.warn("deprecated API for asyncio. Call server_close() on " "server object returned by StartXxxServer", DeprecationWarning) diff --git a/pymodbus/server/asynchronous.py b/pymodbus/server/asynchronous.py index 427abf8a5..24419fcea 100644 --- a/pymodbus/server/asynchronous.py +++ b/pymodbus/server/asynchronous.py @@ -1,13 +1,10 @@ -""" Implementation of a Twisted Modbus Server ------------------------------------------- - -""" +"""Implementation of a Twisted Modbus Server.""" import logging import threading from binascii import b2a_hex from twisted.internet import protocol from twisted.internet.protocol import ServerFactory -from twisted.internet import reactor # pylint: disable=unused-import +from twisted.internet import reactor # noqa F401 pylint: disable=unused-import from pymodbus.constants import Defaults from pymodbus.utilities import hexlify_packets @@ -17,7 +14,7 @@ from pymodbus.device import ModbusAccessControl from pymodbus.device import ModbusDeviceIdentification from pymodbus.exceptions import NoSuchSlaveException -from pymodbus.transaction import ModbusSocketFramer,ModbusAsciiFramer +from pymodbus.transaction import ModbusSocketFramer, ModbusAsciiFramer from pymodbus.pdu import ModbusExceptions as merror # --------------------------------------------------------------------------- # @@ -30,14 +27,14 @@ # Modbus TCP Server # --------------------------------------------------------------------------- # class ModbusTcpProtocol(protocol.Protocol): - """ Implements a modbus server in twisted """ + """Implements a modbus server in twisted.""" def __init__(self): """Define local variables.""" self.framer = None def connectionMade(self): - """ Callback for when a client connects + """Call when a client connects. ..note:: since the protocol factory cannot be accessed from the protocol __init__, the client connection made is essentially @@ -48,8 +45,8 @@ def connectionMade(self): self.framer = self.factory.framer(decoder=self.factory.decoder, client=None) - def connectionLost(self, reason): # pylint: disable=signature-differs - """ Callback for when a client disconnects + def connectionLost(self, reason): # pylint: disable=signature-differs + """Call when a client disconnects. :param reason: The client's reason for disconnecting """ @@ -57,7 +54,7 @@ def connectionLost(self, reason): # pylint: disable=signature-differs _logger.debug(txt) def dataReceived(self, data): - """ Callback when we receive any data + """Call when we receive any data. :param data: The data sent by the client """ @@ -72,7 +69,7 @@ def dataReceived(self, data): unit=units) def _execute(self, request): - """ Executes the request and returns the result + """Execute the request and returns the result. :param request: The decoded request message """ @@ -83,9 +80,9 @@ def _execute(self, request): txt = f"requested slave does not exist: {request.unit_id}" _logger.debug(txt) if self.factory.ignore_missing_slaves: - return # the client will simply timeout waiting for a response + return # the client will simply timeout waiting for a response response = request.doException(merror.GatewayNoResponse) - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except txt = f"Datastore unable to fulfill request: {exc}" _logger.debug(txt) response = request.doException(merror.SlaveFailure) @@ -95,7 +92,7 @@ def _execute(self, request): self._send(response) def _send(self, message): - """ Send a request (string) to the network + """Send a request (string) to the network. :param message: The unencoded modbus response """ @@ -110,7 +107,7 @@ def _send(self, message): class ModbusServerFactory(ServerFactory): - """ Builder class for a modbus server + """Builder class for a modbus server. This also holds the server datastore so that it is persisted between connections @@ -119,7 +116,7 @@ class ModbusServerFactory(ServerFactory): protocol = ModbusTcpProtocol def __init__(self, store, framer=None, identity=None, **kwargs): - """ Overloaded initializer for the modbus factory + """Initialize the modbus factory. If the identify structure is not passed in, the ModbusControlBlock uses its own empty structure. @@ -145,10 +142,10 @@ def __init__(self, store, framer=None, identity=None, **kwargs): # Modbus UDP Server # --------------------------------------------------------------------------- # class ModbusUdpProtocol(protocol.DatagramProtocol): - """ Implements a modbus udp server in twisted """ + """Implements a modbus udp server in twisted.""" def __init__(self, store, framer=None, identity=None, **kwargs): - """ Overloaded initializer for the modbus factory + """Initialize the modbus factory. If the identify structure is not passed in, the ModbusControlBlock uses its own empty structure. @@ -172,7 +169,7 @@ def __init__(self, store, framer=None, identity=None, **kwargs): self.control.Identity.update(identity) def datagramReceived(self, datagram, addr): - """ Callback when we receive any data + """Call when we receive any data. :param data: The data sent by the client """ @@ -186,7 +183,7 @@ def datagramReceived(self, datagram, addr): self.framer.processIncomingPacket(datagram, continuation) def _execute(self, request, addr): - """ Executes the request and returns the result + """Execute the request and return the result. :param request: The decoded request message """ @@ -197,19 +194,19 @@ def _execute(self, request, addr): txt = f"requested slave does not exist: {request.unit_id}" _logger.debug(txt) if self.ignore_missing_slaves: - return # the client will simply timeout waiting for a response + return # the client will simply timeout waiting for a response response = request.doException(merror.GatewayNoResponse) - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except txt = f"Datastore unable to fulfill request: {exc}" _logger.debug(txt) response = request.doException(merror.SlaveFailure) - #self.framer.populateResult(response) + # self.framer.populateResult(response) response.transaction_id = request.transaction_id response.unit_id = request.unit_id self._send(response, addr) def _send(self, message, addr): - """ Send a request (string) to the network + """Send a request (string) to the network. :param message: The unencoded modbus response :param addr: The (host, port) to send the message to @@ -226,7 +223,7 @@ def _send(self, message, addr): # Starting Factories # --------------------------------------------------------------------------- # def _is_main_thread(): - """ Internal is main thread. """ + """Return true if main thread.""" if threading.current_thread() != threading.main_thread(): _logger.debug("Running in spawned thread") return False @@ -234,10 +231,12 @@ def _is_main_thread(): return True -def StartTcpServer(context, identity=None, address=None, #NOSONAR pylint: disable=dangerous-default-value,invalid-name - console=False, defer_reactor_run=False, custom_functions=[], #NOSONAR pylint: disable=,unused-argument +def StartTcpServer(context, # NOSONAR pylint: disable=dangerous-default-value,invalid-name + identity=None, address=None, + console=False, defer_reactor_run=False, # NOSONAR pylint: disable=W0613, + custom_functions=[], **kwargs): - """ Helper method to start the Modbus Async TCP server + """Start the Modbus Async TCP server. :param context: The server data context :param identify: The server identity to use (default empty) @@ -250,7 +249,7 @@ def StartTcpServer(context, identity=None, address=None, #NOSONAR pylint: disabl :param custom_functions: An optional list of custom function classes supported by server instance. """ - from twisted.internet import reactor as local_reactor # pylint: disable=import-outside-toplevel,reimported + from twisted.internet import reactor as local_reactor # pylint: disable=import-outside-toplevel,reimported address = address or ("", Defaults.Port) framer = kwargs.pop("framer", ModbusSocketFramer) @@ -260,14 +259,14 @@ def StartTcpServer(context, identity=None, address=None, #NOSONAR pylint: disabl txt = f"Starting Modbus TCP Server on {address}" _logger.info(txt) - local_reactor.listenTCP(address[1], factory, interface=address[0]) # pylint: disable=no-member + local_reactor.listenTCP(address[1], factory, interface=address[0]) # pylint: disable=no-member if not defer_reactor_run: - local_reactor.run(installSignalHandlers=_is_main_thread()) # pylint: disable=no-member + local_reactor.run(installSignalHandlers=_is_main_thread()) # pylint: disable=no-member -def StartUdpServer(context, identity=None, address=None, #NOSONAR pylint: disable=invalid-name,dangerous-default-value +def StartUdpServer(context, identity=None, address=None, # NOSONAR pylint: disable=invalid-name,dangerous-default-value defer_reactor_run=False, custom_functions=[], **kwargs): - """ Helper method to start the Modbus Async Udp server + """Start the Modbus Async Udp server. :param context: The server data context :param identify: The server identity to use (default empty) @@ -279,7 +278,7 @@ def StartUdpServer(context, identity=None, address=None, #NOSONAR pylint: disabl :param custom_functions: An optional list of custom function classes supported by server instance. """ - from twisted.internet import reactor as local_reactor # pylint: disable=import-outside-toplevel,reimported + from twisted.internet import reactor as local_reactor # pylint: disable=import-outside-toplevel,reimported address = address or ("", Defaults.Port) framer = kwargs.pop("framer", ModbusSocketFramer) @@ -291,12 +290,13 @@ def StartUdpServer(context, identity=None, address=None, #NOSONAR pylint: disabl _logger.info(txt) local_reactor.listenUDP(address[1], server, interface=address[0]) # pylint: disable=no-member if not defer_reactor_run: - local_reactor.run(installSignalHandlers=_is_main_thread()) # pylint: disable=no-member + local_reactor.run(installSignalHandlers=_is_main_thread()) # pylint: disable=no-member -def StartSerialServer(context, identity=None, framer=ModbusAsciiFramer, #NOSONAR pylint: disable=invalid-name,dangerous-default-value +def StartSerialServer(context, # NOSONAR pylint: disable=invalid-name,dangerous-default-value + identity=None, framer=ModbusAsciiFramer, defer_reactor_run=False, custom_functions=[], **kwargs): - """ Helper method to start the Modbus Async Serial server + """Start the Modbus Async Serial server. :param context: The server data context :param identify: The server identity to use (default empty) @@ -312,8 +312,8 @@ def StartSerialServer(context, identity=None, framer=ModbusAsciiFramer, #NOSONAR supported by server instance. """ - from twisted.internet import reactor as local_reactor # pylint: disable=import-outside-toplevel,reimported - from twisted.internet.serialport import SerialPort # pylint: disable=import-outside-toplevel + from twisted.internet import reactor as local_reactor # pylint: disable=import-outside-toplevel,reimported + from twisted.internet.serialport import SerialPort # pylint: disable=import-outside-toplevel port = kwargs.get('port', '/dev/ttyS0') baudrate = kwargs.get('baudrate', Defaults.Baudrate) @@ -332,21 +332,22 @@ def StartSerialServer(context, identity=None, framer=ModbusAsciiFramer, #NOSONAR local_protocol = factory.buildProtocol(None) SerialPort.getHost = lambda self: port # hack for logging - SerialPort(local_protocol, port, local_reactor, baudrate=baudrate, parity=parity, # pylint: disable=unexpected-keyword-arg + SerialPort(local_protocol, # pylint: disable=unexpected-keyword-arg + port, local_reactor, baudrate=baudrate, parity=parity, stopbits=stopbits, timeout=timeout, xonxoff=xonxoff, rtscts=rtscts, bytesize=bytesize) if not defer_reactor_run: - local_reactor.run(installSignalHandlers=_is_main_thread()) # pylint: disable=no-member + local_reactor.run(installSignalHandlers=_is_main_thread()) # pylint: disable=no-member -def StopServer(): #NOSONAR pylint: disable=invalid-name - """ Helper method to stop Async Server. """ - from twisted.internet import reactor as local_reactor # pylint: disable=import-outside-toplevel,reimported +def StopServer(): # NOSONAR pylint: disable=invalid-name + """Stop Async Server.""" + from twisted.internet import reactor as local_reactor # pylint: disable=import-outside-toplevel,reimported if _is_main_thread(): local_reactor.stop() _logger.debug("Stopping server from main thread") else: - local_reactor.callFromThread(local_reactor.stop) # pylint: disable=no-member + local_reactor.callFromThread(local_reactor.stop) # pylint: disable=no-member _logger.debug("Stopping Server from another thread") diff --git a/pymodbus/server/reactive/__init__.py b/pymodbus/server/reactive/__init__.py index 8feb11bcc..2640ad12f 100644 --- a/pymodbus/server/reactive/__init__.py +++ b/pymodbus/server/reactive/__init__.py @@ -1,3 +1,5 @@ -""" Copyright (c) 2020 by RiptideIO +"""Initialize. + +Copyright (c) 2020 by RiptideIO All rights reserved. """ diff --git a/pymodbus/server/reactive/default_config.py b/pymodbus/server/reactive/default_config.py index eac02dda9..0dbad5d66 100644 --- a/pymodbus/server/reactive/default_config.py +++ b/pymodbus/server/reactive/default_config.py @@ -1,36 +1,38 @@ -""" Copyright (c) 2020 by RiptideIO +"""Default config. + +Copyright (c) 2020 by RiptideIO All rights reserved. """ -DEFUALT_CONFIG = { # pylint: disable=consider-using-namedtuple-or-dataclass - "tcp": { - "handler": "ModbusConnectedRequestHandler", - "allow_reuse_address": True, - "allow_reuse_port": True, - "backlog": 20, - "ignore_missing_slaves": False - }, - "serial": { - "handler": "ModbusSingleRequestHandler", - "stopbits": 1, - "bytesize": 8, - "parity": "N", - "baudrate": 9600, - "timeout": 3, - "auto_reconnect": False, - "reconnect_delay": 2 - }, - "tls": { - "handler": "ModbusConnectedRequestHandler", - "certfile": None, - "keyfile": None, - "allow_reuse_address": True, - "allow_reuse_port": True, - "backlog": 20, - "ignore_missing_slaves": False - }, - "udp": { - "handler": "ModbusDisonnectedRequestHandler", - "ignore_missing_slaves": False - } +DEFUALT_CONFIG = { # pylint: disable=consider-using-namedtuple-or-dataclass + "tcp": { + "handler": "ModbusConnectedRequestHandler", + "allow_reuse_address": True, + "allow_reuse_port": True, + "backlog": 20, + "ignore_missing_slaves": False + }, + "serial": { + "handler": "ModbusSingleRequestHandler", + "stopbits": 1, + "bytesize": 8, + "parity": "N", + "baudrate": 9600, + "timeout": 3, + "auto_reconnect": False, + "reconnect_delay": 2 + }, + "tls": { + "handler": "ModbusConnectedRequestHandler", + "certfile": None, + "keyfile": None, + "allow_reuse_address": True, + "allow_reuse_port": True, + "backlog": 20, + "ignore_missing_slaves": False + }, + "udp": { + "handler": "ModbusDisonnectedRequestHandler", + "ignore_missing_slaves": False + } } diff --git a/pymodbus/server/reactive/main.py b/pymodbus/server/reactive/main.py index 9333c8333..39f583aac 100644 --- a/pymodbus/server/reactive/main.py +++ b/pymodbus/server/reactive/main.py @@ -1,4 +1,6 @@ -""" Copyright (c) 2020 by RiptideIO +"""Reactive main. + +Copyright (c) 2020 by RiptideIO All rights reserved. """ import os @@ -10,7 +12,7 @@ try: from aiohttp import web -except ImportError as e: +except ImportError: print("Reactive server requires aiohttp. " "Please install with 'pip install aiohttp' and try again.") sys.exit(1) @@ -86,10 +88,13 @@ class ReactiveServer: - """ Modbus Asynchronous Server which can manipulate the response dynamically. + """Modbus Asynchronous Server which can manipulate the response dynamically. + Useful for testing """ + def __init__(self, host, port, modbus_server, loop=None): + """Initialize.""" self._web_app = web.Application() self._runner = web.AppRunner(self._web_app) self._host = host @@ -105,12 +110,12 @@ def __init__(self, host, port, modbus_server, loop=None): @property def web_app(self): - """ Start web_app. """ + """Start web_app.""" return self._web_app @property def manipulator_config(self): - """ Manipulate config. """ + """Manipulate config.""" return self._manipulator_config @manipulator_config.setter @@ -119,12 +124,13 @@ def manipulator_config(self, value): self._manipulator_config.update(**value) def _add_routes(self): - """ Internal add routes. """ + """Add routes.""" self._web_app.add_routes([ web.post('/', self._response_manipulator)]) async def start_modbus_server(self, app): - """ Start Modbus server as asyncio task after startup + """Start Modbus server as asyncio task after startup. + :param app: Webapp :return: """ @@ -144,12 +150,13 @@ async def start_modbus_server(self, app): self._modbus_server.serve_forever()) logger.info("Modbus server started") - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except logger.error("Error starting modbus server") logger.error(exc) async def stop_modbus_server(self, app): - """ Stop modbus server + """Stop modbus server. + :param app: Webapp :return: """ @@ -161,7 +168,8 @@ async def stop_modbus_server(self, app): logger.info("Modbus server Stopped") async def _response_manipulator(self, request): - """ POST request Handler for response manipulation end point + """POST request Handler for response manipulation end point. + Payload is a dict with following fields :response_type : One among (normal, delayed, error, empty, stray) :error_code: Modbus error code for error response @@ -175,7 +183,8 @@ async def _response_manipulator(self, request): return web.json_response(data=data) def update_manipulator_config(self, config): - """ Updates manipulator config. Resets previous counters + """Update manipulator config. Resets previous counters. + :param config: Manipulator config (dict) :return: """ @@ -183,7 +192,8 @@ def update_manipulator_config(self, config): self._manipulator_config = config def manipulate_response(self, response): - """ Manipulates the actual response according to the required error state. + """Manipulate the actual response according to the required error state. + :param response: Modbus response object :return: Modbus response """ @@ -211,7 +221,7 @@ def manipulate_response(self, response): delay_by = self._manipulator_config.get("delay_by") txt = f"Delaying response by {delay_by}s for all incoming requests" logger.warning(txt) - time.sleep(delay_by) #change to async TODO pylint: disable:fixme + time.sleep(delay_by) # change to async TODO pylint: disable:fixme self._counter += 1 elif response_type == "empty": logger.warning("Sending empty response") @@ -228,7 +238,8 @@ def manipulate_response(self, response): return response, skip_encoding def run(self): - """ Run Web app + """Run Web app. + :return: """ def _info(message): @@ -239,23 +250,25 @@ def _info(message): print=_info) async def run_async(self): - """ Run Web app + """Run Web app. + :return: """ try: await self._runner.setup() site = web.TCPSite(self._runner, self._host, self._port) await site.start() - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except logger.error(exc) @classmethod def create_identity(cls, vendor="Pymodbus", product_code="PM", - vendor_url='http://github.com/riptideio/pymodbus/', #NOSONAR + vendor_url='http://github.com/riptideio/pymodbus/', # NOSONAR product_name="Pymodbus Server", model_name="Reactive Server", version=pymodbus_version.short()): - """ Create modbus identity + """Create modbus identity. + :param vendor: :param product_code: :param vendor_url: @@ -264,7 +277,7 @@ def create_identity(cls, vendor="Pymodbus", product_code="PM", :param version: :return: ModbusIdentity object """ - identity = ModbusDeviceIdentification(info_name= { + identity = ModbusDeviceIdentification(info_name={ 'VendorName': vendor, 'ProductCode': product_code, 'VendorUrl': vendor_url, @@ -278,7 +291,8 @@ def create_identity(cls, vendor="Pymodbus", product_code="PM", @classmethod def create_context(cls, data_block=None, unit=1, single=False): - """ Create Modbus context. + """Create Modbus context. + :param data_block: Datablock (dict) Refer DEFAULT_DATA_BLOCK :param unit: Unit id for the slave :param single: To run as a single slave @@ -290,18 +304,18 @@ def create_context(cls, data_block=None, unit=1, start_address = block_desc.get("start_address", 0) default_count = block_desc.get("count", 0) default_value = block_desc.get("value", 0) - default_values = [default_value]*default_count + default_values = [default_value] * default_count sparse = block_desc.get("sparse", False) db = ModbusSequentialDataBlock if not sparse else ModbusSparseDataBlock if sparse: if not (address_map := block_desc.get("address_map")): - address_map = random.sample( #NOSONAR - range(start_address+1, default_count), default_count-1) + address_map = random.sample( # NOSONAR + range(start_address + 1, default_count), default_count - 1) address_map.insert(0, 0) block[modbus_entity] = {add: val for add in sorted(address_map) - for val in default_values} + for val in default_values} else: - block[modbus_entity] =db(start_address, default_values) + block[modbus_entity] = db(start_address, default_values) slave_context = ModbusSlaveContext(**block, zero_mode=True) if not single: @@ -314,10 +328,12 @@ def create_context(cls, data_block=None, unit=1, return server_context @classmethod - def factory(cls, server, framer=None, context=None, unit=1, single=False, # pylint: disable=dangerous-default-value,too-many-arguments + def factory(cls, server, framer=None, context=None, # pylint: disable=dangerous-default-value,too-many-arguments + unit=1, single=False, host="localhost", modbus_port=5020, web_port=8080, data_block=DEFAULT_DATA_BLOCK, identity=None, loop=None, **kwargs): - """ Factory to create ReactiveModbusServer + """Create ReactiveModbusServer. + :param server: Modbus server type (tcp, rtu, tls, udp) :param framer: Modbus framer (ModbusSocketFramer, ModbusRTUFramer, ModbusTLSFramer) :param context: Modbus server context to use diff --git a/pymodbus/server/sync.py b/pymodbus/server/sync.py index a1401b027..1c1495448 100644 --- a/pymodbus/server/sync.py +++ b/pymodbus/server/sync.py @@ -1,7 +1,4 @@ -""" Implementation of a Threaded Modbus Server ------------------------------------------- - -""" +"""Implementation of a Threaded Modbus Server.""" import logging import traceback from binascii import b2a_hex @@ -31,16 +28,17 @@ # --------------------------------------------------------------------------- # class ModbusBaseRequestHandler(socketserver.BaseRequestHandler): - """ Implements the modbus server protocol + """Implements the modbus server protocol This uses the socketserver.BaseRequestHandler to implement the client handler. """ + running = False framer = None def setup(self): - """ Callback for when a client connects.""" + """Call when a client connects.""" txt = f"Client Connected [{self.client_address}]" _logger.debug(txt) self.running = True @@ -48,13 +46,13 @@ def setup(self): self.server.threads.append(self) def finish(self): - """ Callback for when a client disconnects. """ + """Call when a client disconnects.""" txt = f"Client Disconnected [{self.client_address}]" _logger.debug(txt) self.server.threads.remove(self) def execute(self, request): - """ The callback to call with the resulting message + """Call with the resulting message. :param request: The decoded request message """ @@ -74,7 +72,7 @@ def execute(self, request): if self.server.ignore_missing_slaves: return # the client will simply timeout waiting for a response response = request.doException(merror.GatewayNoResponse) - except Exception as exc: # pylint: disable=broad-except + except Exception as exc: # pylint: disable=broad-except _logger.debug("Datastore unable to fulfill request: " "%s; %s", exc, traceback.format_exc()) response = request.doException(merror.SlaveFailure) @@ -88,12 +86,12 @@ def execute(self, request): # Base class implementations # ----------------------------------------------------------------------- # def handle(self): - """ Callback when we receive any data. """ + """Call when we receive any data.""" raise NotImplementedException("Method not implemented" " by derived class") - def send(self, message): # pylint: disable=no-self-use - """ Send a request (string) to the network + def send(self, message): # pylint: disable=no-self-use + """Send a request (string) to the network. :param message: The unencoded modbus response """ @@ -102,14 +100,14 @@ def send(self, message): # pylint: disable=no-self-use class ModbusSingleRequestHandler(ModbusBaseRequestHandler): - """ Implements the modbus server protocol + """Implements the modbus server protocol. This uses the socketserver.BaseRequestHandler to implement the client handler for a single client(serial clients) """ + def handle(self): - """ Callback when we receive any data - """ + """Call when we receive any data.""" while self.running: try: if data := self.request.recv(1024): @@ -123,7 +121,7 @@ def handle(self): single = self.server.context.single self.framer.processIncomingPacket(data, self.execute, units, single=single) - except Exception as msg: # pylint: disable=broad-except + except Exception as msg: # pylint: disable=broad-except # Since we only have a single socket, we cannot exit # Clear frame buffer self.framer.resetFrame() @@ -131,7 +129,7 @@ def handle(self): _logger.debug(txt) def send(self, message): - """ Send a request (string) to the network + """Send a request (string) to the network. :param message: The unencoded modbus response """ @@ -146,9 +144,9 @@ def send(self, message): class CustomSingleRequestHandler(ModbusSingleRequestHandler): - """ Handle single request. """ + """Handle single request.""" - def __init__(self, request, client_address, server): # pylint: disable=super-init-not-called + def __init__(self, request, client_address, server): # pylint: disable=super-init-not-called self.request = request self.client_address = client_address self.server = server @@ -157,14 +155,16 @@ def __init__(self, request, client_address, server): # pylint: disable=super-ini class ModbusConnectedRequestHandler(ModbusBaseRequestHandler): - """ Implements the modbus server protocol + """Implements the modbus server protocol. This uses the socketserver.BaseRequestHandler to implement the client handler for a connected protocol (TCP). """ - def handle(self): # pylint: disable=too-complex - """ Callback when we receive any data, until self.running becomes False. + def handle(self): # pylint: disable=too-complex + """Call when we receive any data. + + until self.running becomes False. Blocks indefinitely awaiting data. If shutdown is required, then the global socket.settimeout() may be used, to allow timely checking of self.running. However, since this also affects socket @@ -181,7 +181,7 @@ def handle(self): # pylint: disable=too-complex """ reset_frame = False - while self.running: # pylint: disable=too-many-nested-blocks + while self.running: # pylint: disable=too-many-nested-blocks try: units = self.server.context.slaves() if not (data := self.request.recv(1024)): @@ -220,7 +220,7 @@ def handle(self): # pylint: disable=too-complex reset_frame = False def send(self, message): - """ Send a request (string) to the network + """Send a request (string) to the network. :param message: The unencoded modbus response """ @@ -235,17 +235,18 @@ def send(self, message): class ModbusDisconnectedRequestHandler(ModbusBaseRequestHandler): - """ Implements the modbus server protocol + """Implements the modbus server protocol This uses the socketserver.BaseRequestHandler to implement the client handler for a disconnected protocol (UDP). The only difference is that we have to specify who to send the resulting packet data to. """ + socket = None def handle(self): - """ Callback when we receive any data. """ + """Call when we receive any data.""" reset_frame = False while self.running: try: @@ -268,7 +269,7 @@ def handle(self): _logger.error(txt) self.running = False reset_frame = True - except Exception as msg: # pylint: disable=broad-except + except Exception as msg: # pylint: disable=broad-except _logger.error(msg) self.running = False reset_frame = True @@ -280,12 +281,11 @@ def handle(self): reset_frame = False def send(self, message): - """ Send a request (string) to the network + """Send a request (string) to the network. :param message: The unencoded modbus response """ if message.should_respond: - #self.server.control.Counter.BusMessage += 1 pdu = self.framer.buildPacket(message) if _logger.isEnabledFor(logging.DEBUG): txt = f"send: [{message}]- {b2a_hex(pdu)}" @@ -296,8 +296,10 @@ def send(self, message): # --------------------------------------------------------------------------- # # Server Implementations # --------------------------------------------------------------------------- # + + class ModbusTcpServer(socketserver.ThreadingTCPServer): - """ A modbus threaded tcp socket server + """A modbus threaded tcp socket server. We inherit and overload the socket server so that we can control the client threads as well as have a single @@ -307,7 +309,7 @@ class ModbusTcpServer(socketserver.ThreadingTCPServer): def __init__(self, context, framer=None, identity=None, address=None, handler=None, allow_reuse_address=False, **kwargs): - """ Overloaded initializer for the socket server + """Initialize the socket server. If the identify structure is not passed in, the ModbusControlBlock uses its own empty structure. @@ -346,7 +348,7 @@ def __init__(self, context, framer=None, identity=None, **kwargs) def process_request(self, request, client_address): - """ Callback for connecting a new client thread + """Call for connecting a new client thread. :param request: The request to handle :param client: The address of the client @@ -356,7 +358,7 @@ def process_request(self, request, client_address): socketserver.ThreadingTCPServer.process_request(self, request, client_address) def shutdown(self): - """ Stops the serve_forever loop. + """Stop the serve_forever loop. Overridden to signal handlers to stop. """ @@ -365,8 +367,7 @@ def shutdown(self): socketserver.ThreadingTCPServer.shutdown(self) def server_close(self): - """ Callback for stopping the running server - """ + """Call for stopping the running server.""" _logger.debug("Modbus server stopped") self.socket.close() for thread in self.threads: @@ -374,18 +375,18 @@ def server_close(self): class ModbusTlsServer(ModbusTcpServer): - """ A modbus threaded TLS server + """A modbus threaded TLS server. We inherit and overload the ModbusTcpServer so that we can control the client threads as well as have a single server context instance. """ - def __init__(self, context, framer=None, identity=None, address=None, # pylint: disable=too-many-arguments + def __init__(self, context, framer=None, identity=None, address=None, # pylint: disable=too-many-arguments sslctx=None, certfile=None, keyfile=None, password=None, reqclicert=False, handler=None, allow_reuse_address=False, **kwargs): - """ Overloaded initializer for the ModbusTcpServer + """Initialize the ModbusTlsServer. If the identify structure is not passed in, the ModbusControlBlock uses its own empty structure. @@ -417,13 +418,13 @@ def __init__(self, context, framer=None, identity=None, address=None, # pylint: handler, allow_reuse_address, **kwargs) def server_activate(self): - """ Callback for starting listening over TLS connection. """ + """Call for starting listening over TLS connection.""" self.socket = self.sslctx.wrap_socket(self.socket, server_side=True) socketserver.ThreadingTCPServer.server_activate(self) class ModbusUdpServer(socketserver.ThreadingUDPServer): - """ A modbus threaded udp socket server + """A modbus threaded udp socket server. We inherit and overload the socket server so that we can control the client threads as well as have a single @@ -432,7 +433,7 @@ class ModbusUdpServer(socketserver.ThreadingUDPServer): def __init__(self, context, framer=None, identity=None, address=None, handler=None, **kwargs): - """ Overloaded initializer for the socket server + """Initialize the socket server. If the identify structure is not passed in, the ModbusControlBlock uses its own empty structure. @@ -450,7 +451,7 @@ def __init__(self, context, framer=None, identity=None, address=None, """ self.threads = [] self.decoder = ServerDecoder() - self.framer = framer or ModbusSocketFramer + self.framer = framer or ModbusSocketFramer self.context = context or ModbusServerContext() self.control = ModbusControlBlock() self.address = address or ("", Defaults.Port) @@ -464,30 +465,30 @@ def __init__(self, context, framer=None, identity=None, address=None, self.control.Identity.update(identity) socketserver.ThreadingUDPServer.__init__(self, - self.address, self.handler, **kwargs) + self.address, self.handler, **kwargs) # self._BaseServer__shutdown_request = True def process_request(self, request, client_address): - """ Callback for connecting a new client thread + """Call for connecting a new client thread. :param request: The request to handle :param client: The address of the client """ - _, _ = request # TODO I might have to rewrite # pylint: disable=fixme + _, _ = request # TODO I might have to rewrite # pylint: disable=fixme txt = f"Started thread to serve client at {client_address}" _logger.debug(txt) socketserver.ThreadingUDPServer.process_request(self, request, client_address) def server_close(self): - """ Callback for stopping the running server. """ + """Call for stopping the running server.""" _logger.debug("Modbus server stopped") self.socket.close() for thread in self.threads: thread.running = False -class ModbusSerialServer: # pylint: disable=too-many-instance-attributes - """ A modbus threaded serial socket server +class ModbusSerialServer: # pylint: disable=too-many-instance-attributes + """A modbus threaded serial socket server. We inherit and overload the socket server so that we can control the client threads as well as have a single @@ -497,7 +498,7 @@ class ModbusSerialServer: # pylint: disable=too-many-instance-attributes handler = None def __init__(self, context, framer=None, identity=None, **kwargs): - """ Overloaded initializer for the socket server + """Initialize the socket server. If the identify structure is not passed in, the ModbusControlBlock uses its own empty structure. @@ -528,9 +529,9 @@ def __init__(self, context, framer=None, identity=None, **kwargs): self.device = kwargs.get('port', 0) self.stopbits = kwargs.get('stopbits', Defaults.Stopbits) self.bytesize = kwargs.get('bytesize', Defaults.Bytesize) - self.parity = kwargs.get('parity', Defaults.Parity) + self.parity = kwargs.get('parity', Defaults.Parity) self.baudrate = kwargs.get('baudrate', Defaults.Baudrate) - self.timeout = kwargs.get('timeout', Defaults.Timeout) + self.timeout = kwargs.get('timeout', Defaults.Timeout) self.ignore_missing_slaves = kwargs.get('ignore_missing_slaves', Defaults.IgnoreMissingSlaves) self.broadcast_enable = kwargs.get('broadcast_enable', @@ -542,7 +543,7 @@ def __init__(self, context, framer=None, identity=None, **kwargs): CustomSingleRequestHandler)) def _connect(self): - """ Connect to the serial server + """Connect to the serial server. :returns: True if connection succeeded, False otherwise """ @@ -560,8 +561,8 @@ def _connect(self): return self.socket is not None def _build_handler(self, handler): - """ A helper method to create and monkeypatch - a serial handler. + """Create and monkeypatch a serial handler. + :param handler: a custom handler, uses ModbusSingleRequestHandler if set to None :returns: A patched handler @@ -574,8 +575,7 @@ def _build_handler(self, handler): self) def serve_forever(self): - """ Callback for connecting a new client thread - """ + """Call for connecting a new client thread.""" if self._connect(): _logger.debug("Started thread to serve client") if not self.handler: @@ -590,8 +590,7 @@ def serve_forever(self): "Unable to start server!!") def server_close(self): - """ Callback for stopping the running server - """ + """Call for stopping the running server.""" _logger.debug("Modbus server stopped") self.is_running = False self.handler.finish() @@ -603,9 +602,9 @@ def server_close(self): # --------------------------------------------------------------------------- # # Creation Factories # --------------------------------------------------------------------------- # -def StartTcpServer(context=None, identity=None, address=None, # pylint: disable=invalid-name,dangerous-default-value +def StartTcpServer(context=None, identity=None, address=None, # pylint: disable=invalid-name,dangerous-default-value custom_functions=[], **kwargs): - """ A factory to start and run a tcp modbus server + """Start and run a tcp modbus server. :param context: The ModbusServerContext datastore :param identity: An optional identify structure @@ -623,10 +622,11 @@ def StartTcpServer(context=None, identity=None, address=None, # pylint: disable= server.serve_forever() -def StartTlsServer(context=None, identity=None, address=None, sslctx=None, # pylint: disable=invalid-name,dangerous-default-value +def StartTlsServer(context=None, # NOSONAR pylint: disable=invalid-name,dangerous-default-value + identity=None, address=None, sslctx=None, certfile=None, keyfile=None, password=None, reqclicert=False, custom_functions=[], **kwargs): - """ A factory to start and run a tls modbus server + """Start and run a tls modbus server. :param context: The ModbusServerContext datastore :param identity: An optional identify structure @@ -650,9 +650,9 @@ def StartTlsServer(context=None, identity=None, address=None, sslctx=None, # pyl server.serve_forever() -def StartUdpServer(context=None, identity=None, address=None, # pylint: disable=invalid-name,dangerous-default-value +def StartUdpServer(context=None, identity=None, address=None, # pylint: disable=invalid-name,dangerous-default-value custom_functions=[], **kwargs): - """ A factory to start and run a udp modbus server + """Start and run a udp modbus server. :param context: The ModbusServerContext datastore :param identity: An optional identify structure @@ -670,9 +670,10 @@ def StartUdpServer(context=None, identity=None, address=None, # pylint: disable= server.serve_forever() -def StartSerialServer(context=None, identity=None, custom_functions=[], # pylint: disable=invalid-name, dangerous-default-value +def StartSerialServer(context=None, # pylint: disable=invalid-name, dangerous-default-value + identity=None, custom_functions=[], **kwargs): - """ A factory to start and run a serial modbus server + """Start and run a serial modbus server. :param context: The ModbusServerContext datastore :param identity: An optional identify structure diff --git a/pymodbus/server/tls_helper.py b/pymodbus/server/tls_helper.py index 8b970711c..28e45cc35 100644 --- a/pymodbus/server/tls_helper.py +++ b/pymodbus/server/tls_helper.py @@ -1,12 +1,10 @@ -""" TLS helper for Modbus TLS Server ------------------------------------------- - -""" +"""TLS helper for Modbus TLS Server.""" import ssl + def sslctx_provider(sslctx=None, certfile=None, keyfile=None, password=None, reqclicert=False): - """ Provide the SSLContext for ModbusTlsServer + """Provide the SSLContext for ModbusTlsServer. If the user defined SSLContext is not passed in, sslctx_provider will produce a default one. diff --git a/pymodbus/transaction.py b/pymodbus/transaction.py index 814848860..d646b48e8 100644 --- a/pymodbus/transaction.py +++ b/pymodbus/transaction.py @@ -1,6 +1,4 @@ -""" Collection of transaction based abstractions - -""" +"""Collection of transaction based abstractions.""" import logging import struct @@ -30,7 +28,7 @@ # The Global Transaction Manager # --------------------------------------------------------------------------- # class ModbusTransactionManager: - """ Implements a transaction for a manager + """Implement a transaction for a manager. The transaction protocol can be represented by the following pseudo code:: @@ -46,7 +44,7 @@ class ModbusTransactionManager: """ def __init__(self, client, **kwargs): - """ Initializes an instance of the ModbusTransactionManager + """Initialize an instance of the ModbusTransactionManager. :param client: The client socket wrapper :param retry_on_empty: Should the client retry on empty @@ -67,7 +65,7 @@ def __init__(self, client, **kwargs): self._set_adu_size() def _set_adu_size(self): - """ Internal set adu size. """ + """Set adu size.""" # base ADU size of modbus frame in bytes if isinstance(self.client.framer, ModbusSocketFramer): self.base_adu_size = 7 # tid(2), pid(2), length(2), uid(1) @@ -83,27 +81,26 @@ def _set_adu_size(self): self.base_adu_size = -1 def _calculate_response_length(self, expected_pdu_size): - """ Internal calculate response length. """ + """Calculate response length.""" if self.base_adu_size == -1: return None return self.base_adu_size + expected_pdu_size def _calculate_exception_length(self): - """ Returns the length of the Modbus Exception Response according to - the type of Framer. - """ + """Return the length of the Modbus Exception Response according to the type of Framer.""" if isinstance(self.client.framer, (ModbusSocketFramer, ModbusTlsFramer)): return self.base_adu_size + 2 # Fcode(1), ExcecptionCode(1) if isinstance(self.client.framer, ModbusAsciiFramer): return self.base_adu_size + 4 # Fcode(2), ExcecptionCode(2) if isinstance(self.client.framer, (ModbusRtuFramer, - ModbusBinaryFramer)): + ModbusBinaryFramer)): return self.base_adu_size + 2 # Fcode(1), ExcecptionCode(1) return None def _validate_response(self, request, response, exp_resp_len): - """ Validate Incoming response against request + """Validate Incoming response against request. + :param request: Request sent :param response: Response received :param exp_resp_len: Expected response length @@ -120,26 +117,22 @@ def _validate_response(self, request, response, exp_resp_len): return mbap.get('length') == exp_resp_len return True - def execute(self, request): #NOSONAR pylint: disable=too-complex - """ Starts the producer to send the next request to - consumer.write(Frame(request)) - """ + def execute(self, request): # NOSONAR pylint: disable=too-complex + """Start the producer to send the next request to consumer.write(Frame(request)).""" with self._transaction_lock: try: txt = ("Current transaction state - " - f"{ModbusTransactionState.to_string(self.client.state)}") + f"{ModbusTransactionState.to_string(self.client.state)}") _logger.debug(txt) retries = self.retries request.transaction_id = self.getNextTID() txt = f"Running transaction {request.transaction_id}" _logger.debug(txt) - if (_buffer := hexlify_packets(self.client.framer._buffer)): # pylint: disable=protected-access + if (_buffer := hexlify_packets(self.client.framer._buffer)): # pylint: disable=protected-access txt = f"Clearing current Frame: - {_buffer}" _logger.debug(txt) self.client.framer.resetFrame() - broadcast = (self.client.broadcast_enable - and not request.unit_id) - if broadcast: + if (broadcast := (self.client.broadcast_enable and not request.unit_id)): self._transact(request, None, broadcast=True) response = b'Broadcast write sent - no response expected' else: @@ -152,7 +145,7 @@ def execute(self, request): #NOSONAR pylint: disable=too-complex if response_pdu_size: expected_response_length = self._calculate_response_length( response_pdu_size) - if request.unit_id in self._no_response_devices: # pylint: disable=simplifiable-if-statement + if request.unit_id in self._no_response_devices: # pylint: disable=simplifiable-if-statement full = True else: full = False @@ -188,13 +181,13 @@ def execute(self, request): #NOSONAR pylint: disable=too-complex break elif self.retry_on_invalid: response, last_exception = self._retry_transaction( - retries, "invalid", - request, expected_response_length, full=full) + retries, "invalid", + request, expected_response_length, full=full) retries -= 1 else: break # full = False - addTransaction = partial(self.addTransaction, #NOSONAR pylint: disable=invalid-name + addTransaction = partial(self.addTransaction, # NOSONAR pylint: disable=invalid-name tid=request.transaction_id) self.client.framer.processIncomingPacket(response, addTransaction, @@ -228,7 +221,7 @@ def execute(self, request): #NOSONAR pylint: disable=too-complex def _retry_transaction(self, retries, reason, packet, response_length, full=False): - """ Internal retry transaction. """ + """Retry transaction.""" txt = f"Retry on {reason} response - {retries}" _logger.debug(txt) _logger.debug("Changing transaction state from " @@ -241,15 +234,16 @@ def _retry_transaction(self, retries, reason, _logger.debug(txt) self.client.connect() if hasattr(self.client, "_in_waiting"): - if (in_waiting := self.client._in_waiting()): # pylint: disable=protected-access + if (in_waiting := self.client._in_waiting()): # pylint: disable=protected-access if response_length == in_waiting: result = self._recv(response_length, full) return result, None return self._transact(packet, response_length, full=full) - def _transact(self, packet, response_length, # pylint: disable=too-complex + def _transact(self, packet, response_length, # pylint: disable=too-complex full=False, broadcast=False): - """ Does a Write and Read transaction + """Do a Write and Read transaction. + :param packet: packet to be sent :param response_length: Expected response length :param full: the target device was notorious for its no response. Dont @@ -280,7 +274,7 @@ def _transact(self, packet, response_length, # pylint: disable=too-complex "to 'WAITING FOR REPLY'") self.client.state = ModbusTransactionState.WAITING_FOR_REPLY if hasattr(self.client, "handle_local_echo") and self.client.handle_local_echo is True: - if (local_echo_packet := self._recv(size, full)) != packet: + if self._recv(size, full) != packet: return b'', "Wrong local echo" result = self._recv(response_length, full) # result2 = self._recv(response_length, full) @@ -298,12 +292,12 @@ def _transact(self, packet, response_length, # pylint: disable=too-complex result = b'' return result, last_exception - def _send(self, packet, retrying=False): #NOSONAR pylint: disable=unused-argument - """ Internal send. """ + def _send(self, packet, retrying=False): # NOSONAR pylint: disable=unused-argument + """Send.""" return self.client.framer.sendPacket(packet) - def _recv(self, expected_response_length, full): #NOSONAR pylint: disable=too-complex - """ Internal receive. """ + def _recv(self, expected_response_length, full): # NOSONAR pylint: disable=too-complex + """Receive.""" total = None if not full: exception_length = self._calculate_exception_length() @@ -340,7 +334,7 @@ def _recv(self, expected_response_length, full): #NOSONAR pylint: disable=too-co if func_code < 0x80: # Not an error if isinstance(self.client.framer, ModbusSocketFramer): # Omit UID, which is included in header size - h_size = self.client.framer._hsize # pylint: disable=protected-access + h_size = self.client.framer._hsize # pylint: disable=protected-access length = struct.unpack(">H", read_min[4:6])[0] - 1 expected_response_length = h_size + length if expected_response_length is not None: @@ -360,8 +354,8 @@ def _recv(self, expected_response_length, full): #NOSONAR pylint: disable=too-co if total is not None and actual != total: msg_start = "Incomplete message" if actual else "No response" txt = ("{msg_start} received, " - f"Expected {total} bytes Received " - f"{actual} bytes !!!!") + f"Expected {total} bytes Received " + f"{actual} bytes !!!!") _logger.debug(txt) elif not actual: # If actual == 0 and total is not None then the above @@ -373,8 +367,8 @@ def _recv(self, expected_response_length, full): #NOSONAR pylint: disable=too-co self.client.state = ModbusTransactionState.PROCESSING_REPLY return result - def addTransaction(self, request, tid=None): # pylint: disable=invalid-name,no-self-use - """ Adds a transaction to the handler + def addTransaction(self, request, tid=None): # pylint: disable=invalid-name,no-self-use + """Add a transaction to the handler. This holds the request in case it needs to be resent. After being sent, the request is removed. @@ -384,8 +378,8 @@ def addTransaction(self, request, tid=None): # pylint: disable=invalid-name,no-s """ raise NotImplementedException("addTransaction") - def getTransaction(self, tid): # pylint: disable=invalid-name,no-self-use - """ Returns a transaction matching the referenced tid + def getTransaction(self, tid): # pylint: disable=invalid-name,no-self-use + """Return a transaction matching the referenced tid. If the transaction does not exist, None is returned @@ -393,15 +387,15 @@ def getTransaction(self, tid): # pylint: disable=invalid-name,no-self-use """ raise NotImplementedException("getTransaction") - def delTransaction(self, tid): # pylint: disable=invalid-name,no-self-use - """ Removes a transaction matching the referenced tid + def delTransaction(self, tid): # pylint: disable=invalid-name,no-self-use + """Remove a transaction matching the referenced tid. :param tid: The transaction to remove """ raise NotImplementedException("delTransaction") - def getNextTID(self): # pylint: disable=invalid-name - """ Retrieve the next unique transaction identifier + def getNextTID(self): # pylint: disable=invalid-name + """Retrieve the next unique transaction identifier. This handles incrementing the identifier after retrieval @@ -412,18 +406,19 @@ def getNextTID(self): # pylint: disable=invalid-name return self.tid def reset(self): - """ Resets the transaction identifier """ + """Reset the transaction identifier.""" self.tid = Defaults.TransactionId - self.transactions = type(self.transactions)() # pylint: disable=attribute-defined-outside-init + self.transactions = type(self.transactions)() # pylint: disable=attribute-defined-outside-init class DictTransactionManager(ModbusTransactionManager): - """ Implements a transaction for a manager where the - results are keyed based on the supplied transaction id. + """Implements a transaction for a manager. + + Where the results are keyed based on the supplied transaction id. """ def __init__(self, client, **kwargs): - """ Initializes an instance of the ModbusTransactionManager + """Initialize an instance of the ModbusTransactionManager. :param client: The client socket wrapper """ @@ -431,14 +426,14 @@ def __init__(self, client, **kwargs): super().__init__(client, **kwargs) def __iter__(self): - """ Iterator over the current managed transactions + """Iterate over the current managed transactions. :returns: An iterator of the managed transactions """ return iter(self.transactions.keys()) def addTransaction(self, request, tid=None): - """ Adds a transaction to the handler + """Add a transaction to the handler. This holds the requets in case it needs to be resent. After being sent, the request is removed. @@ -452,7 +447,7 @@ def addTransaction(self, request, tid=None): self.transactions[tid] = request def getTransaction(self, tid): - """ Returns a transaction matching the referenced tid + """Return a transaction matching the referenced tid. If the transaction does not exist, None is returned @@ -465,7 +460,7 @@ def getTransaction(self, tid): return self.transactions.pop(tid, None) def delTransaction(self, tid): - """ Removes a transaction matching the referenced tid + """Remove a transaction matching the referenced tid. :param tid: The transaction to remove """ @@ -476,12 +471,13 @@ def delTransaction(self, tid): class FifoTransactionManager(ModbusTransactionManager): - """ Implements a transaction for a manager where the - results are returned in a FIFO manner. + """Implements a transaction. + + For a manager where the results are returned in a FIFO manner. """ def __init__(self, client, **kwargs): - """ Initializes an instance of the ModbusTransactionManager + """Initialize an instance of the ModbusTransactionManager. :param client: The client socket wrapper """ @@ -489,14 +485,14 @@ def __init__(self, client, **kwargs): self.transactions = [] def __iter__(self): - """ Iterator over the current managed transactions + """Iterate over the current managed transactions. :returns: An iterator of the managed transactions """ return iter(self.transactions) def addTransaction(self, request, tid=None): - """ Adds a transaction to the handler + """Add a transaction to the handler. This holds the requets in case it needs to be resent. After being sent, the request is removed. @@ -511,7 +507,7 @@ def addTransaction(self, request, tid=None): self.transactions.append(request) def getTransaction(self, tid): - """ Returns a transaction matching the referenced tid + """Return a transaction matching the referenced tid. If the transaction does not exist, None is returned @@ -520,7 +516,7 @@ def getTransaction(self, tid): return self.transactions.pop(0) if self.transactions else None def delTransaction(self, tid): - """ Removes a transaction matching the referenced tid + """Remove a transaction matching the referenced tid. :param tid: The transaction to remove """ @@ -533,6 +529,7 @@ def delTransaction(self, tid): # Exported symbols # --------------------------------------------------------------------------- # + __all__ = [ "FifoTransactionManager", "DictTransactionManager", diff --git a/pymodbus/utilities.py b/pymodbus/utilities.py index 7f52df79a..2813be50a 100644 --- a/pymodbus/utilities.py +++ b/pymodbus/utilities.py @@ -1,5 +1,4 @@ -""" Modbus Utilities ------------------ +"""Modbus Utilities. A collection of utilities for packing data, unpacking data computing checksums, and decode checksums. @@ -7,8 +6,9 @@ import struct -class ModbusTransactionState: # pylint: disable=too-few-public-methods - """ Modbus Client States. """ +class ModbusTransactionState: # pylint: disable=too-few-public-methods + """Modbus Client States.""" + IDLE = 0 SENDING = 1 WAITING_FOR_REPLY = 2 @@ -40,8 +40,7 @@ def to_string(cls, state): # --------------------------------------------------------------------------- # def default(value): - """ Given a python object, return the default value - of that object. + """Return the default value of object. :param value: The value to get the default of :returns: The default value @@ -50,7 +49,8 @@ def default(value): def dict_property(store, index): - """ Helper to create class properties from a dictionary. + """Create class properties from a dictionary. + Basically this allows you to remove a lot of possible boilerplate code. @@ -76,7 +76,7 @@ def dict_property(store, index): # Bit packing functions # --------------------------------------------------------------------------- # def pack_bitstring(bits): - """ Creates a string out of an array of bits + """Create a string out of an array of bits. :param bits: A bit array @@ -103,7 +103,7 @@ def pack_bitstring(bits): def unpack_bitstring(string): - """ Creates bit array out of a string + """Create bit array out of a string. :param string: The modbus data packet to decode @@ -123,7 +123,8 @@ def unpack_bitstring(string): def make_byte_string(byte_string): - """ Returns byte string from a given string, python3 specific fix + """Return byte string from a given string, python3 specific fix. + :param s: :return: """ @@ -133,8 +134,10 @@ def make_byte_string(byte_string): # --------------------------------------------------------------------------- # # Error Detection Functions # --------------------------------------------------------------------------- # + + def __generate_crc16_table(): - """ Generates a crc16 lookup table + """Generate a crc16 lookup table. .. note:: This will only be generated once """ @@ -144,17 +147,20 @@ def __generate_crc16_table(): for _ in range(8): if (byte ^ crc) & 0x0001: crc = (crc >> 1) ^ 0xa001 - else: crc >>= 1 + else: + crc >>= 1 byte >>= 1 result.append(crc) return result + __crc16_table = __generate_crc16_table() -def computeCRC(data): #NOSONAR pylint: disable=invalid-name - """ Computes a crc16 on the passed in string. For modbus, - this is only used on the binary serial protocols (in this +def computeCRC(data): # NOSONAR pylint: disable=invalid-name + """Compute a crc16 on the passed in string. + + For modbus, this is only used on the binary serial protocols (in this case RTU). The difference between modbus's crc16 and a normal crc16 @@ -171,8 +177,8 @@ def computeCRC(data): #NOSONAR pylint: disable=invalid-name return swapped -def checkCRC(data, check): #NOSONAR pylint: disable=invalid-name - """ Checks if the data matches the passed in CRC +def checkCRC(data, check): # NOSONAR pylint: disable=invalid-name + """Check if the data matches the passed in CRC. :param data: The data to create a crc16 of :param check: The CRC to validate @@ -181,9 +187,10 @@ def checkCRC(data, check): #NOSONAR pylint: disable=invalid-name return computeCRC(data) == check -def computeLRC(data): #NOSONAR pylint: disable=invalid-name - """ Used to compute the longitudinal redundancy check - against a string. This is only used on the serial ASCII +def computeLRC(data): # NOSONAR pylint: disable=invalid-name + """Use to compute the longitudinal redundancy check against a string. + + This is only used on the serial ASCII modbus protocol. A full description of this implementation can be found in appendex B of the serial line modbus description. @@ -196,8 +203,8 @@ def computeLRC(data): #NOSONAR pylint: disable=invalid-name return lrc & 0xff -def checkLRC(data, check): #NOSONAR pylint: disable=invalid-name - """ Checks if the passed in data matches the LRC +def checkLRC(data, check): # NOSONAR pylint: disable=invalid-name + """Check if the passed in data matches the LRC. :param data: The data to calculate :param check: The LRC to validate @@ -206,8 +213,8 @@ def checkLRC(data, check): #NOSONAR pylint: disable=invalid-name return computeLRC(data) == check -def rtuFrameSize(data, byte_count_pos): #NOSONAR pylint: disable=invalid-name - """ Calculates the size of the frame based on the byte count. +def rtuFrameSize(data, byte_count_pos): # NOSONAR pylint: disable=invalid-name + """Calculate the size of the frame based on the byte count. :param data: The buffer containing the frame. :param byte_count_pos: The index of the byte count in the buffer. @@ -230,7 +237,8 @@ def rtuFrameSize(data, byte_count_pos): #NOSONAR pylint: disable=invalid-name def hexlify_packets(packet): - """ Returns hex representation of bytestring received + """Return hex representation of bytestring received. + :param packet: :return: """ @@ -238,6 +246,7 @@ def hexlify_packets(packet): return '' return " ".join([hex(int(x)) for x in packet]) + # --------------------------------------------------------------------------- # # Exported symbols # --------------------------------------------------------------------------- # diff --git a/pymodbus/version.py b/pymodbus/version.py index 1934af958..8df5ba460 100644 --- a/pymodbus/version.py +++ b/pymodbus/version.py @@ -1,5 +1,6 @@ -""" Handle the version information here; you should only have to -change the version tuple. +"""Handle the version information here. + +you should only have to change the version tuple. Since we are using twisted's version class, we can also query the svn version as well using the local .entries file. @@ -10,7 +11,7 @@ class Version: """Manage version.""" def __init__(self, package, major, minor, micro, pre=None): - """ Initialize + """Initialize. :param package: Name of the package that this is a version of. :param major: The major version number. @@ -25,15 +26,13 @@ def __init__(self, package, major, minor, micro, pre=None): self.pre = pre def short(self): - """ Return a string in canonical short version format - ...
-        """
+        """Return a string in canonical short version format: ...
."""
         if self.pre:
             return f'{self.major}.{self.minor}.{self.micro}.{self.pre}'
         return f'{self.major}.{self.minor}.{self.micro}'
 
     def __str__(self):
-        """ Returns a string representation of the object
+        """Return a string representation of the object.
 
         :returns: A string representation of this object
         """
diff --git a/setup.py b/setup.py
index aa0954f54..34f4c669a 100644
--- a/setup.py
+++ b/setup.py
@@ -27,8 +27,8 @@
 from pymodbus import __version__, __author__, __maintainer__
 
 CONSOLE_SCRIPTS = [
-            'pymodbus.console=pymodbus.repl.client.main:main'
-        ]
+    'pymodbus.console=pymodbus.repl.client.main:main'
+]
 CONSOLE_SCRIPTS.append('pymodbus.server=pymodbus.repl.server.main:server')
 with open('requirements.txt') as reqs:
     install_requires = [
diff --git a/setup_commands.py b/setup_commands.py
index e04a7be6c..526ede53d 100755
--- a/setup_commands.py
+++ b/setup_commands.py
@@ -1,3 +1,4 @@
+"""Setup commands."""
 import os
 import shutil
 import sys
@@ -8,25 +9,27 @@
 
 
 class BuildApiDocsCommand(Command):
-    """ Helper command to build the available api documents
+    """Helper command to build the available api documents.
+
     This scans all the subdirectories under api and runs the
     build.py script underneath trying to build the api
     documentation for the given format.
     """
+
     description = "build all the project's api documents"
     user_options = []
 
     def initialize_options(self):
-        """ options setup """
+        """Initialize options setup."""
         if not os.path.exists('./build'):
             os.mkdir('./build')
 
     def finalize_options(self):
-        """ options teardown """
+        """Finalize options teardown."""
         pass
 
     def run(self):
-        """ command runner """
+        """Run command."""
         old_cwd = os.getcwd()
         directories = (d for d in os.listdir('./doc/api') if not d.startswith('.'))
         for entry in directories:
@@ -36,10 +39,8 @@ def run(self):
 
 
 class DeepCleanCommand(Command):
-    """
-    Helper command to return the directory to a completely
-    clean state.
-    """
+    """Helper command to return the directory to a completely clean state."""
+
     description = "clean everything that we don't want"
     user_options = []
     trash = ['build', 'dist', 'pymodbus.egg-info',
@@ -47,19 +48,19 @@ class DeepCleanCommand(Command):
              ]
 
     def initialize_options(self):
-        """ options setup """
+        """Initialize options setup."""
         pass
 
     def finalize_options(self):
         pass
 
     def run(self):
-        """ command runner """
+        """Run command."""
         self._delete_pyc_files()
         self._delete_trash_dirs()
 
     def _delete_trash_dirs(self):
-        """ remove all directories created in building """
+        """Remove all directories created in building."""
         self._delete_pyc_files()
         for directory in self.trash:
             if os.path.exists(directory):
@@ -67,7 +68,7 @@ def _delete_trash_dirs(self):
 
     @staticmethod
     def _delete_pyc_files():
-        """ remove all python cache files """
+        """Remove all python cache files."""
         for root, dirs, files in os.walk('.'):
             for file in files:
                 if file.endswith('.pyc'):
@@ -75,15 +76,13 @@ def _delete_pyc_files():
 
 
 class LintCommand(Command):
-    """
-    Helper command to perform a lint scan of the
-    sourcecode and return the results.
-    """
+    """Helper command to perform a lint scan of the sourcecode and return the results."""
+
     description = "perform a lint scan of the code"
     user_options = []
 
     def initialize_options(self):
-        """ options setup """
+        """Initialize options setup."""
         if not os.path.exists('./build'):
             os.mkdir('./build')
 
@@ -91,7 +90,7 @@ def finalize_options(self):
         pass
 
     def run(self):
-        """ command runner """
+        """Run command."""
         scanners = [s for s in dir(self) if s.find('__try') >= 0]
         for scanner in scanners:
             if getattr(self, scanner)():
@@ -108,35 +107,35 @@ def _try_pyflakes(self):
 
     def _try_pychecker(self):
         try:
-            import pychecker
+            import pychecker  # noqa F401
             sys.argv = """pychecker pymodbus/*.py""".split()
-            main()
+            main()  # noqa F821
             return True
         except Exception:
             return False
 
     def _try_pylint(self):
         try:
-            import pylint
+            import pylint  # noqa F401
             sys.argv = """pylint pymodbus/*.py""".split()
-            main()
+            main()  # noqa F821
             return True
         except Exception:
             return False
 
 
 class Python3Command(Command):
-    """ Helper command to scan for potential python 3
-    errors.
+    """Helper command to scan for potential python 3 errors.
 
     ./setup.py scan_2to3 > build/diffs_2to3 build/report_2to3
     """
+
     description = "perform 2to3 scan of the code"
     user_options = []
     directories = ['pymodbus', 'test', 'examples']
 
     def initialize_options(self):
-        """ options setup """
+        """Initialize options setup."""
         if not os.path.exists('./build'):
             os.mkdir('./build')
 
@@ -144,7 +143,7 @@ def finalize_options(self):
         pass
 
     def run(self):
-        """ command runner """
+        """Run command"""
         self._run_python3()
 
     def _run_python3(self):
@@ -158,15 +157,14 @@ def _run_python3(self):
 
 
 class Pep8Command(Command):
-    """
-    Helper command to scan for potential pep8 violations
-    """
+    """Helper command to scan for potential pep8 violations."""
+
     description = "perform pep8 scan of the code"
     user_options = []
     directories = ['pymodbus']
 
     def initialize_options(self):
-        """ options setup """
+        """Initialize options setup"""
         if not os.path.exists('./build'):
             os.mkdir('./build')
 
@@ -174,7 +172,7 @@ def finalize_options(self):
         pass
 
     def run(self):
-        """ command runner """
+        """Run command."""
         self._run_pep8()
 
     def _run_pep8(self):
diff --git a/test/__init__.py b/test/__init__.py
index e69de29bb..a8e0472a0 100644
--- a/test/__init__.py
+++ b/test/__init__.py
@@ -0,0 +1 @@
+"""Dummy."""
diff --git a/test/asyncio_test_helper.py b/test/asyncio_test_helper.py
index 64d1a8b5f..10c7ac37d 100644
--- a/test/asyncio_test_helper.py
+++ b/test/asyncio_test_helper.py
@@ -3,8 +3,8 @@
 import functools
 
 
-def _yielded_return(return_value, *args): # pylint: disable=unused-argument
-    """Generator factory function with return value."""
+def _yielded_return(return_value, *args):  # pylint: disable=unused-argument
+    """Return Generator factory function with return value."""
 
     async def _():
         """Actual generator producing value."""
@@ -16,7 +16,7 @@ async def _():
 
 
 def return_as_coroutine(return_value=None):
-    """Creates a function that behaves like an asyncio coroutine and returns the given value.
+    """Create a function that behaves like an asyncio coroutine and returns the given value.
 
     Typically used as a side effect of a mocked coroutine like this:
 
@@ -37,8 +37,7 @@ def test_it(mock_sleep):
 
 
 def run_coroutine(coro):
-    """Runs a coroutine as top-level task by iterating through all yielded steps."""
-
+    """Run a coroutine as top-level task by iterating through all yielded steps."""
     result = None
     try:
         # step through all parts of coro without scheduling anything else:
@@ -47,5 +46,5 @@ def run_coroutine(coro):
     except StopIteration as exc:
         # coro reached end pass on its return value:
         return exc.value
-    except: # pylint: disable=try-except-raise
+    except:  # noqa E722 pylint: disable=try-except-raise
         raise
diff --git a/test/modbus_mocks.py b/test/modbus_mocks.py
index ddd789a5a..2d09db44b 100644
--- a/test/modbus_mocks.py
+++ b/test/modbus_mocks.py
@@ -1,10 +1,12 @@
 """Modbus mocks."""
 from pymodbus.interfaces import IModbusSlaveContext
 
-#---------------------------------------------------------------------------#
-# Mocks
-#---------------------------------------------------------------------------#
-class mock: # pylint: disable=too-few-public-methods,invalid-name
+# ---------------------------------------------------------------------------#
+#  Mocks
+# ---------------------------------------------------------------------------#
+
+
+class mock:  # pylint: disable=too-few-public-methods,invalid-name
     """Mock."""
 
 
@@ -12,6 +14,7 @@ class MockContext(IModbusSlaveContext):
     """Mock context."""
 
     def __init__(self, valid=False, default=True):
+        """Initialize."""
         self.valid = valid
         self.default = default
 
@@ -26,14 +29,18 @@ def getValues(self, fx, address, count=0):
     def setValues(self, fx, address, values):
         """Set values."""
 
+
 class FakeList:
-    """ todo, replace with magic mock """
+    """Todo, replace with magic mock."""
 
     def __init__(self, size):
+        """Initialize."""
         self.size = size
 
     def __len__(self):
+        """Get length."""
         return self.size
 
-    def __iter__(self): # pylint: disable=non-iterator-returned
+    def __iter__(self):  # pylint: disable=non-iterator-returned
+        """Iterate."""
         return []
diff --git a/test/test_all_messages.py b/test/test_all_messages.py
index 7982199b4..5bed0c855 100644
--- a/test/test_all_messages.py
+++ b/test/test_all_messages.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test all messages."""
+"""Test all messages."""
 import unittest
 from pymodbus.constants import Defaults
 from pymodbus.bit_read_message import (
@@ -29,20 +29,20 @@
     WriteSingleRegisterRequest,
 )
 
-#---------------------------------------------------------------------------#
-# Fixture
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Fixture
+# ---------------------------------------------------------------------------#
+
+
 class ModbusAllMessagesTests(unittest.TestCase):
     """All messages tests."""
 
-    #-----------------------------------------------------------------------#
-    # Setup/TearDown
-    #-----------------------------------------------------------------------#
+    # -----------------------------------------------------------------------#
+    #  Setup/TearDown
+    # -----------------------------------------------------------------------#
 
     def setUp(self):
-        """ Initializes the test environment and builds request/result
-        encoding pairs
-        """
+        """Initialize the test environment and builds request/result encoding pairs."""
         arguments = {
             'read_address': 1, 'read_count': 1,
             'write_address': 1, 'write_registers': 1
@@ -71,30 +71,30 @@ def setUp(self):
         ]
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
 
     def test_initializing_slave_address_request(self):
-        """ Test that every request can initialize the unit id """
+        """Test that every request can initialize the unit id"""
         unit_id = 0x12
         for factory in self.requests:
             request = factory(unit_id)
             self.assertEqual(request.unit_id, unit_id)
 
     def test_initializing_slave_address_response(self):
-        """ Test that every response can initialize the unit id """
+        """Test that every response can initialize the unit id"""
         unit_id = 0x12
         for factory in self.responses:
             response = factory(unit_id)
             self.assertEqual(response.unit_id, unit_id)
 
     def test_forwarding_kwargs_to_pdu(self):
-        """ Test that the kwargs are forwarded to the pdu correctly """
-        request = ReadCoilsRequest(1,5, unit=0x12, transaction=0x12, protocol=0x12)
+        """Test that the kwargs are forwarded to the pdu correctly"""
+        request = ReadCoilsRequest(1, 5, unit=0x12, transaction=0x12, protocol=0x12)
         self.assertEqual(request.unit_id, 0x12)
         self.assertEqual(request.transaction_id, 0x12)
         self.assertEqual(request.protocol_id, 0x12)
 
-        request = ReadCoilsRequest(1,5)
+        request = ReadCoilsRequest(1, 5)
         self.assertEqual(request.unit_id, Defaults.UnitId)
         self.assertEqual(request.transaction_id, Defaults.TransactionId)
         self.assertEqual(request.protocol_id, Defaults.ProtocolId)
diff --git a/test/test_bit_read_messages.py b/test/test_bit_read_messages.py
index 1e2530c26..e2bd5dea8 100644
--- a/test/test_bit_read_messages.py
+++ b/test/test_bit_read_messages.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
-""" Bit Message Test Fixture
---------------------------------
+"""Bit Message Test Fixture.
+
 This fixture tests the functionality of all the
 bit based request/response messages:
 
@@ -17,110 +17,110 @@
 from .modbus_mocks import MockContext
 res = [True] * 21
 res.extend([False] * 3)
-#---------------------------------------------------------------------------#
-# Fixture
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Fixture
+# ---------------------------------------------------------------------------#
+
+
 class ModbusBitMessageTests(unittest.TestCase):
-    """ Modbus bit read message tests. """
+    """Modbus bit read message tests."""
 
-    #-----------------------------------------------------------------------#
-    # Setup/TearDown
-    #-----------------------------------------------------------------------#
+    # -----------------------------------------------------------------------#
+    #  Setup/TearDown
+    # -----------------------------------------------------------------------#
 
     def setUp(self):
-        """ Initializes the test environment and builds request/result
-        encoding pairs
-        """
+        """Initialize the test environment and builds request/result encoding pairs."""
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
 
     def test_read_bit_base_class_methods(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         handle = ReadBitsRequestBase(1, 1)
-        msg    = "ReadBitRequest(1,1)"
+        msg = "ReadBitRequest(1,1)"
         self.assertEqual(msg, str(handle))
-        handle = ReadBitsResponseBase([1,1])
-        msg    = "ReadBitsResponseBase(2)"
+        handle = ReadBitsResponseBase([1, 1])
+        msg = "ReadBitsResponseBase(2)"
         self.assertEqual(msg, str(handle))
 
     def test_bit_read_base_request_encoding(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         for i in range(20):
             handle = ReadBitsRequestBase(i, i)
-            result = struct.pack('>HH',i, i)
+            result = struct.pack('>HH', i, i)
             self.assertEqual(handle.encode(), result)
             handle.decode(result)
-            self.assertEqual((handle.address, handle.count), (i,i))
+            self.assertEqual((handle.address, handle.count), (i, i))
 
     def test_bit_read_base_response_encoding(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         for i in range(20):
-            data  = [True] * i
+            data = [True] * i
             handle = ReadBitsResponseBase(data)
             result = handle.encode()
             handle.decode(result)
             self.assertEqual(handle.bits[:i], data)
 
     def test_bit_read_base_response_helper_methods(self):
-        """ Test the extra methods on a ReadBitsResponseBase """
-        data  = [False] * 8
+        """Test the extra methods on a ReadBitsResponseBase"""
+        data = [False] * 8
         handle = ReadBitsResponseBase(data)
-        for i in (1,3,5):
+        for i in (1, 3, 5):
             handle.setBit(i, True)
-        for i in (1,3,5):
+        for i in (1, 3, 5):
             handle.resetBit(i)
         for i in range(8):
             self.assertEqual(handle.getBit(i), False)
 
     def test_bit_read_base_requests(self):
-        """ Test bit read request encoding """
+        """Test bit read request encoding"""
         messages = {
-            ReadBitsRequestBase(12, 14)        : b'\x00\x0c\x00\x0e',
-            ReadBitsResponseBase([1,0,1,1,0])  : b'\x01\x0d'
+            ReadBitsRequestBase(12, 14): b'\x00\x0c\x00\x0e',
+            ReadBitsResponseBase([1, 0, 1, 1, 0]): b'\x01\x0d'
         }
         for request, expected in iter(messages.items()):
             self.assertEqual(request.encode(), expected)
 
     def test_bit_read_message_execute_value_errors(self):
-        """ Test bit read request encoding """
+        """Test bit read request encoding"""
         context = MockContext()
         requests = [
-            ReadCoilsRequest(1,0x800),
-            ReadDiscreteInputsRequest(1,0x800),
+            ReadCoilsRequest(1, 0x800),
+            ReadDiscreteInputsRequest(1, 0x800),
         ]
         for request in requests:
             result = request.execute(context)
             self.assertEqual(ModbusExceptions.IllegalValue,
-                result.exception_code)
+                             result.exception_code)
 
     def test_bit_read_message_execute_address_errors(self):
-        """ Test bit read request encoding """
+        """Test bit read request encoding"""
         context = MockContext()
         requests = [
-            ReadCoilsRequest(1,5),
-            ReadDiscreteInputsRequest(1,5),
+            ReadCoilsRequest(1, 5),
+            ReadDiscreteInputsRequest(1, 5),
         ]
         for request in requests:
             result = request.execute(context)
             self.assertEqual(ModbusExceptions.IllegalAddress, result.exception_code)
 
     def test_bit_read_message_execute_success(self):
-        """ Test bit read request encoding """
+        """Test bit read request encoding"""
         context = MockContext()
-        context.validate = lambda a,b,c: True
+        context.validate = lambda a, b, c: True
         requests = [
-            ReadCoilsRequest(1,5),
-            ReadDiscreteInputsRequest(1,5),
+            ReadCoilsRequest(1, 5),
+            ReadDiscreteInputsRequest(1, 5),
         ]
         for request in requests:
             result = request.execute(context)
             self.assertEqual(result.bits, [True] * 5)
 
     def test_bit_read_message_get_response_pdu(self):
-        """ Test bit read message get response pdu."""
+        """Test bit read message get response pdu."""
         requests = {
-            ReadCoilsRequest(1,5): 3,
+            ReadCoilsRequest(1, 5): 3,
             ReadCoilsRequest(1, 8): 3,
             ReadCoilsRequest(0, 16): 4,
             ReadDiscreteInputsRequest(1, 21): 5,
@@ -132,8 +132,8 @@ def test_bit_read_message_get_response_pdu(self):
             self.assertEqual(pdu_len, expected)
 
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_bit_write_messages.py b/test/test_bit_write_messages.py
index 8f392316e..dac479863 100644
--- a/test/test_bit_write_messages.py
+++ b/test/test_bit_write_messages.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
-""" Bit Message Test Fixture
---------------------------------
+"""Bit Message Test Fixture.
+
 This fixture tests the functionality of all the
 bit based request/response messages:
 
@@ -18,37 +18,37 @@
 
 from .modbus_mocks import MockContext, FakeList
 
-#---------------------------------------------------------------------------#
-# Fixture
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Fixture
+# ---------------------------------------------------------------------------#
+
+
 class ModbusBitMessageTests(unittest.TestCase):
-    """ Modbus bit write message tests. """
+    """Modbus bit write message tests."""
 
-    #-----------------------------------------------------------------------#
-    # Setup/TearDown
-    #-----------------------------------------------------------------------#
+    # -----------------------------------------------------------------------#
+    #  Setup/TearDown
+    # -----------------------------------------------------------------------#
 
     def setUp(self):
-        """ Initializes the test environment and builds request/result
-        encoding pairs
-        """
+        """Initialize the test environment and builds request/result encoding pairs."""
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
 
     def test_bit_write_base_requests(self):
-        """ Test bit write base. """
+        """Test bit write base."""
         messages = {
-            WriteSingleCoilRequest(1, 0xabcd)      : b'\x00\x01\xff\x00',
-            WriteSingleCoilResponse(1, 0xabcd)     : b'\x00\x01\xff\x00',
-            WriteMultipleCoilsRequest(1, [True]*5) : b'\x00\x01\x00\x05\x01\x1f',
-            WriteMultipleCoilsResponse(1, 5)       : b'\x00\x01\x00\x05',
+            WriteSingleCoilRequest(1, 0xabcd): b'\x00\x01\xff\x00',
+            WriteSingleCoilResponse(1, 0xabcd): b'\x00\x01\xff\x00',
+            WriteMultipleCoilsRequest(1, [True] * 5): b'\x00\x01\x00\x05\x01\x1f',
+            WriteMultipleCoilsResponse(1, 5): b'\x00\x01\x00\x05',
         }
         for request, expected in iter(messages.items()):
             self.assertEqual(request.encode(), expected)
 
     def test_bit_write_message_get_response_pdu(self):
-        """ Test bit write message. """
+        """Test bit write message."""
         requests = {
             WriteSingleCoilRequest(1, 0xabcd): 5
         }
@@ -57,30 +57,29 @@ def test_bit_write_message_get_response_pdu(self):
             self.assertEqual(pdu_len, expected)
 
     def test_write_multiple_coils_request(self):
-        """ Test write multiple coils. """
-        request = WriteMultipleCoilsRequest(1, [True]*5)
+        """Test write multiple coils."""
+        request = WriteMultipleCoilsRequest(1, [True] * 5)
         request.decode(b'\x00\x01\x00\x05\x01\x1f')
         self.assertEqual(request.byte_count, 1)
         self.assertEqual(request.address, 1)
-        self.assertEqual(request.values, [True]*5)
+        self.assertEqual(request.values, [True] * 5)
         self.assertEqual(request.get_response_pdu_size(), 5)
 
-
     def test_invalid_write_multiple_coils_request(self):
-        """ Test write invalid multiple coils. """
+        """Test write invalid multiple coils."""
         request = WriteMultipleCoilsRequest(1, None)
         self.assertEqual(request.values, [])
 
     def test_write_single_coil_request_encode(self):
-        """ Test write single coil. """
+        """Test write single coil."""
         request = WriteSingleCoilRequest(1, False)
         self.assertEqual(request.encode(), b'\x00\x01\x00\x00')
 
     def test_write_single_coil_execute(self):
-        """ Test write single coil. """
+        """Test write single coil."""
         context = MockContext(False, default=True)
         request = WriteSingleCoilRequest(2, True)
-        result  = request.execute(context)
+        result = request.execute(context)
         self.assertEqual(result.exception_code, ModbusExceptions.IllegalAddress)
 
         context.valid = True
@@ -93,51 +92,52 @@ def test_write_single_coil_execute(self):
         self.assertEqual(result.encode(), b'\x00\x02\x00\x00')
 
     def test_write_multiple_coils_execute(self):
-        """ Test write multiple coils. """
+        """Test write multiple coils."""
         context = MockContext(False)
         # too many values
         request = WriteMultipleCoilsRequest(2, FakeList(0x123456))
-        result  = request.execute(context)
+        result = request.execute(context)
         self.assertEqual(result.exception_code, ModbusExceptions.IllegalValue)
 
         # bad byte count
-        request = WriteMultipleCoilsRequest(2, [0x00]*4)
+        request = WriteMultipleCoilsRequest(2, [0x00] * 4)
         request.byte_count = 0x00
-        result  = request.execute(context)
+        result = request.execute(context)
         self.assertEqual(result.exception_code, ModbusExceptions.IllegalValue)
 
         # does not validate
         context.valid = False
-        request = WriteMultipleCoilsRequest(2, [0x00]*4)
-        result  = request.execute(context)
+        request = WriteMultipleCoilsRequest(2, [0x00] * 4)
+        result = request.execute(context)
         self.assertEqual(result.exception_code, ModbusExceptions.IllegalAddress)
 
         # validated request
         context.valid = True
-        result  = request.execute(context)
+        result = request.execute(context)
         self.assertEqual(result.encode(), b'\x00\x02\x00\x04')
 
     def test_write_multiple_coils_response(self):
-        """ Test write multiple coils. """
+        """Test write multiple coils."""
         response = WriteMultipleCoilsResponse()
         response.decode(b'\x00\x80\x00\x08')
         self.assertEqual(response.address, 0x80)
         self.assertEqual(response.count, 0x08)
 
     def test_serializing_to_string(self):
-        """ Test serializing to string. """
+        """Test serializing to string."""
         requests = [
             WriteSingleCoilRequest(1, 0xabcd),
             WriteSingleCoilResponse(1, 0xabcd),
-            WriteMultipleCoilsRequest(1, [True]*5),
+            WriteMultipleCoilsRequest(1, [True] * 5),
             WriteMultipleCoilsResponse(1, 5),
         ]
         for request in requests:
             result = str(request)
-            self.assertTrue(result is not None and len(result)) #NOSONAR
+            self.assertTrue(result is not None and len(result))  # NOSONAR
+
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_client_async.py b/test/test_client_async.py
index 2f617aeef..09bd056c1 100644
--- a/test/test_client_async.py
+++ b/test/test_client_async.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test client async. """
+"""Test client async."""
 import contextlib
 import sys
 import ssl
@@ -35,13 +35,13 @@
 
 
 def mock_asyncio_gather(coro):
-    """ Mock asyncio gather. """
+    """Mock asyncio gather."""
     return coro
 
 
 @contextlib.contextmanager
 def maybe_manage(condition, manager):
-    """ Maybe manage. """
+    """Maybe manage."""
     if condition:
         with manager as value:
             yield value
@@ -50,15 +50,15 @@ def maybe_manage(condition, manager):
 
 
 class TestAsynchronousClient:
-    """ Unittest for the pymodbus.client.asynchronous module. """
+    """Unittest for the pymodbus.client.asynchronous module."""
 
     # -----------------------------------------------------------------------#
     # Test TCP Client client
     # -----------------------------------------------------------------------#
-    def test_tcp_twisted_client(self): # pylint: disable=no-self-use
-        """ Test the TCP Twisted client. """
+    def test_tcp_twisted_client(self):  # pylint: disable=no-self-use
+        """Test the TCP Twisted client."""
         with patch("twisted.internet.reactor"):
-            def test_callback(client): # pylint: disable=unused-argument
+            def test_callback(client):  # pylint: disable=unused-argument
                 pass
 
             AsyncModbusTCPClient(schedulers.REACTOR,
@@ -68,52 +68,50 @@ def test_callback(client): # pylint: disable=unused-argument
 
     @patch("pymodbus.client.asynchronous.tornado.IOLoop")
     @patch("pymodbus.client.asynchronous.tornado.IOStream")
-    def test_tcp_tornado_client(self, mock_iostream, mock_ioloop): # pylint: disable=no-self-use,unused-argument
-        """ Test the TCP tornado client client initialize """
-        protocol, future = AsyncModbusTCPClient( # NOSOANR pylint: disable=unpacking-non-sequence
+    def test_tcp_tornado_client(self, mock_iostream, mock_ioloop):  # pylint: disable=no-self-use,unused-argument
+        """Test the TCP tornado client client initialize"""
+        protocol, future = AsyncModbusTCPClient(  # NOSOANR pylint: disable=unpacking-non-sequence
             schedulers.IO_LOOP, framer=ModbusSocketFramer(ClientDecoder()))
         client = future.result()
-        assert isinstance(client, AsyncTornadoModbusTcpClient) #nosec
-        assert not list(client.transaction) #nosec
-        assert isinstance(client.framer, ModbusSocketFramer) #nosec
-        assert client.port == 502 #nosec
-        assert client._connected #nosec pylint: disable=protected-access
-        assert client.stream.connect.call_count == 1 #nosec
-        assert client.stream.read_until_close.call_count == 1 #nosec
+        assert isinstance(client, AsyncTornadoModbusTcpClient)  # nosec
+        assert not list(client.transaction)  # nosec
+        assert isinstance(client.framer, ModbusSocketFramer)  # nosec
+        assert client.port == 502  # nosec
+        assert client._connected  # nosec pylint: disable=protected-access
+        assert client.stream.connect.call_count == 1  # nosec
+        assert client.stream.read_until_close.call_count == 1  # nosec
 
         def handle_failure(failure):
-            assert isinstance(failure.exception(), ConnectionException) #nosec
+            assert isinstance(failure.exception(), ConnectionException)  # nosec
 
-        response = client._build_response(0x00) # pylint: disable=protected-access
+        response = client._build_response(0x00)  # pylint: disable=protected-access
         response.add_done_callback(handle_failure)
 
-        assert client._connected #nosec pylint: disable=protected-access
+        assert client._connected  # nosec pylint: disable=protected-access
         client.close()
         protocol.stop()
-        assert not client._connected #nosec pylint: disable=protected-access
-
+        assert not client._connected  # nosec pylint: disable=protected-access
 
     @patch("asyncio.get_event_loop")
     @patch("asyncio.gather")
-    def test_tcp_asyncio_client(self, mock_gather, mock_loop): # pylint: disable=no-self-use,unused-argument
-        """ Test the TCP Twisted client. """
+    def test_tcp_asyncio_client(self, mock_gather, mock_loop):  # pylint: disable=no-self-use,unused-argument
+        """Test the TCP Twisted client."""
         pytest.skip("TBD")
 
     # -----------------------------------------------------------------------#
     # Test TLS Client client
     # -----------------------------------------------------------------------#
 
-
-    def test_tls_asyncio_client(self): # pylint: disable=no-self-use
-        """ Test the TLS AsyncIO client. """
-        _, client = AsyncModbusTLSClient(schedulers.ASYNC_IO) #NOSONAR pylint: disable=unpacking-non-sequence
-        assert isinstance(client, ReconnectingAsyncioModbusTlsClient) #nosec
-        assert isinstance(client.framer, ModbusTlsFramer) #nosec
-        assert isinstance(client.sslctx, ssl.SSLContext) #nosec
-        assert client.port == 802 #nosec
+    def test_tls_asyncio_client(self):  # pylint: disable=no-self-use
+        """Test the TLS AsyncIO client."""
+        _, client = AsyncModbusTLSClient(schedulers.ASYNC_IO)  # NOSONAR pylint: disable=unpacking-non-sequence
+        assert isinstance(client, ReconnectingAsyncioModbusTlsClient)  # nosec
+        assert isinstance(client.framer, ModbusTlsFramer)  # nosec
+        assert isinstance(client.sslctx, ssl.SSLContext)  # nosec
+        assert client.port == 802  # nosec
 
         client.stop()
-        assert client.host is None #nosec
+        assert client.host is None  # nosec
 
     # -----------------------------------------------------------------------#
     # Test UDP client
@@ -121,37 +119,37 @@ def test_tls_asyncio_client(self): # pylint: disable=no-self-use
 
     @patch("pymodbus.client.asynchronous.tornado.IOLoop")
     @patch("pymodbus.client.asynchronous.tornado.IOStream")
-    def test_udp_tornado_client(self, mock_iostream, mock_ioloop): # pylint: disable=no-self-use,unused-argument
-        """ Test the udp tornado client client initialize """
-        protocol, future = AsyncModbusUDPClient( #NOSONAR pylint: disable=unpacking-non-sequence
+    def test_udp_tornado_client(self, mock_iostream, mock_ioloop):  # pylint: disable=no-self-use,unused-argument
+        """Test the udp tornado client client initialize"""
+        protocol, future = AsyncModbusUDPClient(  # NOSONAR pylint: disable=unpacking-non-sequence
             schedulers.IO_LOOP, framer=ModbusSocketFramer(ClientDecoder()))
         client = future.result()
-        assert isinstance(client, AsyncTornadoModbusUdoClient) #nosec
-        assert not list(client.transaction) #nosec
-        assert isinstance(client.framer, ModbusSocketFramer) #nosec
-        assert client.port == 502 #nosec
-        assert client._connected #nosec pylint: disable=protected-access
+        assert isinstance(client, AsyncTornadoModbusUdoClient)  # nosec
+        assert not list(client.transaction)  # nosec
+        assert isinstance(client.framer, ModbusSocketFramer)  # nosec
+        assert client.port == 502  # nosec
+        assert client._connected  # nosec pylint: disable=protected-access
 
         def handle_failure(failure):
-            assert isinstance(failure.exception(), ConnectionException) #nosec
+            assert isinstance(failure.exception(), ConnectionException)  # nosec
 
-        response = client._build_response(0x00) # pylint: disable=protected-access
+        response = client._build_response(0x00)  # pylint: disable=protected-access
         response.add_done_callback(handle_failure)
 
-        assert client._connected #nosec pylint: disable=protected-access
+        assert client._connected  # nosec pylint: disable=protected-access
         client.close()
         protocol.stop()
-        assert not client._connected #nosec pylint: disable=protected-access
+        assert not client._connected  # nosec pylint: disable=protected-access
 
-    def test_udp_twisted_client(self): # pylint: disable=no-self-use
-        """ Test the udp twisted client client initialize """
+    def test_udp_twisted_client(self):  # pylint: disable=no-self-use
+        """Test the udp twisted client client initialize"""
         with pytest.raises(NotImplementedError):
             AsyncModbusUDPClient(schedulers.REACTOR,
                                  framer=ModbusSocketFramer(ClientDecoder()))
 
     @patch("asyncio.get_event_loop")
     @patch("asyncio.gather", side_effect=mock_asyncio_gather)
-    def test_udp_asyncio_client(self, mock_gather, mock_event_loop): # pylint: disable=no-self-use,unused-argument
+    def test_udp_asyncio_client(self, mock_gather, mock_event_loop):  # pylint: disable=no-self-use,unused-argument
         """Test the udp asyncio client"""
         pytest.skip("TBD")
 
@@ -167,62 +165,64 @@ def test_udp_asyncio_client(self, mock_gather, mock_event_loop): # pylint: disab
                                                 ("socket", ModbusSocketFramer),
                                                 ("binary", ModbusBinaryFramer),
                                                 ("ascii", ModbusAsciiFramer)])
-    def test_serial_twisted_client(self, method, framer): # pylint: disable=no-self-use
-        """ Test the serial twisted client client initialize """
+    def test_serial_twisted_client(self, method, framer):  # pylint: disable=no-self-use
+        """Test the serial twisted client client initialize"""
         with patch("serial.Serial"):
-            from twisted.internet.serialport import SerialPort # pylint: disable=import-outside-toplevel
+            from twisted.internet.serialport import SerialPort  # pylint: disable=import-outside-toplevel
             with maybe_manage(sys.platform == 'win32', patch.object(
-                SerialPort, "_finishPortSetup")):
+                    SerialPort, "_finishPortSetup")):
                 with patch('twisted.internet.reactor'):
 
-                    protocol, client = AsyncModbusSerialClient(schedulers.REACTOR, #NOSONAR pylint: disable=unpacking-non-sequence
-                                                               method=method,
-                                                               port=pytest.SERIAL_PORT,
-                                                               proto_cls=ModbusSerClientProtocol)
+                    protocol, client = AsyncModbusSerialClient(  # NOSONAR pylint: disable=unpacking-non-sequence
+                        schedulers.REACTOR,
+                        method=method,
+                        port=pytest.SERIAL_PORT,
+                        proto_cls=ModbusSerClientProtocol
+                    )
 
-                    assert isinstance(client, SerialPort) #nosec
-                    assert isinstance(client.protocol, ModbusSerClientProtocol) #nosec
-                    assert not list(client.protocol.transaction) #nosec
-                    assert isinstance(client.protocol.framer, framer) #nosec
-                    assert client.protocol._connected #nosec pylint: disable=protected-access
+                    assert isinstance(client, SerialPort)  # nosec
+                    assert isinstance(client.protocol, ModbusSerClientProtocol)  # nosec
+                    assert not list(client.protocol.transaction)  # nosec
+                    assert isinstance(client.protocol.framer, framer)  # nosec
+                    assert client.protocol._connected  # nosec pylint: disable=protected-access
 
                     def handle_failure(failure):
-                        assert (isinstance(failure.exception(), ConnectionException)) #nosec
+                        assert (isinstance(failure.exception(), ConnectionException))  # nosec
 
-                    response = client.protocol._buildResponse(0x00) # pylint: disable=protected-access
+                    response = client.protocol._buildResponse(0x00)  # pylint: disable=protected-access
                     response.addCallback(handle_failure)
 
-                    assert client.protocol._connected #nosec pylint: disable=protected-access
+                    assert client.protocol._connected  # nosec pylint: disable=protected-access
                     client.protocol.close()
                     protocol.stop()
-                    assert not client.protocol._connected #nosec pylint: disable=protected-access
+                    assert not client.protocol._connected  # nosec pylint: disable=protected-access
 
     @pytest.mark.parametrize("method, framer", [("rtu", ModbusRtuFramer),
                                                 ("socket", ModbusSocketFramer),
                                                 ("binary", ModbusBinaryFramer),
                                                 ("ascii", ModbusAsciiFramer)])
-    def test_serial_tornado_client(self, method, framer): # pylint: disable=no-self-use
-        """ Test the serial tornado client client initialize """
-        with maybe_manage(sys.platform in set(('darwin', 'win32')),patch.object(Serial, "open")):
-            protocol, future = AsyncModbusSerialClient( #NOSONAR pylint: disable=unpacking-non-sequence
+    def test_serial_tornado_client(self, method, framer):  # pylint: disable=no-self-use
+        """Test the serial tornado client client initialize"""
+        with maybe_manage(sys.platform in set(('darwin', 'win32')), patch.object(Serial, "open")):
+            protocol, future = AsyncModbusSerialClient(  # NOSONAR pylint: disable=unpacking-non-sequence
                 schedulers.IO_LOOP, method=method, port=pytest.SERIAL_PORT)
             client = future.result()
-            assert isinstance(client, AsyncTornadoModbusSerialClient) #nosec
-            assert not list(client.transaction) #nosec
-            assert isinstance(client.framer, framer) #nosec
-            assert client.port == pytest.SERIAL_PORT #nosec
-            assert client._connected #nosec pylint: disable=protected-access
+            assert isinstance(client, AsyncTornadoModbusSerialClient)  # nosec
+            assert not list(client.transaction)  # nosec
+            assert isinstance(client.framer, framer)  # nosec
+            assert client.port == pytest.SERIAL_PORT  # nosec
+            assert client._connected  # nosec pylint: disable=protected-access
 
             def handle_failure(failure):
-                assert isinstance(failure.exception(), ConnectionException) #nosec
+                assert isinstance(failure.exception(), ConnectionException)  # nosec
 
-            response = client._build_response(0x00) # pylint: disable=protected-access
+            response = client._build_response(0x00)  # pylint: disable=protected-access
             response.add_done_callback(handle_failure)
 
-            assert client._connected #nosec pylint: disable=protected-access
+            assert client._connected  # nosec pylint: disable=protected-access
             client.close()
             protocol.stop()
-            assert not client._connected #nosec pylint: disable=protected-access
+            assert not client._connected  # nosec pylint: disable=protected-access
 
     @patch("asyncio.get_event_loop")
     @patch("asyncio.gather", side_effect=mock_asyncio_gather)
@@ -230,22 +230,21 @@ def handle_failure(failure):
                                                 ("socket", ModbusSocketFramer),
                                                 ("binary", ModbusBinaryFramer),
                                                 ("ascii", ModbusAsciiFramer)])
-    def test_serial_asyncio_client(self, mock_gather, mock_event_loop, method, framer): # pylint: disable=no-self-use,unused-argument
-        """ Test that AsyncModbusSerialClient instantiates
-        AsyncioModbusSerialClient for asyncio scheduler.
-        """
+    def test_serial_asyncio_client(self, mock_gather,  # pylint: disable=no-self-use,unused-argument
+                                   mock_event_loop, method, framer):  # pylint: disable=unused-argument
+        """Test that AsyncModbusSerialClient instantiates AsyncioModbusSerialClient for asyncio scheduler."""
         loop = asyncio.get_event_loop()
         loop.is_running.side_effect = lambda: False
-        loop, client = AsyncModbusSerialClient( #NOSONAR pylint: disable=unpacking-non-sequence
+        loop, client = AsyncModbusSerialClient(  # NOSONAR pylint: disable=unpacking-non-sequence
             schedulers.ASYNC_IO, method=method, port=pytest.SERIAL_PORT, loop=loop,
             baudrate=19200, parity='E', stopbits=2, bytesize=7)
-        assert isinstance(client, AsyncioModbusSerialClient) #nosec
-        assert isinstance(client.framer, framer) #nosec
-        assert client.port == pytest.SERIAL_PORT #nosec
-        assert client.baudrate == 19200 #nosec
-        assert client.parity == 'E' #nosec
-        assert client.stopbits == 2 #nosec
-        assert client.bytesize == 7 #nosec
+        assert isinstance(client, AsyncioModbusSerialClient)  # nosec
+        assert isinstance(client.framer, framer)  # nosec
+        assert client.port == pytest.SERIAL_PORT  # nosec
+        assert client.baudrate == 19200  # nosec
+        assert client.parity == 'E'  # nosec
+        assert client.stopbits == 2  # nosec
+        assert client.bytesize == 7  # nosec
         client.stop()
         loop.stop()
 
diff --git a/test/test_client_async_asyncio.py b/test/test_client_async_asyncio.py
index b9b24cba4..5a0143304 100644
--- a/test/test_client_async_asyncio.py
+++ b/test/test_client_async_asyncio.py
@@ -1,4 +1,4 @@
-""" Test client asyncio. """
+"""Test client asyncio."""
 import sys
 from unittest import mock
 from test.asyncio_test_helper import return_as_coroutine, run_coroutine
@@ -22,35 +22,36 @@
 
 
 class TestAsyncioClient:
-    """ Test asyncio client. """
-    def test_base_modbus_async_client_protocol(self): # pylint: disable=no-self-use
-        """ Test base modbus async client protocol. """
+    """Test asyncio client."""
+
+    def test_base_modbus_async_client_protocol(self):  # pylint: disable=no-self-use
+        """Test base modbus async client protocol."""
         protocol = BaseModbusAsyncClientProtocol()
-        assert protocol.factory is None #nosec
-        assert protocol.transport is None #nosec
-        assert not protocol._connected #nosec pylint: disable=protected-access
+        assert protocol.factory is None  # nosec
+        assert protocol.transport is None  # nosec
+        assert not protocol._connected  # nosec pylint: disable=protected-access
 
-    def test_protocol_connection_state_propagation_to_factory(self): # pylint: disable=no-self-use
-        """ Test protocol connection state progration to factory. """
+    def test_protocol_connection_state_propagation_to_factory(self):  # pylint: disable=no-self-use
+        """Test protocol connection state progration to factory."""
         protocol = ModbusClientProtocol()
-        assert protocol.factory is None #nosec
-        assert protocol.transport is None #nosec
-        assert not protocol._connected #nosec pylint: disable=protected-access
+        assert protocol.factory is None  # nosec
+        assert protocol.transport is None  # nosec
+        assert not protocol._connected  # nosec pylint: disable=protected-access
 
         protocol.factory = mock.MagicMock()
 
         protocol.connection_made(mock.sentinel.TRANSPORT)
-        assert protocol.transport is mock.sentinel.TRANSPORT #nosec
-        protocol.factory.protocol_made_connection.assert_called_once_with( # pylint: disable=no-member
+        assert protocol.transport is mock.sentinel.TRANSPORT  # nosec
+        protocol.factory.protocol_made_connection.assert_called_once_with(  # pylint: disable=no-member
             protocol)
-        assert not protocol.factory.protocol_lost_connection.call_count #nosec pylint: disable=no-member
+        assert not protocol.factory.protocol_lost_connection.call_count  # nosec pylint: disable=no-member
 
         protocol.factory.reset_mock()
 
         protocol.connection_lost(mock.sentinel.REASON)
-        assert protocol.transport is None #nosec
-        assert not protocol.factory.protocol_made_connection.call_count #nosec pylint: disable=no-member
-        protocol.factory.protocol_lost_connection.assert_called_once_with( # pylint: disable=no-member
+        assert protocol.transport is None  # nosec
+        assert not protocol.factory.protocol_made_connection.call_count  # nosec pylint: disable=no-member
+        protocol.factory.protocol_lost_connection.assert_called_once_with(  # pylint: disable=no-member
             protocol)
         protocol.raise_future = mock.MagicMock()
         request = mock.MagicMock()
@@ -61,84 +62,85 @@ def test_protocol_connection_state_propagation_to_factory(self): # pylint: disab
         else:
             call_args = protocol.raise_future.call_args[0]
         protocol.raise_future.assert_called_once()
-        assert call_args[0] == request #nosec
-        assert isinstance(call_args[1], ConnectionException) #nosec
+        assert call_args[0] == request  # nosec
+        assert isinstance(call_args[1], ConnectionException)  # nosec
 
-    def test_factory_initialization_state(self): # pylint: disable=no-self-use
-        """ Test factory initialization state. """
+    def test_factory_initialization_state(self):  # pylint: disable=no-self-use
+        """Test factory initialization state."""
         mock_protocol_class = mock.MagicMock()
         mock_loop = mock.MagicMock()
         client = ReconnectingAsyncioModbusTcpClient(
             protocol_class=mock_protocol_class, loop=mock_loop)
-        assert not client.connected #nosec
-        assert client.delay_ms < client.DELAY_MAX_MS #nosec
+        assert not client.connected  # nosec
+        assert client.delay_ms < client.DELAY_MAX_MS  # nosec
 
-        assert client.loop is mock_loop #nosec
-        assert client.protocol_class is mock_protocol_class #nosec
+        assert client.loop is mock_loop  # nosec
+        assert client.protocol_class is mock_protocol_class  # nosec
 
     @pytest.mark.asyncio
-    async def test_initialization_tcp_in_loop(self): # pylint: disable=no-self-use
-        """ Test initialization tcp in loop. """
-        _, client = AsyncModbusTCPClient(schedulers.ASYNC_IO, #NOSONAR pylint: disable=unpacking-non-sequence
+    async def test_initialization_tcp_in_loop(self):  # pylint: disable=no-self-use
+        """Test initialization tcp in loop."""
+        _, client = AsyncModbusTCPClient(schedulers.ASYNC_IO,  # NOSONAR pylint: disable=unpacking-non-sequence
                                          port=5020)
         client = await client
 
-        assert not client.connected #nosec
-        assert client.port == 5020 #nosec
-        assert client.delay_ms < client.DELAY_MAX_MS #nosec
+        assert not client.connected  # nosec
+        assert client.port == 5020  # nosec
+        assert client.delay_ms < client.DELAY_MAX_MS  # nosec
 
     @pytest.mark.asyncio
-    async def test_initialization_udp_in_loop(self): # pylint: disable=no-self-use
-        """ Test initialization udp in loop. """
-        _, client = AsyncModbusUDPClient(schedulers.ASYNC_IO, port=5020) # pylint: disable=unpacking-non-sequence
+    async def test_initialization_udp_in_loop(self):  # pylint: disable=no-self-use
+        """Test initialization udp in loop."""
+        _, client = AsyncModbusUDPClient(schedulers.ASYNC_IO, port=5020)  # pylint: disable=unpacking-non-sequence
         client = await client
 
-        assert client.connected #nosec
-        assert client.port == 5020 #nosec
-        assert client.delay_ms < client.DELAY_MAX_MS #nosec
+        assert client.connected  # nosec
+        assert client.port == 5020  # nosec
+        assert client.delay_ms < client.DELAY_MAX_MS  # nosec
 
     @pytest.mark.asyncio
-    async def test_initialization_tls_in_loop(self): # pylint: disable=no-self-use
-        """ Test initialization tls in loop. """
-        _, client = AsyncModbusTLSClient(schedulers.ASYNC_IO, port=5020) #NOSONAR pylint: disable=unpacking-non-sequence
+    async def test_initialization_tls_in_loop(self):  # pylint: disable=no-self-use
+        """Test initialization tls in loop."""
+        _, client = AsyncModbusTLSClient(  # NOSONAR pylint: disable=unpacking-non-sequence
+            schedulers.ASYNC_IO, port=5020)
         client = await client
 
-        assert not client.connected #nosec
-        assert client.port == 5020 #nosec
-        assert client.delay_ms < client.DELAY_MAX_MS #nosec
+        assert not client.connected  # nosec
+        assert client.port == 5020  # nosec
+        assert client.delay_ms < client.DELAY_MAX_MS  # nosec
 
     @pytest.mark.asyncio
-    def test_initialization_serial_in_loop(self): # pylint: disable=no-self-use
-        """ Test initialization serial in loop. """
-        _, client = AsyncModbusSerialClient( #NOSONAR pylint: disable=unpacking-non-sequence
-            schedulers.ASYNC_IO, port='/tmp/ptyp0', baudrate=9600, method='rtu') #NOSONAR #nosec
+    def test_initialization_serial_in_loop(self):  # pylint: disable=no-self-use
+        """Test initialization serial in loop."""
+        _, client = AsyncModbusSerialClient(  # NOSONAR pylint: disable=unpacking-non-sequence
+            schedulers.ASYNC_IO, port='/tmp/ptyp0', baudrate=9600, method='rtu')  # NOSONAR #nosec
 
-        assert client.port == '/tmp/ptyp0' # nosec NOSONAR
-        assert client.baudrate == 9600 #nosec
+        assert client.port == '/tmp/ptyp0'  # nosec NOSONAR
+        assert client.baudrate == 9600  # nosec
 
-    def test_factory_reset_wait_before_reconnect(self): # pylint: disable=no-self-use
-        """ Test factory reset wait before reconnect. """
+    def test_factory_reset_wait_before_reconnect(self):  # pylint: disable=no-self-use
+        """Test factory reset wait before reconnect."""
         mock_protocol_class = mock.MagicMock()
         mock_loop = mock.MagicMock()
         client = ReconnectingAsyncioModbusTcpClient(
             protocol_class=mock_protocol_class, loop=mock_loop)
         initial_delay = client.delay_ms
-        assert initial_delay > 0 #nosec
+        assert initial_delay > 0  # nosec
         client.delay_ms *= 2
 
-        assert client.delay_ms > initial_delay #nosec
+        assert client.delay_ms > initial_delay  # nosec
         client.reset_delay()
-        assert client.delay_ms == initial_delay #nosec
+        assert client.delay_ms == initial_delay  # nosec
 
-    def test_factory_stop(self): # pylint: disable=no-self-use
-        """ Test factory stop. """
+    def test_factory_stop(self):  # pylint: disable=no-self-use
+        """Test factory stop."""
         mock_protocol_class = mock.MagicMock()
         mock_loop = mock.MagicMock()
         client = ReconnectingAsyncioModbusTcpClient(
             protocol_class=mock_protocol_class, loop=mock_loop)
-        assert not client.connected #nosec
+        assert not client.connected  # nosec
         client.stop()
-        assert not client.connected #nosec
+        assert not client.connected  # nosec
 
         # fake connected client:
         client.protocol = mock.MagicMock()
@@ -147,31 +149,31 @@ def test_factory_stop(self): # pylint: disable=no-self-use
         client.stop()
         client.protocol.transport.close.assert_called_once_with()
 
-    def test_factory_protocol_made_connection(self): # pylint: disable=no-self-use
-        """ Test factory protocol made connection. """
+    def test_factory_protocol_made_connection(self):  # pylint: disable=no-self-use
+        """Test factory protocol made connection."""
         mock_protocol_class = mock.MagicMock()
         mock_loop = mock.MagicMock()
         client = ReconnectingAsyncioModbusTcpClient(
             protocol_class=mock_protocol_class, loop=mock_loop)
-        assert not client.connected #nosec
-        assert client.protocol is None #nosec
+        assert not client.connected  # nosec
+        assert client.protocol is None  # nosec
         client.protocol_made_connection(mock.sentinel.PROTOCOL)
-        assert client.connected #nosec
-        assert client.protocol is mock.sentinel.PROTOCOL #nosec
+        assert client.connected  # nosec
+        assert client.protocol is mock.sentinel.PROTOCOL  # nosec
 
         client.protocol_made_connection(mock.sentinel.PROTOCOL_UNEXPECTED)
-        assert client.connected #nosec
-        assert client.protocol is mock.sentinel.PROTOCOL #nosec
+        assert client.connected  # nosec
+        assert client.protocol is mock.sentinel.PROTOCOL  # nosec
 
     @mock.patch('pymodbus.client.asynchronous.async_io.asyncio.ensure_future')
-    def test_factory_protocol_lost_connection(self, mock_async): # pylint: disable=no-self-use
-        """ Test factory protocol lost connection. """
+    def test_factory_protocol_lost_connection(self, mock_async):  # pylint: disable=no-self-use
+        """Test factory protocol lost connection."""
         mock_protocol_class = mock.MagicMock()
         mock_loop = mock.MagicMock()
         client = ReconnectingAsyncioModbusTcpClient(
             protocol_class=mock_protocol_class, loop=mock_loop)
-        assert not client.connected #nosec
-        assert client.protocol is None #nosec
+        assert not client.connected  # nosec
+        assert client.protocol is None  # nosec
 
         # fake client is connected and *then* looses connection:
         client.connected = True
@@ -180,7 +182,7 @@ def test_factory_protocol_lost_connection(self, mock_async): # pylint: disable=n
         client.protocol = mock.sentinel.PROTOCOL
         client.protocol_lost_connection(mock.sentinel.PROTOCOL_UNEXPECTED)
         mock_async.reset_mock()
-        assert not client.connected #nosec
+        assert not client.connected  # nosec
 
         client.connected = True
         with mock.patch(
@@ -192,19 +194,19 @@ def test_factory_protocol_lost_connection(self, mock_async): # pylint: disable=n
             if sys.version_info == (3, 7):
                 mock_async.assert_called_once_with(
                     mock.sentinel.RECONNECT_GENERATOR, loop=mock_loop)
-        assert not client.connected #nosec
-        assert client.protocol is None #nosec
+        assert not client.connected  # nosec
+        assert client.protocol is None  # nosec
 
     @pytest.mark.asyncio
-    async def test_factory_start_success(self): # pylint: disable=no-self-use
-        """ Test factory start success. """
+    async def test_factory_start_success(self):  # pylint: disable=no-self-use
+        """Test factory start success."""
         mock_protocol_class = mock.MagicMock()
         client = ReconnectingAsyncioModbusTcpClient(protocol_class=mock_protocol_class)
         await client.start(mock.sentinel.HOST, mock.sentinel.PORT)
 
     @mock.patch('pymodbus.client.asynchronous.async_io.asyncio.ensure_future')
-    def test_factory_start_failing_and_retried(self, mock_async): # pylint: disable=no-self-use
-        """ Test factory start failing and retried. """
+    def test_factory_start_failing_and_retried(self, mock_async):  # pylint: disable=no-self-use
+        """Test factory start failing and retried."""
         mock_protocol_class = mock.MagicMock()
         mock_loop = mock.MagicMock()
         mock_loop.create_connection = mock.MagicMock(side_effect=Exception('Did not work.'))
@@ -224,8 +226,8 @@ def test_factory_start_failing_and_retried(self, mock_async): # pylint: disable=
 
     # @pytest.mark.asyncio
     @mock.patch('pymodbus.client.asynchronous.async_io.asyncio.sleep')
-    def test_factory_reconnect(self, mock_sleep): # pylint: disable=no-self-use
-        """ Test factory reconnect. """
+    def test_factory_reconnect(self, mock_sleep):  # pylint: disable=no-self-use
+        """Test factory reconnect."""
         mock_protocol_class = mock.MagicMock()
         mock_sleep.side_effect = return_as_coroutine()
         mock_loop = mock.MagicMock()
@@ -233,43 +235,43 @@ def test_factory_reconnect(self, mock_sleep): # pylint: disable=no-self-use
             protocol_class=mock_protocol_class, loop=mock_loop)
         client.delay_ms = 5000
 
-        run_coroutine(client._reconnect()) # pylint: disable=protected-access
+        run_coroutine(client._reconnect())  # pylint: disable=protected-access
         mock_sleep.assert_called_once_with(5)
-        assert mock_loop.create_connection.call_count == 1 #nosec
+        assert mock_loop.create_connection.call_count == 1  # nosec
 
     @pytest.mark.parametrize("protocol", protocols)
-    def test_client_protocol_connection_made(self, protocol): # pylint: disable=no-self-use
-        """ Test the client protocol close. """
+    def test_client_protocol_connection_made(self, protocol):  # pylint: disable=no-self-use
+        """Test the client protocol close."""
         protocol = protocol(ModbusSocketFramer(ClientDecoder()))
         transport = mock.MagicMock()
         factory = mock.MagicMock()
         if isinstance(protocol, ModbusUdpClientProtocol):
             protocol.factory = factory
         protocol.connection_made(transport)
-        assert protocol.transport == transport #nosec
-        assert protocol.connected #nosec
+        assert protocol.transport == transport  # nosec
+        assert protocol.connected  # nosec
         if isinstance(protocol, ModbusUdpClientProtocol):
-            assert protocol.factory.protocol_made_connection.call_count == 1 #nosec
+            assert protocol.factory.protocol_made_connection.call_count == 1  # nosec
 
     @pytest.mark.parametrize("protocol", protocols)
-    def test_client_protocol_close(self, protocol): # pylint: disable=no-self-use
-        """ Test the client protocol close. """
+    def test_client_protocol_close(self, protocol):  # pylint: disable=no-self-use
+        """Test the client protocol close."""
         protocol = protocol(ModbusSocketFramer(ClientDecoder()))
         transport = mock.MagicMock()
         factory = mock.MagicMock()
         if isinstance(protocol, ModbusUdpClientProtocol):
             protocol.factory = factory
         protocol.connection_made(transport)
-        assert protocol.transport == transport #nosec
-        assert protocol.connected #nosec
+        assert protocol.transport == transport  # nosec
+        assert protocol.connected  # nosec
         protocol.close()
         transport.close.assert_called_once_with()
-        assert not protocol.connected #nosec
+        assert not protocol.connected  # nosec
 
     @pytest.mark.skip("To fix")
     @pytest.mark.parametrize("protocol", protocols)
-    def test_client_protocol_connection_lost(self, protocol): # pylint: disable=no-self-use
-        """ Test the client protocol connection lost"""
+    def test_client_protocol_connection_lost(self, protocol):  # pylint: disable=no-self-use
+        """Test the client protocol connection lost"""
         framer = ModbusSocketFramer(None)
         protocol = protocol(framer=framer, timeout=0)
         protocol.execute = mock.MagicMock()
@@ -288,34 +290,34 @@ def test_client_protocol_connection_lost(self, protocol): # pylint: disable=no-s
         # d = await d
         protocol.connection_lost("REASON")
         excp = response.exception()
-        assert isinstance(excp, ConnectionException) #nosec
+        assert isinstance(excp, ConnectionException)  # nosec
         if isinstance(protocol, ModbusUdpClientProtocol):
-            assert protocol.factory.protocol_lost_connection.call_count == 1 #nosec
+            assert protocol.factory.protocol_lost_connection.call_count == 1  # nosec
 
     @pytest.mark.parametrize("protocol", protocols)
-    async def test_client_protocol_data_received(self, protocol): # pylint: disable=no-self-use
-        """ Test the client protocol data received """
+    async def test_client_protocol_data_received(self, protocol):  # pylint: disable=no-self-use
+        """Test the client protocol data received"""
         protocol = protocol(ModbusSocketFramer(ClientDecoder()))
         transport = mock.MagicMock()
         protocol.connection_made(transport)
-        assert protocol.transport == transport #nosec
-        assert protocol.connected #nosec
+        assert protocol.transport == transport  # nosec
+        assert protocol.connected  # nosec
         data = b'\x00\x00\x12\x34\x00\x06\xff\x01\x01\x02\x00\x04'
 
         # setup existing request
-        response = protocol._buildResponse(0x00) # pylint: disable=protected-access
+        response = protocol._buildResponse(0x00)  # pylint: disable=protected-access
         if isinstance(protocol, ModbusUdpClientProtocol):
             protocol.datagram_received(data, None)
         else:
             protocol.data_received(data)
         result = response.result()
-        assert isinstance(result, ReadCoilsResponse) #nosec
+        assert isinstance(result, ReadCoilsResponse)  # nosec
 
     # @pytest.mark.skip("To fix")
     @pytest.mark.asyncio
     @pytest.mark.parametrize("protocol", protocols)
-    async def test_client_protocol_execute(self, protocol): # pylint: disable=no-self-use
-        """ Test the client protocol execute method """
+    async def test_client_protocol_execute(self, protocol):  # pylint: disable=no-self-use
+        """Test the client protocol execute method"""
         framer = ModbusSocketFramer(None)
         protocol = protocol(framer=framer)
         protocol.create_future = mock.MagicMock()
@@ -330,11 +332,11 @@ async def test_client_protocol_execute(self, protocol): # pylint: disable=no-sel
         response = await protocol.execute(request)
         tid = request.transaction_id
         f_trans = protocol.transaction.getTransaction(tid)
-        assert response == f_trans #nosec
+        assert response == f_trans  # nosec
 
     @pytest.mark.parametrize("protocol", protocols)
-    async def test_client_protocol_handle_response(self, protocol): # pylint: disable=no-self-use
-        """ Test the client protocol handles responses """
+    async def test_client_protocol_handle_response(self, protocol):  # pylint: disable=no-self-use
+        """Test the client protocol handles responses"""
         protocol = protocol()
         transport = mock.MagicMock()
         protocol.connection_made(transport=transport)
@@ -344,26 +346,26 @@ async def test_client_protocol_handle_response(self, protocol): # pylint: disabl
         #     import asyncio
         #     protocol.create_future.return_value = asyncio.Future()
         # handle skipped cases
-        protocol._handleResponse(None) # pylint: disable=protected-access
-        protocol._handleResponse(reply) # pylint: disable=protected-access
+        protocol._handleResponse(None)  # pylint: disable=protected-access
+        protocol._handleResponse(reply)  # pylint: disable=protected-access
 
         # handle existing cases
-        response = protocol._buildResponse(0x00) # pylint: disable=protected-access
-        protocol._handleResponse(reply) # pylint: disable=protected-access
+        response = protocol._buildResponse(0x00)  # pylint: disable=protected-access
+        protocol._handleResponse(reply)  # pylint: disable=protected-access
         result = response.result()
-        assert result == reply #nosec
+        assert result == reply  # nosec
 
     @pytest.mark.parametrize("protocol", protocols)
-    async def test_client_protocol_build_response(self, protocol): # pylint: disable=no-self-use
-        """ Test the udp client protocol builds responses """
+    async def test_client_protocol_build_response(self, protocol):  # pylint: disable=no-self-use
+        """Test the udp client protocol builds responses"""
         protocol = protocol()
-        assert not len(list(protocol.transaction)) #nosec pylint: disable=use-implicit-booleaness-not-len
+        assert not len(list(protocol.transaction))  # nosec pylint: disable=use-implicit-booleaness-not-len
 
-        response = protocol._buildResponse(0x00) #nosec pylint: disable=protected-access
+        response = protocol._buildResponse(0x00)  # nosec pylint: disable=protected-access
         excp = response.exception()
-        assert isinstance(excp, ConnectionException) #nosec
-        assert not len(list(protocol.transaction)) #nosec pylint: disable=use-implicit-booleaness-not-len
+        assert isinstance(excp, ConnectionException)  # nosec
+        assert not len(list(protocol.transaction))  # nosec pylint: disable=use-implicit-booleaness-not-len
 
-        protocol._connected = True # pylint: disable=protected-access
-        protocol._buildResponse(0x00) # pylint: disable=protected-access
-        assert len(list(protocol.transaction)) == 1 #nosec
+        protocol._connected = True  # pylint: disable=protected-access
+        protocol._buildResponse(0x00)  # pylint: disable=protected-access
+        assert len(list(protocol.transaction)) == 1  # nosec
diff --git a/test/test_client_async_tornado.py b/test/test_client_async_tornado.py
index 457153229..360b3975b 100644
--- a/test/test_client_async_tornado.py
+++ b/test/test_client_async_tornado.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test client tornado. """
+"""Test client tornado."""
 import unittest
 from unittest.mock import patch, Mock
 import pytest
@@ -23,55 +23,55 @@
 
 
 class AsynchronousClientTest(unittest.TestCase):
-    """ Unittest for the pymodbus.client.asynchronous module. """
+    """Unittest for the pymodbus.client.asynchronous module."""
 
     # -----------------------------------------------------------------------#
     # Test Client client
     # -----------------------------------------------------------------------#
 
     def test_base_client_init(self):
-        """ Test the client client initialize """
+        """Test the client client initialize"""
         client = BaseTornadoClient()
         self.assertTrue(client.port == 502)
         self.assertTrue(client.host == "127.0.0.1")
         self.assertEqual(0, len(list(client.transaction)))
-        self.assertFalse(client._connected) # pylint: disable=protected-access
+        self.assertFalse(client._connected)  # pylint: disable=protected-access
         self.assertTrue(client.io_loop is None)
         self.assertTrue(isinstance(client.framer, ModbusSocketFramer))
 
         framer = object()
         client = BaseTornadoClient(framer=framer, ioloop=schedulers.IO_LOOP)
         self.assertEqual(0, len(list(client.transaction)))
-        self.assertFalse(client._connected) # pylint: disable=protected-access
+        self.assertFalse(client._connected)  # pylint: disable=protected-access
         self.assertTrue(client.io_loop == schedulers.IO_LOOP)
         self.assertTrue(framer is client.framer)
 
     @patch("pymodbus.client.asynchronous.tornado.IOLoop")
     @patch("pymodbus.client.asynchronous.tornado.IOStream")
-    def test_base_client_on_receive(self, mock_iostream, mock_ioloop): # pylint: disable=unused-argument
-        """ Test the BaseTornado client data received """
+    def test_base_client_on_receive(self, mock_iostream, mock_ioloop):  # pylint: disable=unused-argument
+        """Test the BaseTornado client data received"""
         client = AsyncModbusTCPClient(port=5020)
         client.connect()
         out = []
         data = b'\x00\x00\x12\x34\x00\x06\xff\x01\x01\x02\x00\x04'
 
         # setup existing request
-        response = client._build_response(0x00) # pylint: disable=protected-access
-        response.add_done_callback(lambda v: out.append(v)) # pylint: disable=unnecessary-lambda
+        response = client._build_response(0x00)  # pylint: disable=protected-access
+        response.add_done_callback(lambda v: out.append(v))  # pylint: disable=unnecessary-lambda
 
         client.on_receive(data)
         self.assertTrue(isinstance(response.result(), ReadCoilsResponse))
         data = b''
         out = []
-        response = client._build_response(0x01) # pylint: disable=protected-access
+        response = client._build_response(0x01)  # pylint: disable=protected-access
         client.on_receive(data)
-        response.add_done_callback(lambda v: out.append(v)) # pylint: disable=unnecessary-lambda
+        response.add_done_callback(lambda v: out.append(v))  # pylint: disable=unnecessary-lambda
         self.assertFalse(out)
 
     @patch("pymodbus.client.asynchronous.tornado.IOLoop")
     @patch("pymodbus.client.asynchronous.tornado.IOStream")
-    def test_base_client_execute(self, mock_iostream, mock_ioloop): # pylint: disable=unused-argument
-        """ Test the BaseTornado client execute method """
+    def test_base_client_execute(self, mock_iostream, mock_ioloop):  # pylint: disable=unused-argument
+        """Test the BaseTornado client execute method"""
         client = AsyncModbusTCPClient(port=5020)
         client.connect()
         client.stream = Mock()
@@ -84,8 +84,8 @@ def test_base_client_execute(self, mock_iostream, mock_ioloop): # pylint: disabl
 
     @patch("pymodbus.client.asynchronous.tornado.IOLoop")
     @patch("pymodbus.client.asynchronous.tornado.IOStream")
-    def test_base_client_handle_response(self, mock_iostream, mock_ioloop): # pylint: disable=unused-argument
-        """ Test the BaseTornado client handles responses """
+    def test_base_client_handle_response(self, mock_iostream, mock_ioloop):  # pylint: disable=unused-argument
+        """Test the BaseTornado client handles responses"""
         client = AsyncModbusTCPClient(port=5020)
         client.connect()
         out = []
@@ -93,19 +93,19 @@ def test_base_client_handle_response(self, mock_iostream, mock_ioloop): # pylint
         reply.transaction_id = 0x00
 
         # handle skipped cases
-        client._handle_response(None) # pylint: disable=protected-access
-        client._handle_response(reply) # pylint: disable=protected-access
+        client._handle_response(None)  # pylint: disable=protected-access
+        client._handle_response(reply)  # pylint: disable=protected-access
 
         # handle existing cases
-        response = client._build_response(0x00) # pylint: disable=protected-access
-        response.add_done_callback(lambda v: out.append(v)) # pylint: disable=unnecessary-lambda
-        client._handle_response(reply) # pylint: disable=protected-access
+        response = client._build_response(0x00)  # pylint: disable=protected-access
+        response.add_done_callback(lambda v: out.append(v))  # pylint: disable=unnecessary-lambda
+        client._handle_response(reply)  # pylint: disable=protected-access
         self.assertEqual(response.result(), reply)
 
     @patch("pymodbus.client.asynchronous.tornado.IOLoop")
     @patch("pymodbus.client.asynchronous.tornado.IOStream")
-    def test_base_client_build_response(self, mock_iostream, mock_ioloop): # pylint: disable=unused-argument
-        """ Test the BaseTornado client client builds responses """
+    def test_base_client_build_response(self, mock_iostream, mock_ioloop):  # pylint: disable=unused-argument
+        """Test the BaseTornado client client builds responses"""
         client = BaseTornadoClient()
         self.assertEqual(0, len(list(client.transaction)))
 
@@ -113,19 +113,19 @@ def handle_failure(failure):
             exc = failure.exception()
             self.assertTrue(isinstance(exc, ConnectionException))
 
-        response = client._build_response(0x00) # pylint: disable=protected-access
+        response = client._build_response(0x00)  # pylint: disable=protected-access
         response.add_done_callback(handle_failure)
         self.assertEqual(0, len(list(client.transaction)))
 
-        client._connected = True # pylint: disable=protected-access
-        client._build_response(0x00) # pylint: disable=protected-access
+        client._connected = True  # pylint: disable=protected-access
+        client._build_response(0x00)  # pylint: disable=protected-access
         self.assertEqual(1, len(list(client.transaction)))
 
     # -----------------------------------------------------------------------#
     # Test TCP Client client
     # -----------------------------------------------------------------------#
     def test_tcp_client_init(self):
-        """ Test the tornado tcp client client initialize """
+        """Test the tornado tcp client client initialize"""
         client = AsyncModbusTCPClient()
         self.assertEqual(0, len(list(client.transaction)))
         self.assertTrue(isinstance(client.framer, ModbusSocketFramer))
@@ -136,36 +136,36 @@ def test_tcp_client_init(self):
 
     @patch("pymodbus.client.asynchronous.tornado.IOLoop")
     @patch("pymodbus.client.asynchronous.tornado.IOStream")
-    def test_tcp_client_connect(self, mock_iostream, mock_ioloop): # pylint: disable=unused-argument
-        """ Test the tornado tcp client client connect """
+    def test_tcp_client_connect(self, mock_iostream, mock_ioloop):  # pylint: disable=unused-argument
+        """Test the tornado tcp client client connect"""
         client = AsyncModbusTCPClient(port=5020)
         self.assertTrue(client.port, 5020)
-        self.assertFalse(client._connected) # pylint: disable=protected-access
+        self.assertFalse(client._connected)  # pylint: disable=protected-access
         client.connect()
-        self.assertTrue(client._connected) # pylint: disable=protected-access
+        self.assertTrue(client._connected)  # pylint: disable=protected-access
 
     @patch("pymodbus.client.asynchronous.tornado.IOLoop")
     @patch("pymodbus.client.asynchronous.tornado.IOStream")
-    def test_tcp_client_disconnect(self, mock_iostream, mock_ioloop): # pylint: disable=unused-argument
-        """ Test the tornado tcp client client disconnect """
+    def test_tcp_client_disconnect(self, mock_iostream, mock_ioloop):  # pylint: disable=unused-argument
+        """Test the tornado tcp client client disconnect"""
         client = AsyncModbusTCPClient(port=5020)
         client.connect()
 
         def handle_failure(failure):
             self.assertTrue(isinstance(failure.exception(), ConnectionException))
 
-        response = client._build_response(0x00) # pylint: disable=protected-access
+        response = client._build_response(0x00)  # pylint: disable=protected-access
         response.add_done_callback(handle_failure)
 
-        self.assertTrue(client._connected) # pylint: disable=protected-access
+        self.assertTrue(client._connected)  # pylint: disable=protected-access
         client.close()
-        self.assertFalse(client._connected) # pylint: disable=protected-access
+        self.assertFalse(client._connected)  # pylint: disable=protected-access
 
     # -----------------------------------------------------------------------#
     # Test Serial Client client
     # -----------------------------------------------------------------------#
     def test_serial_client_init(self):
-        """ Test the tornado serial client client initialize """
+        """Test the tornado serial client client initialize"""
         client = AsyncModbusSerialClient(ioloop=schedulers.IO_LOOP,
                                          framer=ModbusRtuFramer(
                                              ClientDecoder()),
@@ -180,43 +180,44 @@ def test_serial_client_init(self):
     @patch("pymodbus.client.asynchronous.tornado.IOLoop")
     @patch("pymodbus.client.asynchronous.tornado.SerialIOStream")
     @patch("pymodbus.client.asynchronous.tornado.Serial")
-    def test_serial_client_connect(self, mock_serial, mock_seriostream, mock_ioloop): # pylint: disable=unused-argument
-        """ Test the tornado serial client client connect """
+    def test_serial_client_connect(self, mock_serial, mock_seriostream, mock_ioloop):  # pylint: disable=unused-argument
+        """Test the tornado serial client client connect"""
         client = AsyncModbusSerialClient(ioloop=schedulers.IO_LOOP,
                                          framer=ModbusRtuFramer(
                                              ClientDecoder()),
                                          port=pytest.SERIAL_PORT)
         self.assertTrue(client.port, pytest.SERIAL_PORT)
-        self.assertFalse(client._connected) # pylint: disable=protected-access
+        self.assertFalse(client._connected)  # pylint: disable=protected-access
         client.connect()
-        self.assertTrue(client._connected) # pylint: disable=protected-access
+        self.assertTrue(client._connected)  # pylint: disable=protected-access
         client.close()
 
     @patch("pymodbus.client.asynchronous.tornado.IOLoop")
     @patch("pymodbus.client.asynchronous.tornado.SerialIOStream")
     @patch("pymodbus.client.asynchronous.tornado.Serial")
-    def test_serial_client_disconnect(self, mock_serial, mock_seriostream, mock_ioloop): # pylint: disable=unused-argument
-        """ Test the tornado serial client client disconnect """
+    def test_serial_client_disconnect(self, mock_serial,  # pylint: disable=unused-argument
+                                      mock_seriostream, mock_ioloop):  # pylint: disable=unused-argument
+        """Test the tornado serial client client disconnect"""
         client = AsyncModbusSerialClient(ioloop=schedulers.IO_LOOP,
                                          framer=ModbusRtuFramer(
                                              ClientDecoder()),
                                          port=pytest.SERIAL_PORT)
         client.connect()
-        self.assertTrue(client._connected) # pylint: disable=protected-access
+        self.assertTrue(client._connected)  # pylint: disable=protected-access
 
         def handle_failure(failure):
             self.assertTrue(isinstance(failure.exception(), ConnectionException))
 
-        response = client._build_response(0x00) # pylint: disable=protected-access
+        response = client._build_response(0x00)  # pylint: disable=protected-access
         response.add_done_callback(handle_failure)
         client.close()
-        self.assertFalse(client._connected) # pylint: disable=protected-access
+        self.assertFalse(client._connected)  # pylint: disable=protected-access
 
     @patch("pymodbus.client.asynchronous.tornado.IOLoop")
     @patch("pymodbus.client.asynchronous.tornado.SerialIOStream")
     @patch("pymodbus.client.asynchronous.tornado.Serial")
-    def test_serial_client_execute(self, mock_serial, mock_seriostream, mock_ioloop): # pylint: disable=unused-argument
-        """ Test the tornado serial client client execute method """
+    def test_serial_client_execute(self, mock_serial, mock_seriostream, mock_ioloop):  # pylint: disable=unused-argument
+        """Test the tornado serial client client execute method"""
         client = AsyncModbusSerialClient(ioloop=schedulers.IO_LOOP,
                                          framer=ModbusRtuFramer(
                                              ClientDecoder()),
@@ -235,8 +236,9 @@ def test_serial_client_execute(self, mock_serial, mock_seriostream, mock_ioloop)
     @patch("pymodbus.client.asynchronous.tornado.IOLoop")
     @patch("pymodbus.client.asynchronous.tornado.SerialIOStream")
     @patch("pymodbus.client.asynchronous.tornado.Serial")
-    def test_serial_client_handle_response(self, mock_serial, mock_seriostream, mock_ioloop): # pylint: disable=unused-argument
-        """ Test the tornado serial client client handles responses """
+    def test_serial_client_handle_response(self, mock_serial,  # pylint: disable=unused-argument
+                                           mock_seriostream, mock_ioloop):  # pylint: disable=unused-argument
+        """Test the tornado serial client client handles responses"""
         client = AsyncModbusSerialClient(ioloop=schedulers.IO_LOOP,
                                          framer=ModbusRtuFramer(
                                              ClientDecoder()),
@@ -247,20 +249,23 @@ def test_serial_client_handle_response(self, mock_serial, mock_seriostream, mock
         reply.transaction_id = 0x00
 
         # handle skipped cases
-        client._handle_response(None) # pylint: disable=protected-access
-        client._handle_response(reply) # pylint: disable=protected-access
+        client._handle_response(None)  # pylint: disable=protected-access
+        client._handle_response(reply)  # pylint: disable=protected-access
 
         # handle existing cases
-        response = client._build_response(0x00) # pylint: disable=protected-access
-        response.add_done_callback(lambda v: out.append(v)) # pylint: disable=unnecessary-lambda
-        client._handle_response(reply) # pylint: disable=protected-access
+        response = client._build_response(0x00)  # pylint: disable=protected-access
+        response.add_done_callback(lambda v: out.append(v))  # pylint: disable=unnecessary-lambda
+        client._handle_response(reply)  # pylint: disable=protected-access
         self.assertEqual(response.result(), reply)
 
     @patch("pymodbus.client.asynchronous.tornado.IOLoop")
     @patch("pymodbus.client.asynchronous.tornado.SerialIOStream")
     @patch("pymodbus.client.asynchronous.tornado.Serial")
-    def test_serial_client_build_response(self, mock_serial, mock_seriostream, mock_ioloop): # pylint: disable=unused-argument
-        """ Test the tornado serial client client builds responses """
+    def test_serial_client_build_response(self,
+                                          mock_serial,  # pylint: disable=unused-argument
+                                          mock_seriostream,  # pylint: disable=unused-argument
+                                          mock_ioloop):  # pylint: disable=unused-argument
+        """Test the tornado serial client client builds responses"""
         client = AsyncModbusSerialClient(ioloop=schedulers.IO_LOOP,
                                          framer=ModbusRtuFramer(
                                              ClientDecoder()),
@@ -270,12 +275,12 @@ def test_serial_client_build_response(self, mock_serial, mock_seriostream, mock_
         def handle_failure(failure):
             exc = failure.exception()
             self.assertTrue(isinstance(exc, ConnectionException))
-        response = client._build_response(0x00) # pylint: disable=protected-access
+        response = client._build_response(0x00)  # pylint: disable=protected-access
         response.add_done_callback(handle_failure)
         self.assertEqual(0, len(list(client.transaction)))
 
-        client._connected = True # pylint: disable=protected-access
-        client._build_response(0x00) # pylint: disable=protected-access
+        client._connected = True  # pylint: disable=protected-access
+        client._build_response(0x00)  # pylint: disable=protected-access
         self.assertEqual(1, len(list(client.transaction)))
 
     # -----------------------------------------------------------------------#
@@ -283,7 +288,7 @@ def handle_failure(failure):
     # -----------------------------------------------------------------------#
 
     def test_udp_client_init(self):
-        """ Test the udp client client initialize """
+        """Test the udp client client initialize"""
         client = AsyncModbusUDPClient()
         self.assertEqual(0, len(list(client.transaction)))
         self.assertTrue(isinstance(client.framer, ModbusSocketFramer))
@@ -297,7 +302,7 @@ def test_udp_client_init(self):
     # -----------------------------------------------------------------------#
 
     def test_modbus_client_factory(self):
-        """ Test the base class for all the clients """
+        """Test the base class for all the clients"""
         factory = ModbusClientFactory()
         self.assertTrue(factory is not None)
 
diff --git a/test/test_client_async_twisted.py b/test/test_client_async_twisted.py
index 29024edc9..2af906a16 100644
--- a/test/test_client_async_twisted.py
+++ b/test/test_client_async_twisted.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test client async twisted. """
+"""Test client async twisted."""
 import unittest
 from unittest.mock import Mock
 
@@ -15,68 +15,70 @@
 from pymodbus.transaction import ModbusSocketFramer, ModbusRtuFramer
 from pymodbus.bit_read_message import ReadCoilsRequest, ReadCoilsResponse
 
-#---------------------------------------------------------------------------#
-# Fixture
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Fixture
+# ---------------------------------------------------------------------------#
+
 
 class AsynchronousClientTest(unittest.TestCase):
-    """ Unittest for the pymodbus.client.asynchronous module. """
+    """Unittest for the pymodbus.client.asynchronous module."""
 
-    #-----------------------------------------------------------------------#
-    # Test Client Protocol
-    #-----------------------------------------------------------------------#
+    # -----------------------------------------------------------------------#
+    #  Test Client Protocol
+    # -----------------------------------------------------------------------#
 
     def test_client_protocol_init(self):
-        """ Test the client protocol initialize """
+        """Test the client protocol initialize"""
         protocol = ModbusClientProtocol()
         self.assertEqual(0, len(list(protocol.transaction)))
-        self.assertFalse(protocol._connected) # pylint: disable=protected-access
+        self.assertFalse(protocol._connected)  # pylint: disable=protected-access
         self.assertTrue(isinstance(protocol.framer, ModbusSocketFramer))
 
         framer = object()
         protocol = ModbusClientProtocol(framer=framer)
         self.assertEqual(0, len(list(protocol.transaction)))
-        self.assertFalse(protocol._connected) # pylint: disable=protected-access
+        self.assertFalse(protocol._connected)  # pylint: disable=protected-access
         self.assertTrue(framer is protocol.framer)
 
     def test_client_protocol_connect(self):
-        """ Test the client protocol connect """
+        """Test the client protocol connect"""
         decoder = object()
         framer = ModbusSocketFramer(decoder)
         protocol = ModbusClientProtocol(framer=framer)
-        self.assertFalse(protocol._connected) # pylint: disable=protected-access
+        self.assertFalse(protocol._connected)  # pylint: disable=protected-access
         protocol.connectionMade()
-        self.assertTrue(protocol._connected) # pylint: disable=protected-access
+        self.assertTrue(protocol._connected)  # pylint: disable=protected-access
 
     def test_client_protocol_disconnect(self):
-        """ Test the client protocol disconnect """
+        """Test the client protocol disconnect"""
         protocol = ModbusClientProtocol()
         protocol.connectionMade()
+
         def handle_failure(failure):
             self.assertTrue(isinstance(failure.value, ConnectionException))
-        response = protocol._buildResponse(0x00) # pylint: disable=protected-access
+        response = protocol._buildResponse(0x00)  # pylint: disable=protected-access
         response.addErrback(handle_failure)
 
-        self.assertTrue(protocol._connected) # pylint: disable=protected-access
+        self.assertTrue(protocol._connected)  # pylint: disable=protected-access
         protocol.connectionLost('because')
-        self.assertFalse(protocol._connected) # pylint: disable=protected-access
+        self.assertFalse(protocol._connected)  # pylint: disable=protected-access
 
     def test_client_protocol_data_received(self):
-        """ Test the client protocol data received """
+        """Test the client protocol data received"""
         protocol = ModbusClientProtocol(ModbusSocketFramer(ClientDecoder()))
         protocol.connectionMade()
         out = []
         data = b'\x00\x00\x12\x34\x00\x06\xff\x01\x01\x02\x00\x04'
 
         # setup existing request
-        response = protocol._buildResponse(0x00) # pylint: disable=protected-access
-        response.addCallback(lambda v: out.append(v)) # pylint: disable=unnecessary-lambda
+        response = protocol._buildResponse(0x00)  # pylint: disable=protected-access
+        response.addCallback(lambda v: out.append(v))  # pylint: disable=unnecessary-lambda
 
         protocol.dataReceived(data)
         self.assertTrue(isinstance(out[0], ReadCoilsResponse))
 
     def test_client_protocol_execute(self):
-        """ Test the client protocol execute method """
+        """Test the client protocol execute method"""
         framer = ModbusSocketFramer(None)
         protocol = ModbusClientProtocol(framer=framer)
         protocol.connectionMade()
@@ -89,7 +91,7 @@ def test_client_protocol_execute(self):
         self.assertEqual(response, protocol.transaction.getTransaction(tid))
 
     def test_client_protocol_handle_response(self):
-        """ Test the client protocol handles responses """
+        """Test the client protocol handles responses"""
         protocol = ModbusClientProtocol()
         protocol.connectionMade()
         out = []
@@ -97,35 +99,35 @@ def test_client_protocol_handle_response(self):
         reply.transaction_id = 0x00
 
         # handle skipped cases
-        protocol._handleResponse(None) # pylint: disable=protected-access
-        protocol._handleResponse(reply) # pylint: disable=protected-access
+        protocol._handleResponse(None)  # pylint: disable=protected-access
+        protocol._handleResponse(reply)  # pylint: disable=protected-access
 
         # handle existing cases
-        response = protocol._buildResponse(0x00) # pylint: disable=protected-access
-        response.addCallback(lambda v: out.append(v)) # pylint: disable=unnecessary-lambda
-        protocol._handleResponse(reply) # pylint: disable=protected-access
+        response = protocol._buildResponse(0x00)  # pylint: disable=protected-access
+        response.addCallback(lambda v: out.append(v))  # pylint: disable=unnecessary-lambda
+        protocol._handleResponse(reply)  # pylint: disable=protected-access
         self.assertEqual(out[0], reply)
 
     def test_client_protocol_build_response(self):
-        """ Test the udp client protocol builds responses """
+        """Test the udp client protocol builds responses"""
         protocol = ModbusClientProtocol()
         self.assertEqual(0, len(list(protocol.transaction)))
 
         def handle_failure(failure):
             self.assertTrue(isinstance(failure.value, ConnectionException))
-        response = protocol._buildResponse(0x00) # pylint: disable=protected-access
+        response = protocol._buildResponse(0x00)  # pylint: disable=protected-access
         response.addErrback(handle_failure)
         self.assertEqual(0, len(list(protocol.transaction)))
 
-        protocol._connected = True # pylint: disable=protected-access
-        protocol._buildResponse(0x00) # pylint: disable=protected-access
+        protocol._connected = True  # pylint: disable=protected-access
+        protocol._buildResponse(0x00)  # pylint: disable=protected-access
         self.assertEqual(1, len(list(protocol.transaction)))
 
-    #-----------------------------------------------------------------------#
-    # Test TCP Client Protocol
-    #-----------------------------------------------------------------------#
+    # -----------------------------------------------------------------------#
+    #  Test TCP Client Protocol
+    # -----------------------------------------------------------------------#
     def test_tcp_client_protocol_init(self):
-        """ Test the udp client protocol initialize """
+        """Test the udp client protocol initialize"""
         protocol = ModbusTcpClientProtocol()
         self.assertEqual(0, len(list(protocol.transaction)))
         self.assertTrue(isinstance(protocol.framer, ModbusSocketFramer))
@@ -134,11 +136,11 @@ def test_tcp_client_protocol_init(self):
         protocol = ModbusClientProtocol(framer=framer)
         self.assertTrue(framer is protocol.framer)
 
-    #-----------------------------------------------------------------------#
-    # Test Serial Client Protocol
-    #-----------------------------------------------------------------------#
+    # -----------------------------------------------------------------------#
+    #  Test Serial Client Protocol
+    # -----------------------------------------------------------------------#
     def test_serial_client_protocol_init(self):
-        """ Test the udp client protocol initialize """
+        """Test the udp client protocol initialize"""
         protocol = ModbusSerClientProtocol()
         self.assertEqual(0, len(list(protocol.transaction)))
         self.assertTrue(isinstance(protocol.framer, ModbusRtuFramer))
@@ -147,12 +149,12 @@ def test_serial_client_protocol_init(self):
         protocol = ModbusClientProtocol(framer=framer)
         self.assertTrue(framer is protocol.framer)
 
-    #-----------------------------------------------------------------------#
-    # Test Udp Client Protocol
-    #-----------------------------------------------------------------------#
+    # -----------------------------------------------------------------------#
+    #  Test Udp Client Protocol
+    # -----------------------------------------------------------------------#
 
     def test_udp_client_protocol_init(self):
-        """ Test the udp client protocol initialize """
+        """Test the udp client protocol initialize"""
         protocol = ModbusUdpClientProtocol()
         self.assertEqual(0, len(list(protocol.transaction)))
         self.assertTrue(isinstance(protocol.framer, ModbusSocketFramer))
@@ -162,21 +164,21 @@ def test_udp_client_protocol_init(self):
         self.assertTrue(framer is protocol.framer)
 
     def test_udp_client_protocol_data_received(self):
-        """ Test the udp client protocol data received """
+        """Test the udp client protocol data received"""
         protocol = ModbusUdpClientProtocol()
         out = []
         data = b'\x00\x00\x12\x34\x00\x06\xff\x01\x01\x02\x00\x04'
         server = ('127.0.0.1', 12345)
 
         # setup existing request
-        response = protocol._buildResponse(0x00) # pylint: disable=protected-access
-        response.addCallback(lambda v: out.append(v)) # pylint: disable=unnecessary-lambda
+        response = protocol._buildResponse(0x00)  # pylint: disable=protected-access
+        response.addCallback(lambda v: out.append(v))  # pylint: disable=unnecessary-lambda
 
         protocol.datagramReceived(data, server)
         self.assertTrue(isinstance(out[0], ReadCoilsResponse))
 
     def test_udp_client_protocol_execute(self):
-        """ Test the udp client protocol execute method """
+        """Test the udp client protocol execute method"""
         protocol = ModbusUdpClientProtocol()
         protocol.transport = Mock()
         protocol.transport.write = Mock()
@@ -187,41 +189,42 @@ def test_udp_client_protocol_execute(self):
         self.assertEqual(response, protocol.transaction.getTransaction(tid))
 
     def test_udp_client_protocol_handle_response(self):
-        """ Test the udp client protocol handles responses """
+        """Test the udp client protocol handles responses"""
         protocol = ModbusUdpClientProtocol()
         out = []
         reply = ReadCoilsRequest(1, 1)
         reply.transaction_id = 0x00
 
         # handle skipped cases
-        protocol._handleResponse(None) # pylint: disable=protected-access
-        protocol._handleResponse(reply) # pylint: disable=protected-access
+        protocol._handleResponse(None)  # pylint: disable=protected-access
+        protocol._handleResponse(reply)  # pylint: disable=protected-access
 
         # handle existing cases
-        response = protocol._buildResponse(0x00) # pylint: disable=protected-access
-        response.addCallback(lambda v: out.append(v)) # pylint: disable=unnecessary-lambda
-        protocol._handleResponse(reply) # pylint: disable=protected-access
+        response = protocol._buildResponse(0x00)  # pylint: disable=protected-access
+        response.addCallback(lambda v: out.append(v))  # pylint: disable=unnecessary-lambda
+        protocol._handleResponse(reply)  # pylint: disable=protected-access
         self.assertEqual(out[0], reply)
 
     def test_udp_client_protocol_build_response(self):
-        """ Test the udp client protocol builds responses """
+        """Test the udp client protocol builds responses"""
         protocol = ModbusUdpClientProtocol()
         self.assertEqual(0, len(list(protocol.transaction)))
 
-        protocol._buildResponse(0x00) # pylint: disable=protected-access
+        protocol._buildResponse(0x00)  # pylint: disable=protected-access
         self.assertEqual(1, len(list(protocol.transaction)))
 
-    #-----------------------------------------------------------------------#
-    # Test Client Factories
-    #-----------------------------------------------------------------------#
+    # -----------------------------------------------------------------------#
+    #  Test Client Factories
+    # -----------------------------------------------------------------------#
 
     def test_modbus_client_factory(self):
-        """ Test the base class for all the clients """
+        """Test the base class for all the clients"""
         factory = ModbusClientFactory()
         self.assertTrue(factory is not None)
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_client_common.py b/test/test_client_common.py
index d6544ccee..83be96b71 100644
--- a/test/test_client_common.py
+++ b/test/test_client_common.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test client common. """
+"""Test client common."""
 import unittest
 from pymodbus.client.common import ModbusClientMixin
 from pymodbus.bit_read_message import (
@@ -21,62 +21,64 @@
     WriteSingleRegisterRequest,
 )
 
-#---------------------------------------------------------------------------#
-# Mocks
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Mocks
+# ---------------------------------------------------------------------------#
+
+
 class MockClient(ModbusClientMixin):
-    """ Mock client. """
+    """Mock client."""
 
-    def execute(self, request): # pylint: disable=no-self-use
-        """ Mock execute. """
+    def execute(self, request):  # pylint: disable=no-self-use
+        """Mock execute."""
         return request
 
-#---------------------------------------------------------------------------#
-# Fixture
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Fixture
+# ---------------------------------------------------------------------------#
+
+
 class ModbusCommonClientTests(unittest.TestCase):
-    """ Modbus common client tests. """
+    """Modbus common client tests."""
 
-    #-----------------------------------------------------------------------#
-    # Setup/TearDown
-    #-----------------------------------------------------------------------#
+    # -----------------------------------------------------------------------#
+    #  Setup/TearDown
+    # -----------------------------------------------------------------------#
     def setUp(self):
-        """ Initializes the test environment and builds request/result
-        encoding pairs
-        """
+        """Initialize the test environment and builds request/result encoding pairs."""
         self.client = MockClient()
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
         del self.client
 
-    #-----------------------------------------------------------------------#
-    # Tests
-    #-----------------------------------------------------------------------#
+    # -----------------------------------------------------------------------#
+    #  Tests
+    # -----------------------------------------------------------------------#
     def test_modbus_client_mixin_methods(self):
-        """ This tests that the mixing returns the correct request object """
+        """This tests that the mixing returns the correct request object"""
         arguments = {
             'read_address': 1, 'read_count': 1,
             'write_address': 1, 'write_registers': 1
         }
         self.assertTrue(
-            isinstance(self.client.read_coils(1,1), ReadCoilsRequest))
+            isinstance(self.client.read_coils(1, 1), ReadCoilsRequest))
         self.assertTrue(
-            isinstance(self.client.read_discrete_inputs(1,1), ReadDiscreteInputsRequest))
+            isinstance(self.client.read_discrete_inputs(1, 1), ReadDiscreteInputsRequest))
         self.assertTrue(
-            isinstance(self.client.write_coil(1,True), WriteSingleCoilRequest))
+            isinstance(self.client.write_coil(1, True), WriteSingleCoilRequest))
         self.assertTrue(
-            isinstance(self.client.write_coils(1,[True]), WriteMultipleCoilsRequest))
+            isinstance(self.client.write_coils(1, [True]), WriteMultipleCoilsRequest))
         self.assertTrue(
-            isinstance(self.client.write_register(1,0x00), WriteSingleRegisterRequest))
+            isinstance(self.client.write_register(1, 0x00), WriteSingleRegisterRequest))
         self.assertTrue(
-            isinstance(self.client.write_registers(1,[0x00]), WriteMultipleRegistersRequest))
+            isinstance(self.client.write_registers(1, [0x00]), WriteMultipleRegistersRequest))
         self.assertTrue(
-            isinstance(self.client.read_holding_registers(1,1), ReadHoldingRegistersRequest))
+            isinstance(self.client.read_holding_registers(1, 1), ReadHoldingRegistersRequest))
         self.assertTrue(
-            isinstance(self.client.read_input_registers(1,1), ReadInputRegistersRequest))
+            isinstance(self.client.read_input_registers(1, 1), ReadInputRegistersRequest))
         self.assertTrue(
             isinstance(self.client.readwrite_registers(**arguments),
-                ReadWriteMultipleRegistersRequest))
+                       ReadWriteMultipleRegistersRequest))
         self.assertTrue(
-            isinstance(self.client.mask_write_register(1,0,0), MaskWriteRegisterRequest))
+            isinstance(self.client.mask_write_register(1, 0, 0), MaskWriteRegisterRequest))
diff --git a/test/test_client_sync.py b/test/test_client_sync.py
index c9eb8e20a..0a3cb39f1 100755
--- a/test/test_client_sync.py
+++ b/test/test_client_sync.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test client sync. """
+"""Test client sync."""
 import socket
 import ssl
 import sys
@@ -25,44 +25,45 @@
 # ---------------------------------------------------------------------------#
 # Mock Classes
 # ---------------------------------------------------------------------------#
-class mockSocket: #NOSONAR pylint: disable=invalid-name
-    """ Mock socket. """
+class mockSocket:  # NOSONAR pylint: disable=invalid-name
+    """Mock socket."""
+
     timeout = 2
 
-    def close(self): # pylint: disable=no-self-use
-        """ Close. """
+    def close(self):  # pylint: disable=no-self-use
+        """Close."""
         return True
 
-    def recv(self, size): # pylint: disable=no-self-use
-        """ Receive. """
+    def recv(self, size):  # pylint: disable=no-self-use
+        """Receive."""
         return b'\x00' * size
 
-    def read(self, size): # pylint: disable=no-self-use
-        """ Read. """
+    def read(self, size):  # pylint: disable=no-self-use
+        """Read."""
         return b'\x00' * size
 
-    def send(self, msg): # pylint: disable=no-self-use
-        """ Send. """
+    def send(self, msg):  # pylint: disable=no-self-use
+        """Send."""
         return len(msg)
 
-    def write(self, msg): # pylint: disable=no-self-use
-        """ Write. """
+    def write(self, msg):  # pylint: disable=no-self-use
+        """Write."""
         return len(msg)
 
-    def recvfrom(self, size): # pylint: disable=no-self-use
-        """ Receive from. """
+    def recvfrom(self, size):  # pylint: disable=no-self-use
+        """Receive from."""
         return [b'\x00' * size]
 
-    def sendto(self, msg, *args): #NOSONAR pylint: disable=no-self-use,unused-argument
-        """ Send to. """
+    def sendto(self, msg, *args):  # NOSONAR pylint: disable=no-self-use,unused-argument
+        """Send to."""
         return len(msg)
 
-    def setblocking(self, flag): #NOSONAR pylint: disable=no-self-use,unused-argument
-        """ Set blocking. """
+    def setblocking(self, flag):  # NOSONAR pylint: disable=no-self-use,unused-argument
+        """Set blocking."""
         return None
 
-    def in_waiting(self): # pylint: disable=no-self-use
-        """ in waiting. """
+    def in_waiting(self):  # pylint: disable=no-self-use
+        """Do in waiting."""
         return None
 
 
@@ -75,28 +76,27 @@ def in_waiting(self): # pylint: disable=no-self-use
 )
 
 
-
 # ---------------------------------------------------------------------------#
 # Fixture
 # ---------------------------------------------------------------------------#
-class SynchronousClientTest(unittest.TestCase): # pylint: disable=too-many-public-methods
-    """ Unittest for the pymodbus.client.sync module. """
+class SynchronousClientTest(unittest.TestCase):  # pylint: disable=too-many-public-methods
+    """Unittest for the pymodbus.client.sync module."""
 
     # -----------------------------------------------------------------------#
     # Test Base Client
     # -----------------------------------------------------------------------#
 
     def test_base_modbus_client(self):
-        """ Test the base class for all the clients """
-
+        """Test the base class for all the clients"""
         client = BaseModbusClient(None)
         client.transaction = None
-        self.assertRaises(NotImplementedException, lambda: client.connect()) # pylint: disable=unnecessary-lambda
+        self.assertRaises(NotImplementedException, lambda: client.connect())  # pylint: disable=unnecessary-lambda
         self.assertRaises(NotImplementedException, lambda: client.send(None))
         self.assertRaises(NotImplementedException, lambda: client.recv(None))
-        self.assertRaises(NotImplementedException, lambda: client.__enter__()) # pylint: disable=unnecessary-lambda
-        self.assertRaises(NotImplementedException, lambda: client.execute()) # pylint: disable=unnecessary-lambda
-        self.assertRaises(NotImplementedException, lambda: client.is_socket_open()) # pylint: disable=unnecessary-lambda
+        self.assertRaises(NotImplementedException, lambda: client.__enter__())  # pylint: disable=unnecessary-lambda
+        self.assertRaises(NotImplementedException, lambda: client.execute())  # pylint: disable=unnecessary-lambda
+        self.assertRaises(NotImplementedException, lambda: client.is_socket_open()  # pylint: disable=unnecessary-lambda
+                          )  # pylint: disable=unnecessary-lambda
         self.assertEqual("Null Transport", str(client))
         client.close()
         client.__exit__(0, 0, 0)
@@ -112,7 +112,7 @@ def test_base_modbus_client(self):
         self.assertEqual(False, client.debug_enabled())
         writable = StringIO()
         client.trace(writable)
-        client._dump(b'\x00\x01\x02') # pylint: disable=protected-access
+        client._dump(b'\x00\x01\x02')  # pylint: disable=protected-access
         self.assertEqual(hexlify_packets(b'\x00\x01\x02'), writable.getvalue())
 
         # a successful execute
@@ -123,27 +123,26 @@ def test_base_modbus_client(self):
 
         # a unsuccessful connect
         client.connect = lambda: False
-        self.assertRaises(ConnectionException, lambda: client.__enter__()) # pylint: disable=unnecessary-lambda
-        self.assertRaises(ConnectionException, lambda: client.execute()) # pylint: disable=unnecessary-lambda
+        self.assertRaises(ConnectionException, lambda: client.__enter__())  # pylint: disable=unnecessary-lambda
+        self.assertRaises(ConnectionException, lambda: client.execute())  # pylint: disable=unnecessary-lambda
 
     # -----------------------------------------------------------------------#
     # Test UDP Client
     # -----------------------------------------------------------------------#
 
     def test_sync_udp_client_instantiation(self):
-        """ Test sync udp clientt. """
+        """Test sync udp clientt."""
         client = ModbusUdpClient()
         self.assertNotEqual(client, None)
 
     def tes_basic_sync_udp_client(self):
-        """ Test the basic methods for the udp sync client"""
-
+        """Test the basic methods for the udp sync client"""
         # receive/send
         client = ModbusUdpClient()
         client.socket = mockSocket()
-        self.assertEqual(0, client._send(None)) # pylint: disable=protected-access
-        self.assertEqual(1, client._send(b'\x00')) # pylint: disable=protected-access
-        self.assertEqual(b'\x00', client._recv(1)) # pylint: disable=protected-access
+        self.assertEqual(0, client._send(None))  # pylint: disable=protected-access
+        self.assertEqual(1, client._send(b'\x00'))  # pylint: disable=protected-access
+        self.assertEqual(b'\x00', client._recv(1))  # pylint: disable=protected-access
 
         # connect/disconnect
         self.assertTrue(client.connect())
@@ -157,20 +156,21 @@ def tes_basic_sync_udp_client(self):
 
     @inet_pton_skipif
     def test_udp_client_address_family(self):
-        """ Test the Udp client get address family method"""
+        """Test the Udp client get address family method"""
         client = ModbusUdpClient()
         self.assertEqual(socket.AF_INET,
-                         client._get_address_family('127.0.0.1')) # pylint: disable=protected-access
-        self.assertEqual(socket.AF_INET6, client._get_address_family('::1')) # pylint: disable=protected-access
+                         client._get_address_family('127.0.0.1'))  # pylint: disable=protected-access
+        self.assertEqual(socket.AF_INET6, client._get_address_family('::1'))  # pylint: disable=protected-access
 
     @inet_pton_skipif
     def test_udp_client_connect(self):
-        """ Test the Udp client connection method"""
+        """Test the Udp client connection method"""
         with patch.object(socket, 'socket') as mock_method:
-            class DummySocket: # pylint: disable=too-few-public-methods
-                """ Dummy socket. """
+            class DummySocket:  # pylint: disable=too-few-public-methods
+                """Dummy socket."""
+
                 def settimeout(self, *a, **kwa):
-                    """ Set timeout. """
+                    """Set timeout."""
 
             mock_method.return_value = DummySocket()
             client = ModbusUdpClient()
@@ -183,30 +183,30 @@ def settimeout(self, *a, **kwa):
 
     @inet_pton_skipif
     def test_udp_client_is_socket_open(self):
-        """ Test the udp client is_socket_open method"""
+        """Test the udp client is_socket_open method"""
         client = ModbusUdpClient()
         self.assertTrue(client.is_socket_open())
 
     def test_udp_client_send(self):
-        """ Test the udp client send method"""
+        """Test the udp client send method"""
         client = ModbusUdpClient()
-        self.assertRaises(ConnectionException, lambda: client._send(None)) # pylint: disable=protected-access
+        self.assertRaises(ConnectionException, lambda: client._send(None))  # pylint: disable=protected-access
 
         client.socket = mockSocket()
-        self.assertEqual(0, client._send(None)) # pylint: disable=protected-access
-        self.assertEqual(4, client._send('1234')) # pylint: disable=protected-access
+        self.assertEqual(0, client._send(None))  # pylint: disable=protected-access
+        self.assertEqual(4, client._send('1234'))  # pylint: disable=protected-access
 
     def test_udp_client_recv(self):
-        """ Test the udp client receive method"""
+        """Test the udp client receive method"""
         client = ModbusUdpClient()
-        self.assertRaises(ConnectionException, lambda: client._recv(1024)) # pylint: disable=protected-access
+        self.assertRaises(ConnectionException, lambda: client._recv(1024))  # pylint: disable=protected-access
 
         client.socket = mockSocket()
-        self.assertEqual(b'', client._recv(0)) # pylint: disable=protected-access
-        self.assertEqual(b'\x00' * 4, client._recv(4)) # pylint: disable=protected-access
+        self.assertEqual(b'', client._recv(0))  # pylint: disable=protected-access
+        self.assertEqual(b'\x00' * 4, client._recv(4))  # pylint: disable=protected-access
 
     def test_udp_client_repr(self):
-        """ Test udp client representation. """
+        """Test udp client representation."""
         client = ModbusUdpClient()
         rep = f"<{client.__class__.__name__} at {hex(id(client))} socket={client.socket}, "\
               f"ipaddr={client.host}, port={client.port}, timeout={client.timeout}>"
@@ -217,21 +217,20 @@ def test_udp_client_repr(self):
     # -----------------------------------------------------------------------#
 
     def test_sync_tcp_client_instantiation(self):
-        """ Test sync tcp client. """
+        """Test sync tcp client."""
         client = ModbusTcpClient()
         self.assertNotEqual(client, None)
 
     @patch('pymodbus.client.sync.select')
     def test_basic_sync_tcp_client(self, mock_select):
-        """ Test the basic methods for the tcp sync client"""
-
+        """Test the basic methods for the tcp sync client"""
         # receive/send
         mock_select.select.return_value = [True]
         client = ModbusTcpClient()
         client.socket = mockSocket()
-        self.assertEqual(0, client._send(None)) # pylint: disable=protected-access
-        self.assertEqual(1, client._send(b'\x00')) # pylint: disable=protected-access
-        self.assertEqual(b'\x00', client._recv(1)) # pylint: disable=protected-access
+        self.assertEqual(0, client._send(None))  # pylint: disable=protected-access
+        self.assertEqual(1, client._send(b'\x00'))  # pylint: disable=protected-access
+        self.assertEqual(b'\x00', client._recv(1))  # pylint: disable=protected-access
 
         # connect/disconnect
         self.assertTrue(client.connect())
@@ -244,7 +243,7 @@ def test_basic_sync_tcp_client(self, mock_select):
         self.assertEqual("ModbusTcpClient(127.0.0.1:502)", str(client))
 
     def test_tcp_client_connect(self):
-        """ Test the tcp client connection method"""
+        """Test the tcp client connection method"""
         with patch.object(socket, 'create_connection') as mock_method:
             _socket = MagicMock()
             mock_method.return_value = _socket
@@ -258,66 +257,66 @@ def test_tcp_client_connect(self):
             self.assertFalse(client.connect())
 
     def test_tcp_client_is_socket_open(self):
-        """ Test the tcp client is_socket_open method"""
+        """Test the tcp client is_socket_open method"""
         client = ModbusTcpClient()
         self.assertFalse(client.is_socket_open())
 
     def test_tcp_client_send(self):
-        """ Test the tcp client send method"""
+        """Test the tcp client send method"""
         client = ModbusTcpClient()
-        self.assertRaises(ConnectionException, lambda: client._send(None)) # pylint: disable=protected-access
+        self.assertRaises(ConnectionException, lambda: client._send(None))  # pylint: disable=protected-access
 
         client.socket = mockSocket()
-        self.assertEqual(0, client._send(None)) # pylint: disable=protected-access
-        self.assertEqual(4, client._send('1234')) # pylint: disable=protected-access
+        self.assertEqual(0, client._send(None))  # pylint: disable=protected-access
+        self.assertEqual(4, client._send('1234'))  # pylint: disable=protected-access
 
     @patch('pymodbus.client.sync.time')
     @patch('pymodbus.client.sync.select')
     def test_tcp_client_recv(self, mock_select, mock_time):
-        """ Test the tcp client receive method"""
-
+        """Test the tcp client receive method"""
         mock_select.select.return_value = [True]
         mock_time.time.side_effect = count()
         client = ModbusTcpClient()
-        self.assertRaises(ConnectionException, lambda: client._recv(1024)) # pylint: disable=protected-access
+        self.assertRaises(ConnectionException, lambda: client._recv(1024))  # pylint: disable=protected-access
 
         client.socket = mockSocket()
-        self.assertEqual(b'', client._recv(0)) # pylint: disable=protected-access
-        self.assertEqual(b'\x00' * 4, client._recv(4)) # pylint: disable=protected-access
+        self.assertEqual(b'', client._recv(0))  # pylint: disable=protected-access
+        self.assertEqual(b'\x00' * 4, client._recv(4))  # pylint: disable=protected-access
 
         mock_socket = MagicMock()
         mock_socket.recv.side_effect = iter([b'\x00', b'\x01', b'\x02'])
         client.socket = mock_socket
         client.timeout = 3
-        self.assertEqual(b'\x00\x01\x02', client._recv(3)) # pylint: disable=protected-access
+        self.assertEqual(b'\x00\x01\x02', client._recv(3))  # pylint: disable=protected-access
         mock_socket.recv.side_effect = iter([b'\x00', b'\x01', b'\x02'])
-        self.assertEqual(b'\x00\x01', client._recv(2)) # pylint: disable=protected-access
+        self.assertEqual(b'\x00\x01', client._recv(2))  # pylint: disable=protected-access
         mock_select.select.return_value = [False]
-        self.assertEqual(b'', client._recv(2)) # pylint: disable=protected-access
+        self.assertEqual(b'', client._recv(2))  # pylint: disable=protected-access
         client.socket = mockSocket()
         mock_select.select.return_value = [True]
-        self.assertIn(b'\x00', client._recv(None)) # pylint: disable=protected-access
+        self.assertIn(b'\x00', client._recv(None))  # pylint: disable=protected-access
 
         mock_socket = MagicMock()
         mock_socket.recv.return_value = b''
         client.socket = mock_socket
-        self.assertRaises(ConnectionException, lambda: client._recv(1024)) # pylint: disable=protected-access
+        self.assertRaises(ConnectionException, lambda: client._recv(1024))  # pylint: disable=protected-access
 
         mock_socket.recv.side_effect = iter([b'\x00', b'\x01', b'\x02', b''])
         client.socket = mock_socket
-        self.assertEqual(b'\x00\x01\x02', client._recv(1024)) # pylint: disable=protected-access
+        self.assertEqual(b'\x00\x01\x02', client._recv(1024))  # pylint: disable=protected-access
 
     def test_tcp_client_repr(self):
-        """ Test tcp client. """
+        """Test tcp client."""
         client = ModbusTcpClient()
         rep = f"<{client.__class__.__name__} at {hex(id(client))} socket={client.socket}, "\
               f"ipaddr={client.host}, port={client.port}, timeout={client.timeout}>"
         self.assertEqual(repr(client), rep)
 
     def test_tcp_client_register(self):
-        """ Test tcp client. """
-        class CustomRequest: # pylint: disable=too-few-public-methods
-            """ Dummy custom request. """
+        """Test tcp client."""
+        class CustomRequest:  # pylint: disable=too-few-public-methods
+            """Dummy custom request."""
+
             function_code = 79
         client = ModbusTcpClient()
         client.framer = Mock()
@@ -329,7 +328,7 @@ class CustomRequest: # pylint: disable=too-few-public-methods
     # -----------------------------------------------------------------------#
 
     def test_tls_sslctx_provider(self):
-        """ test that sslctx_provider() produce SSLContext correctly """
+        """Test that sslctx_provider() produce SSLContext correctly"""
         with patch.object(ssl.SSLContext, 'load_cert_chain') as mock_method:
             sslctx1 = sslctx_provider(certfile="cert.pem")
             self.assertIsNotNone(sslctx1)
@@ -351,7 +350,7 @@ def test_tls_sslctx_provider(self):
             self.assertEqual(sslctx_new, sslctx_old)
 
     def test_sync_tls_client_instantiation(self):
-        """ Test sync tls client. """
+        """Test sync tls client."""
         # default SSLContext
         client = ModbusTlsClient()
         self.assertNotEqual(client, None)
@@ -359,14 +358,13 @@ def test_sync_tls_client_instantiation(self):
         self.assertTrue(client.sslctx)
 
     def test_basic_sync_tls_client(self):
-        """ Test the basic methods for the tls sync client"""
-
+        """Test the basic methods for the tls sync client"""
         # receive/send
         client = ModbusTlsClient()
         client.socket = mockSocket()
-        self.assertEqual(0, client._send(None)) # pylint: disable=protected-access
-        self.assertEqual(1, client._send(b'\x00')) # pylint: disable=protected-access
-        self.assertEqual(b'\x00', client._recv(1)) # pylint: disable=protected-access
+        self.assertEqual(0, client._send(None))  # pylint: disable=protected-access
+        self.assertEqual(1, client._send(b'\x00'))  # pylint: disable=protected-access
+        self.assertEqual(b'\x00', client._recv(1))  # pylint: disable=protected-access
 
         # connect/disconnect
         self.assertTrue(client.connect())
@@ -379,7 +377,7 @@ def test_basic_sync_tls_client(self):
         self.assertEqual("ModbusTlsClient(localhost:802)", str(client))
 
     def test_tls_client_connect(self):
-        """ Test the tls client connection method"""
+        """Test the tls client connection method"""
         with patch.object(ssl.SSLSocket, 'connect') as mock_method:
             client = ModbusTlsClient()
             self.assertTrue(client.connect())
@@ -390,39 +388,39 @@ def test_tls_client_connect(self):
             self.assertFalse(client.connect())
 
     def test_tls_client_send(self):
-        """ Test the tls client send method"""
+        """Test the tls client send method"""
         client = ModbusTlsClient()
-        self.assertRaises(ConnectionException, lambda: client._send(None)) # pylint: disable=protected-access
+        self.assertRaises(ConnectionException, lambda: client._send(None))  # pylint: disable=protected-access
 
         client.socket = mockSocket()
-        self.assertEqual(0, client._send(None)) # pylint: disable=protected-access
-        self.assertEqual(4, client._send('1234')) # pylint: disable=protected-access
+        self.assertEqual(0, client._send(None))  # pylint: disable=protected-access
+        self.assertEqual(4, client._send('1234'))  # pylint: disable=protected-access
 
     @patch('pymodbus.client.sync.time')
     def test_tls_client_recv(self, mock_time):
-        """ Test the tls client receive method"""
+        """Test the tls client receive method"""
         client = ModbusTlsClient()
-        self.assertRaises(ConnectionException, lambda: client._recv(1024)) # pylint: disable=protected-access
+        self.assertRaises(ConnectionException, lambda: client._recv(1024))  # pylint: disable=protected-access
 
         mock_time.time.side_effect = count()
 
         client.socket = mockSocket()
-        self.assertEqual(b'', client._recv(0)) # pylint: disable=protected-access
-        self.assertEqual(b'\x00' * 4, client._recv(4)) # pylint: disable=protected-access
+        self.assertEqual(b'', client._recv(0))  # pylint: disable=protected-access
+        self.assertEqual(b'\x00' * 4, client._recv(4))  # pylint: disable=protected-access
 
         client.timeout = 2
-        self.assertIn(b'\x00', client._recv(None)) # pylint: disable=protected-access
+        self.assertIn(b'\x00', client._recv(None))  # pylint: disable=protected-access
 
         mock_socket = MagicMock()
         mock_socket.recv.side_effect = iter([b'\x00', b'\x01', b'\x02'])
         client.socket = mock_socket
         client.timeout = 3
-        self.assertEqual(b'\x00\x01\x02', client._recv(3)) # pylint: disable=protected-access
+        self.assertEqual(b'\x00\x01\x02', client._recv(3))  # pylint: disable=protected-access
         mock_socket.recv.side_effect = iter([b'\x00', b'\x01', b'\x02'])
-        self.assertEqual(b'\x00\x01', client._recv(2)) # pylint: disable=protected-access
+        self.assertEqual(b'\x00\x01', client._recv(2))  # pylint: disable=protected-access
 
     def test_tls_client_repr(self):
-        """ Test tls client. """
+        """Test tls client."""
         client = ModbusTlsClient()
         rep = f"<{client.__class__.__name__} at {hex(id(client))} socket={client.socket}, "\
               f"ipaddr={client.host}, port={client.port}, sslctx={client.sslctx}, "\
@@ -430,9 +428,10 @@ def test_tls_client_repr(self):
         self.assertEqual(repr(client), rep)
 
     def test_tls_client_register(self):
-        """ Test tls client. """
-        class CustomeRequest: # pylint: disable=too-few-public-methods
-            """ Dummy custom request. """
+        """Test tls client."""
+        class CustomeRequest:  # pylint: disable=too-few-public-methods
+            """Dummy custom request."""
+
             function_code = 79
         client = ModbusTlsClient()
         client.framer = Mock()
@@ -444,7 +443,7 @@ class CustomeRequest: # pylint: disable=too-few-public-methods
     # -----------------------------------------------------------------------#
 
     def test_sync_serial_client_instantiation(self):
-        """ Test sync serial client. """
+        """Test sync serial client."""
         client = ModbusSerialClient()
         self.assertNotEqual(client, None)
         self.assertTrue(isinstance(ModbusSerialClient(method='ascii').framer,
@@ -459,7 +458,7 @@ def test_sync_serial_client_instantiation(self):
                           lambda: ModbusSerialClient(method='something'))
 
     def test_sync_serial_rtu_client_timeouts(self):
-        """ Test sync serial rtu. """
+        """Test sync serial rtu."""
         client = ModbusSerialClient(method="rtu", baudrate=9600)
         self.assertEqual(client.silent_interval, round((3.5 * 11 / 9600), 6))
         client = ModbusSerialClient(method="rtu", baudrate=38400)
@@ -467,20 +466,19 @@ def test_sync_serial_rtu_client_timeouts(self):
 
     @patch("serial.Serial")
     def test_basic_sync_serial_client(self, mock_serial):
-        """ Test the basic methods for the serial sync client"""
-
+        """Test the basic methods for the serial sync client."""
         # receive/send
         mock_serial.in_waiting = 0
-        mock_serial.write = lambda x: len(x) # pylint: disable=unnecessary-lambda
+        mock_serial.write = lambda x: len(x)  # pylint: disable=unnecessary-lambda
 
         mock_serial.read = lambda size: b'\x00' * size
         client = ModbusSerialClient()
         client.socket = mock_serial
         client.state = 0
-        self.assertEqual(0, client._send(None)) # pylint: disable=protected-access
+        self.assertEqual(0, client._send(None))  # pylint: disable=protected-access
         client.state = 0
-        self.assertEqual(1, client._send(b'\x00')) # pylint: disable=protected-access
-        self.assertEqual(b'\x00', client._recv(1)) # pylint: disable=protected-access
+        self.assertEqual(1, client._send(b'\x00'))  # pylint: disable=protected-access
+        self.assertEqual(b'\x00', client._recv(1))  # pylint: disable=protected-access
 
         # connect/disconnect
         self.assertTrue(client.connect())
@@ -499,7 +497,7 @@ def test_basic_sync_serial_client(self, mock_serial):
         self.assertEqual('ModbusSerialClient(ascii baud[19200])', str(client))
 
     def test_serial_client_connect(self):
-        """ Test the serial client connection method"""
+        """Test the serial client connection method"""
         with patch.object(serial, 'Serial') as mock_method:
             mock_method.return_value = MagicMock()
             client = ModbusSerialClient()
@@ -512,7 +510,7 @@ def test_serial_client_connect(self):
 
     @patch("serial.Serial")
     def test_serial_client_is_socket_open(self, mock_serial):
-        """ Test the serial client is_socket_open method"""
+        """Test the serial client is_socket_open method"""
         client = ModbusSerialClient()
         self.assertFalse(client.is_socket_open())
         client.socket = mock_serial
@@ -520,51 +518,51 @@ def test_serial_client_is_socket_open(self, mock_serial):
 
     @patch("serial.Serial")
     def test_serial_client_send(self, mock_serial):
-        """ Test the serial client send method"""
+        """Test the serial client send method"""
         mock_serial.in_waiting = None
-        mock_serial.write = lambda x: len(x) # pylint: disable=unnecessary-lambda
+        mock_serial.write = lambda x: len(x)  # pylint: disable=unnecessary-lambda
         client = ModbusSerialClient()
-        self.assertRaises(ConnectionException, lambda: client._send(None)) # pylint: disable=protected-access
+        self.assertRaises(ConnectionException, lambda: client._send(None))  # pylint: disable=protected-access
         # client.connect()
         client.socket = mock_serial
         client.state = 0
-        self.assertEqual(0, client._send(None)) # pylint: disable=protected-access
+        self.assertEqual(0, client._send(None))  # pylint: disable=protected-access
         client.state = 0
-        self.assertEqual(4, client._send('1234')) # pylint: disable=protected-access
+        self.assertEqual(4, client._send('1234'))  # pylint: disable=protected-access
 
     @patch("serial.Serial")
     def test_serial_client_cleanup_buffer_before_send(self, mock_serial):
-        """ Test the serial client send method"""
+        """Test the serial client send method"""
         mock_serial.in_waiting = 4
         mock_serial.read = lambda x: b'1' * x
-        mock_serial.write = lambda x: len(x) # pylint: disable=unnecessary-lambda
+        mock_serial.write = lambda x: len(x)  # pylint: disable=unnecessary-lambda
         client = ModbusSerialClient()
-        self.assertRaises(ConnectionException, lambda: client._send(None)) # pylint: disable=protected-access
+        self.assertRaises(ConnectionException, lambda: client._send(None))  # pylint: disable=protected-access
         # client.connect()
         client.socket = mock_serial
         client.state = 0
-        self.assertEqual(0, client._send(None)) # pylint: disable=protected-access
+        self.assertEqual(0, client._send(None))  # pylint: disable=protected-access
         client.state = 0
-        self.assertEqual(4, client._send('1234')) # pylint: disable=protected-access
+        self.assertEqual(4, client._send('1234'))  # pylint: disable=protected-access
 
     def test_serial_client_recv(self):
-        """ Test the serial client receive method"""
+        """Test the serial client receive method"""
         client = ModbusSerialClient()
-        self.assertRaises(ConnectionException, lambda: client._recv(1024)) # pylint: disable=protected-access
+        self.assertRaises(ConnectionException, lambda: client._recv(1024))  # pylint: disable=protected-access
 
         client.socket = mockSocket()
-        self.assertEqual(b'', client._recv(0)) # pylint: disable=protected-access
-        self.assertEqual(b'\x00' * 4, client._recv(4)) # pylint: disable=protected-access
+        self.assertEqual(b'', client._recv(0))  # pylint: disable=protected-access
+        self.assertEqual(b'\x00' * 4, client._recv(4))  # pylint: disable=protected-access
         client.socket = MagicMock()
         client.socket.read.return_value = b''
-        self.assertEqual(b'', client._recv(None)) # pylint: disable=protected-access
+        self.assertEqual(b'', client._recv(None))  # pylint: disable=protected-access
         client.socket.timeout = 0
-        self.assertEqual(b'', client._recv(0)) # pylint: disable=protected-access
+        self.assertEqual(b'', client._recv(0))  # pylint: disable=protected-access
         client.timeout = None
-        self.assertEqual(b'', client._recv(None)) # pylint: disable=protected-access
+        self.assertEqual(b'', client._recv(None))  # pylint: disable=protected-access
 
     def test_serial_client_repr(self):
-        """ Test serial client. """
+        """Test serial client."""
         client = ModbusSerialClient()
         rep = f"<{client.__class__.__name__} at {hex(id(client))} socket={client.socket}, "\
               f"method={client.method}, timeout={client.timeout}>"
diff --git a/test/test_client_sync_diag.py b/test/test_client_sync_diag.py
index c24cc52e9..ba61aba1e 100755
--- a/test/test_client_sync_diag.py
+++ b/test/test_client_sync_diag.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test client sync diag. """
+"""Test client sync diag."""
 import unittest
 from itertools import count
 from unittest.mock import patch, MagicMock
@@ -14,7 +14,8 @@
 # Fixture
 # ---------------------------------------------------------------------------#
 class SynchronousDiagnosticClientTest(unittest.TestCase):
-    """ Unittest for the pymodbus.client.sync_diag module.
+    """Unittest for the pymodbus.client.sync_diag module.
+
     It is a copy of parts of the test for the TCP class in the pymodbus.client.sync
     module, as it should operate identically and only log some additional
     lines.
@@ -25,13 +26,12 @@ class SynchronousDiagnosticClientTest(unittest.TestCase):
     # -----------------------------------------------------------------------#
 
     def test_sync_tcp_diag_client_instantiation(self):
-        """ Test sync tcp diag client. """
+        """Test sync tcp diag client."""
         client = get_client()
         self.assertNotEqual(client, None)
 
     def test_basic_sync_tcp_diag_client(self):
-        """ Test the basic methods for the tcp sync diag client"""
-
+        """Test the basic methods for the tcp sync diag client"""
         # connect/disconnect
         client = ModbusTcpDiagClient()
         client.socket = mockSocket()
@@ -39,7 +39,7 @@ def test_basic_sync_tcp_diag_client(self):
         client.close()
 
     def test_tcp_diag_client_connect(self):
-        """ Test the tcp sync diag client connection method"""
+        """Test the tcp sync diag client connection method"""
         with patch.object(socket, 'create_connection') as mock_method:
             mock_method.return_value = object()
             client = ModbusTcpDiagClient()
@@ -54,49 +54,48 @@ def test_tcp_diag_client_connect(self):
     @patch('pymodbus.client.sync_diag.time')
     @patch('pymodbus.client.sync.select')
     def test_tcp_diag_client_recv(self, mock_select, mock_diag_time, mock_time):
-        """ Test the tcp sync diag client receive method"""
-
+        """Test the tcp sync diag client receive method"""
         mock_select.select.return_value = [True]
         mock_time.time.side_effect = count()
         mock_diag_time.time.side_effect = count()
         client = ModbusTcpDiagClient()
-        self.assertRaises(ConnectionException, lambda: client._recv(1024)) # pylint: disable=protected-access
+        self.assertRaises(ConnectionException, lambda: client._recv(1024))  # pylint: disable=protected-access
 
         client.socket = mockSocket()
         # Test logging of non-delayed responses
-        self.assertIn(b'\x00', client._recv(None)) # pylint: disable=protected-access
-        self.assertEqual(b'\x00', client._recv(1)) # pylint: disable=protected-access
+        self.assertIn(b'\x00', client._recv(None))  # pylint: disable=protected-access
+        self.assertEqual(b'\x00', client._recv(1))  # pylint: disable=protected-access
 
         # Fool diagnostic logger into thinking we're running late,
         # test logging of delayed responses
         mock_diag_time.time.side_effect = count(step=3)
-        self.assertEqual(b'\x00' * 4, client._recv(4)) # pylint: disable=protected-access
-        self.assertEqual(b'', client._recv(0)) # pylint: disable=protected-access
+        self.assertEqual(b'\x00' * 4, client._recv(4))  # pylint: disable=protected-access
+        self.assertEqual(b'', client._recv(0))  # pylint: disable=protected-access
 
         mock_socket = MagicMock()
         mock_socket.recv.side_effect = iter([b'\x00', b'\x01', b'\x02'])
         client.timeout = 3
         client.socket = mock_socket
-        self.assertEqual(b'\x00\x01\x02', client._recv(3)) # pylint: disable=protected-access
+        self.assertEqual(b'\x00\x01\x02', client._recv(3))  # pylint: disable=protected-access
         mock_socket.recv.side_effect = iter([b'\x00', b'\x01', b'\x02'])
-        self.assertEqual(b'\x00\x01', client._recv(2)) # pylint: disable=protected-access
+        self.assertEqual(b'\x00\x01', client._recv(2))  # pylint: disable=protected-access
         mock_select.select.return_value = [False]
-        self.assertEqual(b'', client._recv(2)) # pylint: disable=protected-access
+        self.assertEqual(b'', client._recv(2))  # pylint: disable=protected-access
         client.socket = mockSocket()
         mock_select.select.return_value = [True]
-        self.assertIn(b'\x00', client._recv(None)) # pylint: disable=protected-access
+        self.assertIn(b'\x00', client._recv(None))  # pylint: disable=protected-access
 
         mock_socket = MagicMock()
         client.socket = mock_socket
         mock_socket.recv.return_value = b''
-        self.assertRaises(ConnectionException, lambda: client._recv(1024)) # pylint: disable=protected-access
+        self.assertRaises(ConnectionException, lambda: client._recv(1024))  # pylint: disable=protected-access
 
         mock_socket.recv.side_effect = iter([b'\x00', b'\x01', b'\x02', b''])
         client.socket = mock_socket
-        self.assertEqual(b'\x00\x01\x02', client._recv(1024)) # pylint: disable=protected-access
+        self.assertEqual(b'\x00\x01\x02', client._recv(1024))  # pylint: disable=protected-access
 
     def test_tcp_diag_client_repr(self):
-        """ Test tcp diag client. """
+        """Test tcp diag client."""
         client = ModbusTcpDiagClient()
         rep = f"<{client.__class__.__name__} at {hex(id(client))} "\
               f"socket={client.socket}, ipaddr={client.host}, "\
diff --git a/test/test_datastore.py b/test/test_datastore.py
index 307655015..a0e8a63d6 100644
--- a/test/test_datastore.py
+++ b/test/test_datastore.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test datastore. """
+"""Test datastore."""
 import unittest
 import random
 from mock import MagicMock
@@ -19,48 +19,48 @@
 
 
 class ModbusDataStoreTest(unittest.TestCase):
-    """ Unittest for the pymodbus.datastore module. """
+    """Unittest for the pymodbus.datastore module."""
 
     def setUp(self):
-        pass
+        """Do setup."""
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
 
     def test_modbus_data_block(self):
-        """ Test a base data block store """
+        """Test a base data block store"""
         block = BaseModbusDataBlock()
         block.default(10, True)
 
         self.assertNotEqual(str(block), None)
         self.assertEqual(block.default_value, True)
-        self.assertEqual(block.values, [True]*10)
+        self.assertEqual(block.values, [True] * 10)
 
         block.default_value = False
         block.reset()
-        self.assertEqual(block.values, [False]*10)
+        self.assertEqual(block.values, [False] * 10)
 
     def test_modbus_data_block_iterate(self):
-        """ Test a base data block store """
+        """Test a base data block store"""
         block = BaseModbusDataBlock()
         block.default(10, False)
-        for _,value in block:
+        for _, value in block:
             self.assertEqual(value, False)
 
-        block.values = {0 : False, 2 : False, 3 : False }
-        for _,value in block:
+        block.values = {0: False, 2: False, 3: False}
+        for _, value in block:
             self.assertEqual(value, False)
 
     def test_modbus_data_block_other(self):
-        """ Test a base data block store """
+        """Test a base data block store"""
         block = BaseModbusDataBlock()
-        self.assertRaises(NotImplementedException, lambda: block.validate(1,1))
-        self.assertRaises(NotImplementedException, lambda: block.getValues(1,1))
-        self.assertRaises(NotImplementedException, lambda: block.setValues(1,1))
+        self.assertRaises(NotImplementedException, lambda: block.validate(1, 1))
+        self.assertRaises(NotImplementedException, lambda: block.getValues(1, 1))
+        self.assertRaises(NotImplementedException, lambda: block.setValues(1, 1))
 
     def test_modbus_sequential_data_block(self):
-        """ Test a sequential data block store """
-        block = ModbusSequentialDataBlock(0x00, [False]*10)
+        """Test a sequential data block store"""
+        block = ModbusSequentialDataBlock(0x00, [False] * 10)
         self.assertFalse(block.validate(-1, 0))
         self.assertFalse(block.validate(0, 20))
         self.assertFalse(block.validate(10, 1))
@@ -69,19 +69,19 @@ def test_modbus_sequential_data_block(self):
         block.setValues(0x00, True)
         self.assertEqual(block.getValues(0x00, 1), [True])
 
-        block.setValues(0x00, [True]*10)
-        self.assertEqual(block.getValues(0x00, 10), [True]*10)
+        block.setValues(0x00, [True] * 10)
+        self.assertEqual(block.getValues(0x00, 10), [True] * 10)
 
     def test_modbus_sequential_data_block_factory(self):
-        """ Test the sequential data block store factory """
+        """Test the sequential data block store factory"""
         block = ModbusSequentialDataBlock.create()
-        self.assertEqual(block.getValues(0x00, 65536), [False]*65536)
+        self.assertEqual(block.getValues(0x00, 65536), [False] * 65536)
         block = ModbusSequentialDataBlock(0x00, 0x01)
         self.assertEqual(block.values, [0x01])
 
     def test_modbus_sparse_data_block(self):
-        """ Test a sparse data block store """
-        values = dict(enumerate([True]*10))
+        """Test a sparse data block store"""
+        values = dict(enumerate([True] * 10))
         block = ModbusSparseDataBlock(values)
         self.assertFalse(block.validate(-1, 0))
         self.assertFalse(block.validate(0, 20))
@@ -94,22 +94,22 @@ def test_modbus_sparse_data_block(self):
         block.setValues(0x00, True)
         self.assertEqual(block.getValues(0x00, 1), [True])
 
-        block.setValues(0x00, [True]*10)
-        self.assertEqual(block.getValues(0x00, 10), [True]*10)
+        block.setValues(0x00, [True] * 10)
+        self.assertEqual(block.getValues(0x00, 10), [True] * 10)
 
-        block.setValues(0x00, dict(enumerate([False]*10)))
-        self.assertEqual(block.getValues(0x00, 10), [False]*10)
+        block.setValues(0x00, dict(enumerate([False] * 10)))
+        self.assertEqual(block.getValues(0x00, 10), [False] * 10)
 
         block = ModbusSparseDataBlock({3: [10, 11, 12], 10: 1, 15: [0] * 4})
         self.assertEqual(block.values, {3: 10, 4: 11, 5: 12, 10: 1,
-                                        15:0 , 16:0, 17:0, 18:0 })
+                                        15: 0, 16: 0, 17: 0, 18: 0})
         self.assertEqual(block.default_value, {3: 10, 4: 11, 5: 12, 10: 1,
-                                        15:0 , 16:0, 17:0, 18:0 })
+                                               15: 0, 16: 0, 17: 0, 18: 0})
         self.assertEqual(block.mutable, True)
         block.setValues(3, [20, 21, 22, 23], use_as_default=True)
         self.assertEqual(block.getValues(3, 4), [20, 21, 22, 23])
-        self.assertEqual(block.default_value, {3: 20, 4: 21, 5: 22, 6:23, 10: 1,
-                                        15:0 , 16:0, 17:0, 18:0 })
+        self.assertEqual(block.default_value, {3: 20, 4: 21, 5: 22, 6: 23, 10: 1,
+                                               15: 0, 16: 0, 17: 0, 18: 0})
         # check when values is a dict, address is ignored
         block.setValues(0, {5: 32, 7: 43})
         self.assertEqual(block.getValues(5, 3), [32, 23, 43])
@@ -129,48 +129,46 @@ def test_modbus_sparse_data_block(self):
         block = ModbusSparseDataBlock({3: [10, 11, 12], 10: 1, 15: [0] * 4})
         block.setValues(0, {3: [20, 21, 22], 10: 11, 15: [10] * 4})
         self.assertEqual(block.values, {3: 20, 4: 21, 5: 22, 10: 11,
-                                        15: 10 ,16:10, 17:10, 18:10 })
+                                        15: 10, 16: 10, 17: 10, 18: 10})
         block.reset()
         self.assertEqual(block.values, {3: 10, 4: 11, 5: 12, 10: 1,
                                         15: 0, 16: 0, 17: 0, 18: 0})
 
-
     def test_modbus_sparse_data_block_factory(self):
-        """ Test the sparse data block store factory """
-        block = ModbusSparseDataBlock.create([0x00]*65536)
-        self.assertEqual(block.getValues(0x00, 65536), [False]*65536)
+        """Test the sparse data block store factory"""
+        block = ModbusSparseDataBlock.create([0x00] * 65536)
+        self.assertEqual(block.getValues(0x00, 65536), [False] * 65536)
 
     def test_modbus_sparse_data_block_other(self):
-        """ Test modbus sparce data block. """
-        block = ModbusSparseDataBlock([True]*10)
-        self.assertEqual(block.getValues(0x00, 10), [True]*10)
+        """Test modbus sparce data block."""
+        block = ModbusSparseDataBlock([True] * 10)
+        self.assertEqual(block.getValues(0x00, 10), [True] * 10)
         self.assertRaises(ParameterException,
-            lambda: ModbusSparseDataBlock(True))
-
+                          lambda: ModbusSparseDataBlock(True))
 
     def test_modbus_slave_context(self):
-        """ Test a modbus slave context """
+        """Test a modbus slave context"""
         store = {
-            'di' : ModbusSequentialDataBlock(0, [False]*10),
-            'co' : ModbusSequentialDataBlock(0, [False]*10),
-            'ir' : ModbusSequentialDataBlock(0, [False]*10),
-            'hr' : ModbusSequentialDataBlock(0, [False]*10),
+            'di': ModbusSequentialDataBlock(0, [False] * 10),
+            'co': ModbusSequentialDataBlock(0, [False] * 10),
+            'ir': ModbusSequentialDataBlock(0, [False] * 10),
+            'hr': ModbusSequentialDataBlock(0, [False] * 10),
         }
         context = ModbusSlaveContext(**store)
         self.assertNotEqual(str(context), None)
 
-        for i in (1,2,3,4):
-            context.setValues(i, 0, [True]*10)
-            self.assertTrue(context.validate(i, 0,10))
-            self.assertEqual(context.getValues(i, 0,10), [True]*10)
+        for i in (1, 2, 3, 4):
+            context.setValues(i, 0, [True] * 10)
+            self.assertTrue(context.validate(i, 0, 10))
+            self.assertEqual(context.getValues(i, 0, 10), [True] * 10)
         context.reset()
 
-        for i in (1,2,3,4):
-            self.assertTrue(context.validate(i, 0,10))
-            self.assertEqual(context.getValues(i, 0,10), [False]*10)
+        for i in (1, 2, 3, 4):
+            self.assertTrue(context.validate(i, 0, 10))
+            self.assertEqual(context.getValues(i, 0, 10), [False] * 10)
 
     def test_modbus_server_context(self):
-        """ Test a modbus server context """
+        """Test a modbus server context"""
         def _set(ctx):
             ctx[0xffff] = None
         context = ModbusServerContext(single=False)
@@ -179,29 +177,30 @@ def _set(ctx):
 
 
 class RedisDataStoreTest(unittest.TestCase):
-    """ Unittest for the pymodbus.datastore.database.redis module. """
+    """Unittest for the pymodbus.datastore.database.redis module."""
 
     def setUp(self):
+        """Do setup."""
         self.slave = RedisSlaveContext()
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
 
     def test_str(self):
-        """ Test string. """
+        """Test string."""
         # slave = RedisSlaveContext()
         self.assertEqual(str(self.slave), f"Redis Slave Context {self.slave.client}")
 
     def test_reset(self):
-        """ Test reset. """
+        """Test reset."""
         self.assertTrue(isinstance(self.slave.client, redis.Redis))
         self.slave.client = MagicMock()
         self.slave.reset()
         self.slave.client.flushall.assert_called_once_with()
 
     def test_val_callbacks_success(self):
-        """ Test value callbacks success. """
-        self.slave._build_mapping() # pylint: disable=protected-access
+        """Test value callbacks success."""
+        self.slave._build_mapping()  # pylint: disable=protected-access
         mock_count = 3
         mock_offset = 0
         self.slave.client.mset = MagicMock()
@@ -209,12 +208,12 @@ def test_val_callbacks_success(self):
 
         for key in ('d', 'c', 'h', 'i'):
             self.assertTrue(
-                self.slave._val_callbacks[key](mock_offset, mock_count) # pylint: disable=protected-access
+                self.slave._val_callbacks[key](mock_offset, mock_count)  # pylint: disable=protected-access
             )
 
     def test_val_callbacks_failure(self):
-        """ Test value callbacks failure. """
-        self.slave._build_mapping() # pylint: disable=protected-access
+        """Test value callbacks failure."""
+        self.slave._build_mapping()  # pylint: disable=protected-access
         mock_count = 3
         mock_offset = 0
         self.slave.client.mset = MagicMock()
@@ -222,82 +221,85 @@ def test_val_callbacks_failure(self):
 
         for key in ('d', 'c', 'h', 'i'):
             self.assertFalse(
-                self.slave._val_callbacks[key](mock_offset, mock_count) # pylint: disable=protected-access
+                self.slave._val_callbacks[key](mock_offset, mock_count)  # pylint: disable=protected-access
             )
 
     def test_get_callbacks(self):
-        """ Test get callbacks. """
-        self.slave._build_mapping() # pylint: disable=protected-access
+        """Test get callbacks."""
+        self.slave._build_mapping()  # pylint: disable=protected-access
         mock_count = 3
         mock_offset = 0
         self.slave.client.mget = MagicMock(return_value='11')
 
         for key in ('d', 'c'):
-            resp = self.slave._get_callbacks[key](mock_offset, mock_count) # pylint: disable=protected-access
+            resp = self.slave._get_callbacks[key](mock_offset, mock_count)  # pylint: disable=protected-access
             self.assertEqual(resp, [True, False, False])
 
         for key in ('h', 'i'):
-            resp = self.slave._get_callbacks[key](mock_offset, mock_count) # pylint: disable=protected-access
+            resp = self.slave._get_callbacks[key](mock_offset, mock_count)  # pylint: disable=protected-access
             self.assertEqual(resp, ['1', '1'])
 
     def test_set_callbacks(self):
-        """ Test set callbacks. """
-        self.slave._build_mapping() # pylint: disable=protected-access
+        """Test set callbacks."""
+        self.slave._build_mapping()  # pylint: disable=protected-access
         mock_values = [3]
         mock_offset = 0
         self.slave.client.mset = MagicMock()
         self.slave.client.mget = MagicMock()
 
         for key in ('c', 'd'):
-            self.slave._set_callbacks[key](mock_offset, [3]) # pylint: disable=protected-access
+            self.slave._set_callbacks[key](mock_offset, [3])  # pylint: disable=protected-access
             k = f"pymodbus:{key}:{mock_offset}"
             self.slave.client.mset.assert_called_with(
                 {k: '\x01'}
             )
 
         for key in ('h', 'i'):
-            self.slave._set_callbacks[key](mock_offset, [3]) # pylint: disable=protected-access
+            self.slave._set_callbacks[key](mock_offset, [3])  # pylint: disable=protected-access
             k = f"pymodbus:{key}:{mock_offset}"
             self.slave.client.mset.assert_called_with(
                 {k: mock_values[0]}
             )
 
     def test_validate(self):
-        """ Test validate. """
+        """Test validate."""
         self.slave.client.mget = MagicMock(return_value=[123])
         self.assertTrue(self.slave.validate(0x01, 3000))
 
     def test_set_value(self):
-        """ Test set value. """
+        """Test set value."""
         self.slave.client.mset = MagicMock()
         self.slave.client.mget = MagicMock()
         self.assertEqual(self.slave.setValues(0x01, 1000, [12]), None)
 
     def test_get_value(self):
-        """ Test get value. """
+        """Test get value."""
         self.slave.client.mget = MagicMock(return_value=["123"])
         self.assertEqual(self.slave.getValues(0x01, 23), [])
 
 
-class MockSqlResult: # pylint: disable=too-few-public-methods
-    """ Mock SQL Result. """
+class MockSqlResult:  # pylint: disable=too-few-public-methods
+    """Mock SQL Result."""
+
     def __init__(self, rowcount=0, value=0):
+        """Initialize."""
         self.rowcount = rowcount
         self.value = value
 
 
 class SqlDataStoreTest(unittest.TestCase):
-    """ Unittest for the pymodbus.datastore.database.SqlSlaveContext module. """
+    """Unittest for the pymodbus.datastore.database.SqlSlaveContext module."""
 
     def setUp(self):
+        """Do setup."""
         self.slave = SqlSlaveContext()
-        self.slave._metadata.drop_all = MagicMock() # pylint: disable=protected-access
-        self.slave._db_create = MagicMock() # pylint: disable=protected-access
-        self.slave._table.select = MagicMock() # pylint: disable=protected-access
-        self.slave._connection = MagicMock() # pylint: disable=protected-access
+        self.slave._metadata.drop_all = MagicMock()  # pylint: disable=protected-access
+        self.slave._db_create = MagicMock()  # pylint: disable=protected-access
+        self.slave._table.select = MagicMock()  # pylint: disable=protected-access
+        self.slave._connection = MagicMock()  # pylint: disable=protected-access
 
-        self.mock_addr = random.randint(0, 65000) #NOSONAR # nosec
-        self.mock_values = random.sample(range(1, 100), 5) #NOSONAR # nosec
+        self.mock_addr = random.randint(0, 65000)  # NOSONAR # nosec
+        self.mock_values = random.sample(range(1, 100), 5)  # NOSONAR # nosec
         self.mock_function = 0x01
         self.mock_type = 'h'
         self.mock_offset = 0
@@ -308,38 +310,40 @@ def setUp(self):
         self.function_map.update([(i, 'c') for i in (1, 5, 15)])
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
 
     def test_str(self):
-        """ Test string. """
+        """Test string."""
         self.assertEqual(str(self.slave), "Modbus Slave Context")
 
     def test_reset(self):
-        """ Test reset. """
+        """Test reset."""
         self.slave.reset()
 
-        self.slave._metadata.drop_all.assert_called_once_with() # pylint: disable=protected-access
-        self.slave._db_create.assert_called_once_with( # pylint: disable=protected-access
+        self.slave._metadata.drop_all.assert_called_once_with()  # pylint: disable=protected-access
+        self.slave._db_create.assert_called_once_with(  # pylint: disable=protected-access
             self.slave.table, self.slave.database
         )
 
     def test_validate_success(self):
-        """ Test validate success. """
-        self.slave._connection.execute.return_value.fetchall.return_value = self.mock_values # pylint: disable=protected-access
+        """Test validate success."""
+        self.slave._connection.execute.return_value.fetchall.return_value = \
+            self.mock_values  # pylint: disable=protected-access
         self.assertTrue(self.slave.validate(
             self.mock_function, self.mock_addr, len(self.mock_values))
         )
 
     def test_validate_failure(self):
-        """ Test validate failure. """
+        """Test validate failure."""
         wrong_count = 9
-        self.slave._connection.execute.return_value.fetchall.return_value = self.mock_values # pylint: disable=protected-access
+        self.slave._connection.execute.return_value.fetchall.return_value = \
+            self.mock_values  # pylint: disable=protected-access
         self.assertFalse(self.slave.validate(
             self.mock_function, self.mock_addr, wrong_count)
         )
 
     def test_build_set(self):
-        """ Test build set. """
+        """Test build set."""
         mock_set = [
             {
                 'index': 0,
@@ -352,72 +356,72 @@ def test_build_set(self):
                 'value': 12
             }
         ]
-        self.assertListEqual(self.slave._build_set('h', 0, [11, 12]), mock_set) # pylint: disable=protected-access
+        self.assertListEqual(self.slave._build_set('h', 0, [11, 12]), mock_set)  # pylint: disable=protected-access
 
     def test_check_success(self):
-        """ Test check success. """
+        """Test check success."""
         mock_success_results = [1, 2, 3]
-        self.slave._get = MagicMock(return_value=mock_success_results) # pylint: disable=protected-access
-        self.assertFalse(self.slave._check('h', 0, 1)) # pylint: disable=protected-access
+        self.slave._get = MagicMock(return_value=mock_success_results)  # pylint: disable=protected-access
+        self.assertFalse(self.slave._check('h', 0, 1))  # pylint: disable=protected-access
 
     def test_check_failure(self):
-        """ Test check failure. """
+        """Test check failure."""
         mock_success_results = []
-        self.slave._get = MagicMock(return_value=mock_success_results) # pylint: disable=protected-access
-        self.assertTrue(self.slave._check('h', 0, 1)) # pylint: disable=protected-access
+        self.slave._get = MagicMock(return_value=mock_success_results)  # pylint: disable=protected-access
+        self.assertTrue(self.slave._check('h', 0, 1))  # pylint: disable=protected-access
 
     def test_get_values(self):
-        """ Test get values. """
-        self.slave._get = MagicMock() # pylint: disable=protected-access
+        """Test get values."""
+        self.slave._get = MagicMock()  # pylint: disable=protected-access
 
         for key, value in self.function_map.items():
             self.slave.getValues(key, self.mock_addr, self.mock_count)
-            self.slave._get.assert_called_with( # pylint: disable=protected-access
+            self.slave._get.assert_called_with(  # pylint: disable=protected-access
                 value, self.mock_addr + 1, self.mock_count
             )
 
     def test_set_values(self):
-        """ Test set values. """
-        self.slave._set = MagicMock() # pylint: disable=protected-access
+        """Test set values."""
+        self.slave._set = MagicMock()  # pylint: disable=protected-access
 
         for key, value in self.function_map.items():
             self.slave.setValues(key, self.mock_addr,
                                  self.mock_values, update=False)
-            self.slave._set.assert_called_with( # pylint: disable=protected-access
+            self.slave._set.assert_called_with(  # pylint: disable=protected-access
                 value, self.mock_addr + 1, self.mock_values
             )
 
     def test_set(self):
-        """ Test set. """
-        self.slave._check = MagicMock(return_value=True) # pylint: disable=protected-access
-        self.slave._connection.execute = MagicMock( # pylint: disable=protected-access
+        """Test set."""
+        self.slave._check = MagicMock(return_value=True)  # pylint: disable=protected-access
+        self.slave._connection.execute = MagicMock(  # pylint: disable=protected-access
             return_value=MockSqlResult(rowcount=len(self.mock_values))
         )
-        self.assertTrue(self.slave._set( # pylint: disable=protected-access
+        self.assertTrue(self.slave._set(  # pylint: disable=protected-access
             self.mock_type, self.mock_offset, self.mock_values)
         )
 
-        self.slave._check = MagicMock(return_value=False) # pylint: disable=protected-access
+        self.slave._check = MagicMock(return_value=False)  # pylint: disable=protected-access
         self.assertFalse(
-            self.slave._set(self.mock_type, self.mock_offset, self.mock_values) # pylint: disable=protected-access
+            self.slave._set(self.mock_type, self.mock_offset, self.mock_values)  # pylint: disable=protected-access
         )
 
     def test_update_success(self):
-        """ Test update success. """
-        self.slave._connection.execute = MagicMock( # pylint: disable=protected-access
+        """Test update success."""
+        self.slave._connection.execute = MagicMock(  # pylint: disable=protected-access
             return_value=MockSqlResult(rowcount=len(self.mock_values))
         )
         self.assertTrue(
-            self.slave._update(self.mock_type, self.mock_offset, self.mock_values) # pylint: disable=protected-access
+            self.slave._update(self.mock_type, self.mock_offset, self.mock_values)  # pylint: disable=protected-access
         )
 
     def test_update_failure(self):
-        """ Test update failure. """
-        self.slave._connection.execute = MagicMock( # pylint: disable=protected-access
+        """Test update failure."""
+        self.slave._connection.execute = MagicMock(  # pylint: disable=protected-access
             return_value=MockSqlResult(rowcount=100)
         )
         self.assertFalse(
-            self.slave._update(self.mock_type, self.mock_offset, self.mock_values) # pylint: disable=protected-access
+            self.slave._update(self.mock_type, self.mock_offset, self.mock_values)  # pylint: disable=protected-access
         )
 
 
diff --git a/test/test_device.py b/test/test_device.py
index 1b43c8188..86055ac0e 100644
--- a/test/test_device.py
+++ b/test/test_device.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test device. """
+"""Test device."""
 import unittest
 from pymodbus.device import (
     ModbusPlusStatistics,
@@ -11,22 +11,25 @@
 from pymodbus.events import ModbusEvent, RemoteReceiveEvent
 from pymodbus.constants import DeviceInformation
 
-#---------------------------------------------------------------------------#
-# Fixture
-#---------------------------------------------------------------------------#
-class SimpleDataStoreTest(unittest.TestCase): # pylint: disable=too-many-public-methods
-    """ Unittest for the pymodbus.device module. """
+# ---------------------------------------------------------------------------#
+#  Fixture
+# ---------------------------------------------------------------------------#
 
-    #-----------------------------------------------------------------------#
-    # Setup/TearDown
-    #-----------------------------------------------------------------------#
+
+class SimpleDataStoreTest(unittest.TestCase):  # pylint: disable=too-many-public-methods
+    """Unittest for the pymodbus.device module."""
+
+    # -----------------------------------------------------------------------#
+    #  Setup/TearDown
+    # -----------------------------------------------------------------------#
 
     def setUp(self):
+        """Do setup."""
         self.info = {
             0x00: 'Bashwork',               # VendorName
             0x01: 'PTM',                    # ProductCode
             0x02: '1.0',                    # MajorMinorRevision
-            0x03: 'http://internets.com',   #NOSONAR VendorUrl
+            0x03: 'http://internets.com',  # NOSONAR VendorUrl
             0x04: 'pymodbus',               # ProductName
             0x05: 'bashwork',               # ModelName
             0x06: 'unittest',               # UserApplicationName
@@ -37,30 +40,30 @@ def setUp(self):
             0x82: 'custom2',                # device specific
             0xFF: 'customlast',             # device specific last
         }
-        self.ident   = ModbusDeviceIdentification(self.info)
+        self.ident = ModbusDeviceIdentification(self.info)
         self.control = ModbusControlBlock()
-        self.access  = ModbusAccessControl()
+        self.access = ModbusAccessControl()
         self.control.reset()
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
         del self.ident
         del self.control
         del self.access
 
     def test_update_identity(self):
-        """ Test device identification reading """
+        """Test device identification reading"""
         self.control.Identity.update(self.ident)
         self.assertEqual(self.control.Identity.VendorName, 'Bashwork')
         self.assertEqual(self.control.Identity.ProductCode, 'PTM')
         self.assertEqual(self.control.Identity.MajorMinorRevision, '1.0')
-        self.assertEqual(self.control.Identity.VendorUrl, 'http://internets.com') #NOSONAR
+        self.assertEqual(self.control.Identity.VendorUrl, 'http://internets.com')  # NOSONAR
         self.assertEqual(self.control.Identity.ProductName, 'pymodbus')
         self.assertEqual(self.control.Identity.ModelName, 'bashwork')
         self.assertEqual(self.control.Identity.UserApplicationName, 'unittest')
 
     def test_device_identification_factory(self):
-        """ Test device identification reading """
+        """Test device identification reading"""
         self.control.Identity.update(self.ident)
         result = DeviceInformationFactory.get(self.control, DeviceInformation.Specific, 0x00)
         self.assertEqual(result[0x00], 'Bashwork')
@@ -74,13 +77,13 @@ def test_device_identification_factory(self):
         self.assertEqual(result[0x00], 'Bashwork')
         self.assertEqual(result[0x01], 'PTM')
         self.assertEqual(result[0x02], '1.0')
-        self.assertEqual(result[0x03], 'http://internets.com') #NOSONAR
+        self.assertEqual(result[0x03], 'http://internets.com')  # NOSONAR
         self.assertEqual(result[0x04], 'pymodbus')
         self.assertEqual(result[0x05], 'bashwork')
         self.assertEqual(result[0x06], 'unittest')
 
     def test_device_identification_factory_lookup(self):
-        """ Test device identification factory lookup. """
+        """Test device identification factory lookup."""
         result = DeviceInformationFactory.get(self.control, DeviceInformation.Basic, 0x00)
         self.assertEqual(sorted(result.keys()), [0x00, 0x01, 0x02])
         result = DeviceInformationFactory.get(self.control, DeviceInformation.Basic, 0x02)
@@ -93,7 +96,7 @@ def test_device_identification_factory_lookup(self):
         self.assertEqual(sorted(result.keys()), [0x05, 0x06])
         result = DeviceInformationFactory.get(self.control, DeviceInformation.Extended, 0x00)
         self.assertEqual(sorted(result.keys()),
-            [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x80, 0x82, 0xFF])
+                         [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x80, 0x82, 0xFF])
         result = DeviceInformationFactory.get(self.control, DeviceInformation.Extended, 0x02)
         self.assertEqual(sorted(result.keys()), [0x02, 0x03, 0x04, 0x05, 0x06, 0x80, 0x82, 0xFF])
         result = DeviceInformationFactory.get(self.control, DeviceInformation.Extended, 0x06)
@@ -104,19 +107,19 @@ def test_device_identification_factory_lookup(self):
         self.assertEqual(sorted(result.keys()), [0x82, 0xFF])
         result = DeviceInformationFactory.get(self.control, DeviceInformation.Extended, 0x81)
         self.assertEqual(sorted(result.keys()),
-            [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x80, 0x82, 0xFF])
+                         [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x80, 0x82, 0xFF])
 
     def test_basic_commands(self):
-        """ Test device identification reading """
-        self.assertEqual(str(self.ident),   "DeviceIdentity")
+        """Test device identification reading"""
+        self.assertEqual(str(self.ident), "DeviceIdentity")
         self.assertEqual(str(self.control), "ModbusControl")
 
     def test_modbus_device_identification_get(self):
-        """ Test device identification reading """
+        """Test device identification reading"""
         self.assertEqual(self.ident[0x00], 'Bashwork')
         self.assertEqual(self.ident[0x01], 'PTM')
         self.assertEqual(self.ident[0x02], '1.0')
-        self.assertEqual(self.ident[0x03], 'http://internets.com') #NOSONAR
+        self.assertEqual(self.ident[0x03], 'http://internets.com')  # NOSONAR
         self.assertEqual(self.ident[0x04], 'pymodbus')
         self.assertEqual(self.ident[0x05], 'bashwork')
         self.assertEqual(self.ident[0x06], 'unittest')
@@ -126,13 +129,13 @@ def test_modbus_device_identification_get(self):
         self.assertEqual(self.ident[0x54], '')
 
     def test_modbus_device_identification_summary(self):
-        """ Test device identification summary creation """
-        summary  = sorted(self.ident.summary().values())
-        expected = sorted(list(self.info.values())[:0x07]) # remove private
+        """Test device identification summary creation"""
+        summary = sorted(self.ident.summary().values())
+        expected = sorted(list(self.info.values())[:0x07])  # remove private
         self.assertEqual(summary, expected)
 
     def test_modbus_device_identification_set(self):
-        """ Test a device identification writing """
+        """Test a device identification writing"""
         self.ident[0x07] = 'y'
         self.ident[0x08] = 'y'
         self.ident[0x10] = 'public'
@@ -144,7 +147,7 @@ def test_modbus_device_identification_set(self):
         self.assertEqual('testing', self.ident[0x54])
 
     def test_modbus_control_block_ascii_modes(self):
-        """ Test a server control block ascii mode """
+        """Test a server control block ascii mode"""
         self.assertEqual(id(self.control), id(ModbusControlBlock()))
         self.control.Mode = 'RTU'
         self.assertEqual('RTU', self.control.Mode)
@@ -152,21 +155,21 @@ def test_modbus_control_block_ascii_modes(self):
         self.assertNotEqual('FAKE', self.control.Mode)
 
     def test_modbus_control_block_counters(self):
-        """ Tests the MCB counters methods """
+        """Tests the MCB counters methods"""
         self.assertEqual(0x0, self.control.Counter.BusMessage)
         for _ in range(10):
             self.control.Counter.BusMessage += 1
             self.control.Counter.SlaveMessage += 1
         self.assertEqual(10, self.control.Counter.BusMessage)
         self.control.Counter.BusMessage = 0x00
-        self.assertEqual(0,  self.control.Counter.BusMessage)
+        self.assertEqual(0, self.control.Counter.BusMessage)
         self.assertEqual(10, self.control.Counter.SlaveMessage)
         self.control.Counter.reset()
         self.assertEqual(0, self.control.Counter.SlaveMessage)
 
     def test_modbus_control_block_update(self):
-        """ Tests the MCB counters update methods """
-        values = {'SlaveMessage':5, 'BusMessage':5}
+        """Tests the MCB counters update methods"""
+        values = {'SlaveMessage': 5, 'BusMessage': 5}
         self.control.Counter.BusMessage += 1
         self.control.Counter.SlaveMessage += 1
         self.control.Counter.update(values)
@@ -174,19 +177,19 @@ def test_modbus_control_block_update(self):
         self.assertEqual(6, self.control.Counter.BusMessage)
 
     def test_modbus_control_block_iterator(self):
-        """ Tests the MCB counters iterator """
+        """Tests the MCB counters iterator"""
         self.control.Counter.reset()
-        for _,count in self.control:
+        for _, count in self.control:
             self.assertEqual(0, count)
 
     def test_modbus_counters_handler_iterator(self):
-        """ Tests the MCB counters iterator """
+        """Tests the MCB counters iterator"""
         self.control.Counter.reset()
-        for _,count in self.control.Counter:
+        for _, count in self.control.Counter:
             self.assertEqual(0, count)
 
     def test_modbus_control_block_counter_summary(self):
-        """ Tests retrieving the current counter summary """
+        """Tests retrieving the current counter summary"""
         self.assertEqual(0x00, self.control.Counter.summary())
         for _ in range(10):
             self.control.Counter.BusMessage += 1
@@ -198,15 +201,14 @@ def test_modbus_control_block_counter_summary(self):
         self.assertEqual(0x00, self.control.Counter.summary())
 
     def test_modbus_control_block_listen(self):
-        """ Tests the MCB listen flag methods """
-
+        """Test the MCB listen flag methods"""
         self.control.ListenOnly = False
         self.assertEqual(self.control.ListenOnly, False)
         self.control.ListenOnly = not self.control.ListenOnly
         self.assertEqual(self.control.ListenOnly, True)
 
     def test_modbus_control_block_delimiter(self):
-        """ Tests the MCB delimiter setting methods """
+        """Tests the MCB delimiter setting methods"""
         self.control.Delimiter = b'\r'
         self.assertEqual(self.control.Delimiter, b'\r')
         self.control.Delimiter = '='
@@ -215,26 +217,26 @@ def test_modbus_control_block_delimiter(self):
         self.assertEqual(self.control.Delimiter, b'=')
 
     def test_modbus_control_block_diagnostic(self):
-        """ Tests the MCB delimiter setting methods """
+        """Tests the MCB delimiter setting methods"""
         self.assertEqual([False] * 16, self.control.getDiagnosticRegister())
-        for i in (1,3,4,6):
-            self.control.setDiagnostic({i:True})
+        for i in (1, 3, 4, 6):
+            self.control.setDiagnostic({i: True})
         self.assertEqual(True, self.control.getDiagnostic(1))
         self.assertEqual(False, self.control.getDiagnostic(2))
         actual = [False, True, False, True, True, False, True] + [False] * 9
         self.assertEqual(actual, self.control.getDiagnosticRegister())
         for i in range(16):
-            self.control.setDiagnostic({i:False})
+            self.control.setDiagnostic({i: False})
 
     def test_modbus_control_block_invalid_diagnostic(self):
-        """ Tests querying invalid MCB counters methods """
+        """Tests querying invalid MCB counters methods"""
         self.assertEqual(None, self.control.getDiagnostic(-1))
         self.assertEqual(None, self.control.getDiagnostic(17))
         self.assertEqual(None, self.control.getDiagnostic(None))
-        self.assertEqual(None, self.control.getDiagnostic([1,2,3]))
+        self.assertEqual(None, self.control.getDiagnostic([1, 2, 3]))
 
     def test_add_remove__single_clients(self):
-        """ Test adding and removing a host """
+        """Test adding and removing a host"""
         self.assertFalse(self.access.check("192.168.1.1"))  # NOSONAR
         self.access.add("192.168.1.1")  # NOSONAR
         self.assertTrue(self.access.check("192.168.1.1"))  # NOSONAR
@@ -243,7 +245,7 @@ def test_add_remove__single_clients(self):
         self.assertFalse(self.access.check("192.168.1.1"))  # NOSONAR
 
     def test_add_remove_multiple_clients(self):
-        """ Test adding and removing a host """
+        """Test adding and removing a host"""
         clients = ["192.168.1.1", "192.168.1.2", "192.168.1.3"]  # NOSONAR
         self.access.add(clients)
         for host in clients:
@@ -251,7 +253,7 @@ def test_add_remove_multiple_clients(self):
         self.access.remove(clients)
 
     def test_network_access_list_iterator(self):
-        """ Test adding and removing a host """
+        """Test adding and removing a host"""
         clients = ["127.0.0.1", "192.168.1.1", "192.168.1.2", "192.168.1.3"]  # NOSONAR
         self.access.add(clients)
         for host in self.access:
@@ -260,7 +262,7 @@ def test_network_access_list_iterator(self):
             self.assertTrue(host in self.access)
 
     def test_clearing_control_events(self):
-        """ Test adding and clearing modbus events """
+        """Test adding and clearing modbus events"""
         self.assertEqual(self.control.Events, [])
         event = ModbusEvent()
         self.control.addEvent(event)
@@ -271,7 +273,7 @@ def test_clearing_control_events(self):
         self.assertEqual(self.control.Counter.Event, 1)
 
     def test_retrieving_control_events(self):
-        """ Test adding and removing a host """
+        """Test adding and removing a host"""
         self.assertEqual(self.control.Events, [])
         event = RemoteReceiveEvent()
         self.control.addEvent(event)
@@ -280,7 +282,7 @@ def test_retrieving_control_events(self):
         self.assertEqual(packet, b'\x40')
 
     def test_modbus_plus_statistics(self):
-        """ Test device identification reading """
+        """Test device identification reading"""
         default = [0x0000] * 55
         statistics = ModbusPlusStatistics()
         self.assertEqual(default, statistics.encode())
@@ -288,24 +290,23 @@ def test_modbus_plus_statistics(self):
         self.assertEqual(default, statistics.encode())
         self.assertEqual(default, self.control.Plus.encode())
 
-
-
     def test_modbus_plus_statistics_helpers(self):
-        """ Test modbus plus statistics helper methods """
+        """Test modbus plus statistics helper methods"""
         statistics = ModbusPlusStatistics()
         summary = [
-             [0],[0],[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0],[0,0],[0],
-             [0,0,0,0,0,0,0,0],[0],[0],[0],[0],[0,0],[0],[0],[0],[0],
-             [0],[0],[0],[0,0],[0],[0],[0],[0],[0,0,0,0,0,0,0,0],[0],
-             [0,0,0,0,0,0,0,0],[0,0],[0],[0,0,0,0,0,0,0,0],
-             [0,0,0,0,0,0,0,0],[0],[0],[0,0],[0],[0],[0],[0],[0,0],
-             [0],[0],[0],[0],[0],[0,0],[0],[0,0,0,0,0,0,0,0]]
-        stats_summary = [x for x in statistics.summary()] # pylint: disable=unnecessary-comprehension
+            [0], [0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0], [0],
+            [0, 0, 0, 0, 0, 0, 0, 0], [0], [0], [0], [0], [0, 0], [0], [0], [0], [0],
+            [0], [0], [0], [0, 0], [0], [0], [0], [0], [0, 0, 0, 0, 0, 0, 0, 0], [0],
+            [0, 0, 0, 0, 0, 0, 0, 0], [0, 0], [0], [0, 0, 0, 0, 0, 0, 0, 0],
+            [0, 0, 0, 0, 0, 0, 0, 0], [0], [0], [0, 0], [0], [0], [0], [0], [0, 0],
+            [0], [0], [0], [0], [0], [0, 0], [0], [0, 0, 0, 0, 0, 0, 0, 0]]
+        stats_summary = [x for x in statistics.summary()]  # pylint: disable=unnecessary-comprehension
         self.assertEqual(sorted(summary), sorted(stats_summary))
         self.assertEqual(0x00, sum(sum(value[1]) for value in statistics))
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_diag_messages.py b/test/test_diag_messages.py
index 11b18d68e..1924bed65 100644
--- a/test/test_diag_messages.py
+++ b/test/test_diag_messages.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test diag messages. """
+"""Test diag messages."""
 import unittest
 
 from pymodbus.exceptions import NotImplementedException
@@ -45,10 +45,12 @@
 from pymodbus.diag_message import DiagnosticStatusSimpleRequest
 from pymodbus.diag_message import DiagnosticStatusSimpleResponse
 
+
 class SimpleDataStoreTest(unittest.TestCase):
-    """ Unittest for the pymodbus.diag_message module. """
+    """Unittest for the pymodbus.diag_message module."""
 
     def setUp(self):
+        """Do setup."""
         self.requests = [
             (RestartCommunicationsOptionRequest,
                 b'\x00\x01\x00\x00', b'\x00\x01\xff\x00'),
@@ -87,82 +89,82 @@ def setUp(self):
         ]
 
         self.responses = [
-            #(DiagnosticStatusResponse,                     b'\x00\x00\x00\x00'),
-            #(DiagnosticStatusSimpleResponse,               b'\x00\x00\x00\x00'),
-            (ReturnQueryDataResponse,                      b'\x00\x00\x00\x00'),
-            (RestartCommunicationsOptionResponse,          b'\x00\x01\x00\x00'),
-            (ReturnDiagnosticRegisterResponse,             b'\x00\x02\x00\x00'),
-            (ChangeAsciiInputDelimiterResponse,            b'\x00\x03\x00\x00'),
-            (ForceListenOnlyModeResponse,                  b'\x00\x04'),
-            (ReturnQueryDataResponse,                      b'\x00\x00\x00\x00'),
-            (ClearCountersResponse,                        b'\x00\x0a\x00\x00'),
-            (ReturnBusMessageCountResponse,                b'\x00\x0b\x00\x00'),
-            (ReturnBusCommunicationErrorCountResponse,     b'\x00\x0c\x00\x00'),
-            (ReturnBusExceptionErrorCountResponse,         b'\x00\x0d\x00\x00'),
-            (ReturnSlaveMessageCountResponse,              b'\x00\x0e\x00\x00'),
-            (ReturnSlaveNoReponseCountResponse,            b'\x00\x0f\x00\x00'),
-            (ReturnSlaveNAKCountResponse,                  b'\x00\x10\x00\x00'),
-            (ReturnSlaveBusyCountResponse,                 b'\x00\x11\x00\x00'),
-            (ReturnSlaveBusCharacterOverrunCountResponse,  b'\x00\x12\x00\x00'),
-            (ReturnIopOverrunCountResponse,                b'\x00\x13\x00\x00'),
-            (ClearOverrunCountResponse,                    b'\x00\x14\x00\x00'),
-            (GetClearModbusPlusResponse,                   b'\x00\x15\x00\x04' + b'\x00\x00' * 55),
+            # (DiagnosticStatusResponse,                     b'\x00\x00\x00\x00'),
+            # (DiagnosticStatusSimpleResponse,               b'\x00\x00\x00\x00'),
+            (ReturnQueryDataResponse, b'\x00\x00\x00\x00'),
+            (RestartCommunicationsOptionResponse, b'\x00\x01\x00\x00'),
+            (ReturnDiagnosticRegisterResponse, b'\x00\x02\x00\x00'),
+            (ChangeAsciiInputDelimiterResponse, b'\x00\x03\x00\x00'),
+            (ForceListenOnlyModeResponse, b'\x00\x04'),
+            (ReturnQueryDataResponse, b'\x00\x00\x00\x00'),
+            (ClearCountersResponse, b'\x00\x0a\x00\x00'),
+            (ReturnBusMessageCountResponse, b'\x00\x0b\x00\x00'),
+            (ReturnBusCommunicationErrorCountResponse, b'\x00\x0c\x00\x00'),
+            (ReturnBusExceptionErrorCountResponse, b'\x00\x0d\x00\x00'),
+            (ReturnSlaveMessageCountResponse, b'\x00\x0e\x00\x00'),
+            (ReturnSlaveNoReponseCountResponse, b'\x00\x0f\x00\x00'),
+            (ReturnSlaveNAKCountResponse, b'\x00\x10\x00\x00'),
+            (ReturnSlaveBusyCountResponse, b'\x00\x11\x00\x00'),
+            (ReturnSlaveBusCharacterOverrunCountResponse, b'\x00\x12\x00\x00'),
+            (ReturnIopOverrunCountResponse, b'\x00\x13\x00\x00'),
+            (ClearOverrunCountResponse, b'\x00\x14\x00\x00'),
+            (GetClearModbusPlusResponse, b'\x00\x15\x00\x04' + b'\x00\x00' * 55),
         ]
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
         del self.requests
         del self.responses
 
     def test_diagnostic_requests_decode(self):
-        """ Testing diagnostic request messages encoding """
-        for msg,enc,_ in self.requests:
+        """Testing diagnostic request messages encoding"""
+        for msg, enc, _ in self.requests:
             handle = DiagnosticStatusRequest()
             handle.decode(enc)
             self.assertEqual(handle.sub_function_code, msg.sub_function_code)
 
     def test_diagnostic_simple_requests(self):
-        """ Testing diagnostic request messages encoding """
+        """Testing diagnostic request messages encoding"""
         request = DiagnosticStatusSimpleRequest(b'\x12\x34')
         request.sub_function_code = 0x1234
-        self.assertRaises(NotImplementedException, lambda: request.execute()) # pylint: disable=unnecessary-lambda
+        self.assertRaises(NotImplementedException, lambda: request.execute())  # pylint: disable=unnecessary-lambda
         self.assertEqual(request.encode(), b'\x12\x34\x12\x34')
         DiagnosticStatusSimpleResponse(None)
 
     def test_diagnostic_response_decode(self):
-        """ Testing diagnostic request messages encoding """
-        for msg,enc,_ in self.requests:
+        """Testing diagnostic request messages encoding"""
+        for msg, enc, _ in self.requests:
             handle = DiagnosticStatusResponse()
             handle.decode(enc)
             self.assertEqual(handle.sub_function_code, msg.sub_function_code)
 
     def test_diagnostic_requests_encode(self):
-        """ Testing diagnostic request messages encoding """
-        for msg,enc,_ in self.requests:
+        """Testing diagnostic request messages encoding"""
+        for msg, enc, _ in self.requests:
             self.assertEqual(msg().encode(), enc)
 
     def test_diagnostic_execute(self):
-        """ Testing diagnostic message execution """
+        """Testing diagnostic message execution"""
         for message, encoded, executed in self.requests:
             encoded = message().execute().encode()
             self.assertEqual(encoded, executed)
 
     def test_return_query_data_request(self):
-        """ Testing diagnostic message execution """
-        message = ReturnQueryDataRequest([0x0000]*2)
+        """Testing diagnostic message execution"""
+        message = ReturnQueryDataRequest([0x0000] * 2)
         self.assertEqual(message.encode(), b'\x00\x00\x00\x00\x00\x00')
         message = ReturnQueryDataRequest(0x0000)
         self.assertEqual(message.encode(), b'\x00\x00\x00\x00')
 
     def test_return_query_data_response(self):
-        """ Testing diagnostic message execution """
-        message = ReturnQueryDataResponse([0x0000]*2)
+        """Testing diagnostic message execution"""
+        message = ReturnQueryDataResponse([0x0000] * 2)
         self.assertEqual(message.encode(), b'\x00\x00\x00\x00\x00\x00')
         message = ReturnQueryDataResponse(0x0000)
         self.assertEqual(message.encode(), b'\x00\x00\x00\x00')
 
     def test_restart_cmmunications_option(self):
-        """ Testing diagnostic message execution """
+        """Testing diagnostic message execution"""
         request = RestartCommunicationsOptionRequest(True)
         self.assertEqual(request.encode(), b'\x00\x01\xff\x00')
         request = RestartCommunicationsOptionRequest(False)
@@ -174,7 +176,7 @@ def test_restart_cmmunications_option(self):
         self.assertEqual(response.encode(), b'\x00\x01\x00\x00')
 
     def test_get_clear_modbus_plus_request_execute(self):
-        """ Testing diagnostic message execution """
+        """Testing diagnostic message execution"""
         request = GetClearModbusPlusRequest(data=ModbusPlusOperation.ClearStatistics)
         response = request.execute()
         self.assertEqual(response.message, ModbusPlusOperation.ClearStatistics)
@@ -182,10 +184,11 @@ def test_get_clear_modbus_plus_request_execute(self):
         request = GetClearModbusPlusRequest(data=ModbusPlusOperation.GetStatistics)
         response = request.execute()
         resp = [ModbusPlusOperation.GetStatistics]
-        self.assertEqual(response.message, resp+[0x00] * 55)
+        self.assertEqual(response.message, resp + [0x00] * 55)
+
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_events.py b/test/test_events.py
index 1120ee8c8..f3ed1f5e9 100644
--- a/test/test_events.py
+++ b/test/test_events.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test events. """
+"""Test events."""
 import unittest
 from pymodbus.events import (
     CommunicationRestartEvent,
@@ -11,23 +11,24 @@
 from pymodbus.exceptions import NotImplementedException
 from pymodbus.exceptions import ParameterException
 
+
 class ModbusEventsTest(unittest.TestCase):
-    """ Unittest for the pymodbus.device module. """
+    """Unittest for the pymodbus.device module."""
 
     def setUp(self):
-        """ Sets up the test environment """
+        """Set up the test environment"""
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
 
     def test_modbus_event_base_class(self):
-        """ Test modbus event base class. """
+        """Test modbus event base class."""
         event = ModbusEvent()
         self.assertRaises(NotImplementedException, event.encode)
         self.assertRaises(NotImplementedException, lambda: event.decode(None))
 
     def test_remote_receive_event(self):
-        """ Test remove receive event. """
+        """Test remove receive event."""
         event = RemoteReceiveEvent()
         event.decode(b'\x70')
         self.assertTrue(event.overrun)
@@ -35,7 +36,7 @@ def test_remote_receive_event(self):
         self.assertTrue(event.broadcast)
 
     def test_remote_sent_event(self):
-        """ Test remote sent event. """
+        """Test remote sent event."""
         event = RemoteSendEvent()
         result = event.encode()
         self.assertEqual(result, b'\x40')
@@ -48,21 +49,21 @@ def test_remote_sent_event(self):
         self.assertTrue(event.listen)
 
     def test_remote_sent_event_encode(self):
-        """ Test remote sent event encode. """
+        """Test remote sent event encode."""
         arguments = {
-            'read'          : True,
-            'slave_abort'   : True,
-            'slave_busy'    : True,
-            'slave_nak'     : True,
-            'write_timeout' : True,
-            'listen'        : True,
+            'read': True,
+            'slave_abort': True,
+            'slave_busy': True,
+            'slave_nak': True,
+            'write_timeout': True,
+            'listen': True,
         }
         event = RemoteSendEvent(**arguments)
         result = event.encode()
         self.assertEqual(result, b'\x7f')
 
     def test_entered_listen_mode_event(self):
-        """ Test entered listen mode event. """
+        """Test entered listen mode event."""
         event = EnteredListenModeEvent()
         result = event.encode()
         self.assertEqual(result, b'\x04')
@@ -71,7 +72,7 @@ def test_entered_listen_mode_event(self):
         self.assertRaises(ParameterException, lambda: event.decode(b'\x00'))
 
     def test_communication_restart_event(self):
-        """ Test communication restart event. """
+        """Test communication restart event."""
         event = CommunicationRestartEvent()
         result = event.encode()
         self.assertEqual(result, b'\x00')
@@ -79,8 +80,9 @@ def test_communication_restart_event(self):
         self.assertEqual(event.value, 0x00)
         self.assertRaises(ParameterException, lambda: event.decode(b'\x04'))
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_exceptions.py b/test/test_exceptions.py
index 2403d5d07..bb314a673 100644
--- a/test/test_exceptions.py
+++ b/test/test_exceptions.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test exceptions. """
+"""Test exceptions."""
 import unittest
 
 from pymodbus.exceptions import (
@@ -10,24 +10,25 @@
     ModbusIOException,
 )
 
+
 class SimpleExceptionsTest(unittest.TestCase):
-    """ Unittest for the pymodbus.exceptions module. """
+    """Unittest for the pymodbus.exceptions module."""
 
     def setUp(self):
-        """ Initializes the test environment """
+        """Initialize the test environment"""
         self.exceptions = [
-                ModbusException("bad base"),
-                ModbusIOException("bad register"),
-                ParameterException("bad parameter"),
-                NotImplementedException("bad function"),
-                ConnectionException("bad connection"),
+            ModbusException("bad base"),
+            ModbusIOException("bad register"),
+            ParameterException("bad parameter"),
+            NotImplementedException("bad function"),
+            ConnectionException("bad connection"),
         ]
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
 
     def test_exceptions(self):
-        """ Test all module exceptions """
+        """Test all module exceptions"""
         for exc in self.exceptions:
             try:
                 raise exc
@@ -36,8 +37,9 @@ def test_exceptions(self):
                 return
             self.fail("Excepted a ModbusExceptions")
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_factory.py b/test/test_factory.py
index b9dec1041..377d4ad85 100644
--- a/test/test_factory.py
+++ b/test/test_factory.py
@@ -1,95 +1,97 @@
 #!/usr/bin/env python3
-""" Test factory. """
+"""Test factory."""
 import unittest
 
 from pymodbus.factory import ServerDecoder, ClientDecoder
 from pymodbus.exceptions import ModbusException
 from pymodbus.pdu import ModbusResponse, ModbusRequest
 
+
 def _raise_exception(_):
-    """ Raise exception. """
+    """Raise exception."""
     raise ModbusException('something')
 
+
 class SimpleFactoryTest(unittest.TestCase):
-    """ Unittest for the pymod.exceptions module. """
+    """Unittest for the pymod.exceptions module."""
 
     def setUp(self):
-        """ Initializes the test environment """
-        self.client  = ClientDecoder()
-        self.server  = ServerDecoder()
+        """Initialize the test environment"""
+        self.client = ClientDecoder()
+        self.server = ServerDecoder()
         self.request = (
-                (0x01, b'\x01\x00\x01\x00\x01'),                       # read coils
-                (0x02, b'\x02\x00\x01\x00\x01'),                       # read discrete inputs
-                (0x03, b'\x03\x00\x01\x00\x01'),                       # read holding registers
-                (0x04, b'\x04\x00\x01\x00\x01'),                       # read input registers
-                (0x05, b'\x05\x00\x01\x00\x01'),                       # write single coil
-                (0x06, b'\x06\x00\x01\x00\x01'),                       # write single register
-                (0x07, b'\x07'),                                       # read exception status
-                (0x08, b'\x08\x00\x00\x00\x00'),                       # read diagnostic
-                (0x0b, b'\x0b'),                                       # get comm event counters
-                (0x0c, b'\x0c'),                                       # get comm event log
-                (0x0f, b'\x0f\x00\x01\x00\x08\x01\x00\xff'),           # write multiple coils
-                (0x10, b'\x10\x00\x01\x00\x02\x04\0xff\xff'),          # write multiple registers
-                (0x11, b'\x11'),                                       # report slave id
-                (0x14, b'\x14\x0e\x06\x00\x04\x00\x01\x00\x02' \
-                       b'\x06\x00\x03\x00\x09\x00\x02'),               # read file record
-                (0x15, b'\x15\x0d\x06\x00\x04\x00\x07\x00\x03' \
-                       b'\x06\xaf\x04\xbe\x10\x0d'),                   # write file record
-                (0x16, b'\x16\x00\x01\x00\xff\xff\x00'),               # mask write register
-                (0x17, b'\x17\x00\x01\x00\x01\x00\x01\x00\x01\x02\x12\x34'), # r/w multiple regs
-                (0x18, b'\x18\x00\x01'),                               # read fifo queue
-                (0x2b, b'\x2b\x0e\x01\x00'),                           # read device identification
+            (0x01, b'\x01\x00\x01\x00\x01'),                       # read coils
+            (0x02, b'\x02\x00\x01\x00\x01'),                       # read discrete inputs
+            (0x03, b'\x03\x00\x01\x00\x01'),                       # read holding registers
+            (0x04, b'\x04\x00\x01\x00\x01'),                       # read input registers
+            (0x05, b'\x05\x00\x01\x00\x01'),                       # write single coil
+            (0x06, b'\x06\x00\x01\x00\x01'),                       # write single register
+            (0x07, b'\x07'),                                       # read exception status
+            (0x08, b'\x08\x00\x00\x00\x00'),                       # read diagnostic
+            (0x0b, b'\x0b'),                                       # get comm event counters
+            (0x0c, b'\x0c'),                                       # get comm event log
+            (0x0f, b'\x0f\x00\x01\x00\x08\x01\x00\xff'),           # write multiple coils
+            (0x10, b'\x10\x00\x01\x00\x02\x04\0xff\xff'),          # write multiple registers
+            (0x11, b'\x11'),                                       # report slave id
+            (0x14, b'\x14\x0e\x06\x00\x04\x00\x01\x00\x02' \
+             b'\x06\x00\x03\x00\x09\x00\x02'),               # read file record
+            (0x15, b'\x15\x0d\x06\x00\x04\x00\x07\x00\x03' \
+             b'\x06\xaf\x04\xbe\x10\x0d'),                   # write file record
+            (0x16, b'\x16\x00\x01\x00\xff\xff\x00'),               # mask write register
+            (0x17, b'\x17\x00\x01\x00\x01\x00\x01\x00\x01\x02\x12\x34'),  # r/w multiple regs
+            (0x18, b'\x18\x00\x01'),                               # read fifo queue
+            (0x2b, b'\x2b\x0e\x01\x00'),                           # read device identification
         )
 
         self.response = (
-                (0x01, b'\x01\x01\x01'),                             # read coils
-                (0x02, b'\x02\x01\x01'),                             # read discrete inputs
-                (0x03, b'\x03\x02\x01\x01'),                         # read holding registers
-                (0x04, b'\x04\x02\x01\x01'),                         # read input registers
-                (0x05, b'\x05\x00\x01\x00\x01'),                     # write single coil
-                (0x06, b'\x06\x00\x01\x00\x01'),                     # write single register
-                (0x07, b'\x07\x00'),                                 # read exception status
-                (0x08, b'\x08\x00\x00\x00\x00'),                     # read diagnostic
-                (0x0b, b'\x0b\x00\x00\x00\x00'),                     # get comm event counters
-                (0x0c, b'\x0c\x08\x00\x00\x01\x08\x01\x21\x20\x00'), # get comm event log
-                (0x0f, b'\x0f\x00\x01\x00\x08'), # write multiple coils
-                (0x10, b'\x10\x00\x01\x00\x02'), # write multiple registers
-                (0x11, b'\x11\x03\x05\x01\x54'), # report slave id (device specific)
-                (0x14, b'\x14\x0c\x05\x06\x0d\xfe\x00\x20\x05' \
-                       b'\x06\x33\xcd\x00\x40'),                     # read file record
-                (0x15, b'\x15\x0d\x06\x00\x04\x00\x07\x00\x03' \
-                       b'\x06\xaf\x04\xbe\x10\x0d'),                 # write file record
-                (0x16, b'\x16\x00\x01\x00\xff\xff\x00'),             # mask write register
-                (0x17, b'\x17\x02\x12\x34'),                         # read/write multiple registers
-                (0x18, b'\x18\x00\x01\x00\x01\x00\x00'),             # read fifo queue
-                (0x2b, b'\x2b\x0e\x01\x01\x00\x00\x01\x00\x01\x77'), # read device identification
+            (0x01, b'\x01\x01\x01'),                             # read coils
+            (0x02, b'\x02\x01\x01'),                             # read discrete inputs
+            (0x03, b'\x03\x02\x01\x01'),                         # read holding registers
+            (0x04, b'\x04\x02\x01\x01'),                         # read input registers
+            (0x05, b'\x05\x00\x01\x00\x01'),                     # write single coil
+            (0x06, b'\x06\x00\x01\x00\x01'),                     # write single register
+            (0x07, b'\x07\x00'),                                 # read exception status
+            (0x08, b'\x08\x00\x00\x00\x00'),                     # read diagnostic
+            (0x0b, b'\x0b\x00\x00\x00\x00'),                     # get comm event counters
+            (0x0c, b'\x0c\x08\x00\x00\x01\x08\x01\x21\x20\x00'),  # get comm event log
+            (0x0f, b'\x0f\x00\x01\x00\x08'),  # write multiple coils
+            (0x10, b'\x10\x00\x01\x00\x02'),  # write multiple registers
+            (0x11, b'\x11\x03\x05\x01\x54'),  # report slave id (device specific)
+            (0x14, b'\x14\x0c\x05\x06\x0d\xfe\x00\x20\x05' \
+             b'\x06\x33\xcd\x00\x40'),                     # read file record
+            (0x15, b'\x15\x0d\x06\x00\x04\x00\x07\x00\x03' \
+             b'\x06\xaf\x04\xbe\x10\x0d'),                 # write file record
+            (0x16, b'\x16\x00\x01\x00\xff\xff\x00'),             # mask write register
+            (0x17, b'\x17\x02\x12\x34'),                         # read/write multiple registers
+            (0x18, b'\x18\x00\x01\x00\x01\x00\x00'),             # read fifo queue
+            (0x2b, b'\x2b\x0e\x01\x01\x00\x00\x01\x00\x01\x77'),  # read device identification
         )
 
         self.exception = (
-                (0x81, b'\x81\x01\xd0\x50'), # illegal function exception
-                (0x82, b'\x82\x02\x90\xa1'), # illegal data address exception
-                (0x83, b'\x83\x03\x50\xf1'), # illegal data value exception
-                (0x84, b'\x84\x04\x13\x03'), # skave device failure exception
-                (0x85, b'\x85\x05\xd3\x53'), # acknowledge exception
-                (0x86, b'\x86\x06\x93\xa2'), # slave device busy exception
-                (0x87, b'\x87\x08\x53\xf2'), # memory parity exception
-                (0x88, b'\x88\x0a\x16\x06'), # gateway path unavailable exception
-                (0x89, b'\x89\x0b\xd6\x56'), # gateway target failed exception
+            (0x81, b'\x81\x01\xd0\x50'),  # illegal function exception
+            (0x82, b'\x82\x02\x90\xa1'),  # illegal data address exception
+            (0x83, b'\x83\x03\x50\xf1'),  # illegal data value exception
+            (0x84, b'\x84\x04\x13\x03'),  # skave device failure exception
+            (0x85, b'\x85\x05\xd3\x53'),  # acknowledge exception
+            (0x86, b'\x86\x06\x93\xa2'),  # slave device busy exception
+            (0x87, b'\x87\x08\x53\xf2'),  # memory parity exception
+            (0x88, b'\x88\x0a\x16\x06'),  # gateway path unavailable exception
+            (0x89, b'\x89\x0b\xd6\x56'),  # gateway target failed exception
         )
 
         self.bad = (
-                (0x80, b'\x80\x00\x00\x00'), # Unknown Function
-                (0x81, b'\x81\x00\x00\x00'), # error message
+            (0x80, b'\x80\x00\x00\x00'),  # Unknown Function
+            (0x81, b'\x81\x00\x00\x00'),  # error message
         )
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
         del self.bad
         del self.request
         del self.response
 
     def test_exception_lookup(self):
-        """ Test that we can look up exception messages """
+        """Test that we can look up exception messages"""
         for func, _ in self.exception:
             response = self.client.lookupPduClass(func)
             self.assertNotEqual(response, None)
@@ -99,55 +101,56 @@ def test_exception_lookup(self):
             self.assertNotEqual(response, None)
 
     def test_response_lookup(self):
-        """ Test a working response factory lookup """
+        """Test a working response factory lookup"""
         for func, _ in self.response:
             response = self.client.lookupPduClass(func)
             self.assertNotEqual(response, None)
 
     def test_request_ookup(self):
-        """ Test a working request factory lookup """
+        """Test a working request factory lookup"""
         for func, _ in self.request:
             request = self.client.lookupPduClass(func)
             self.assertNotEqual(request, None)
 
     def test_response_working(self):
-        """ Test a working response factory decoders """
+        """Test a working response factory decoders"""
         for func, msg in self.response:
             try:
                 self.client.decode(msg)
             except ModbusException:
-                self.fail("Failed to Decode Response Message", func) # pylint: disable=too-many-function-args
+                self.fail("Failed to Decode Response Message", func)  # pylint: disable=too-many-function-args
 
     def test_response_errors(self):
-        """ Test a response factory decoder exceptions """
-        self.assertRaises(ModbusException, self.client._helper, self.bad[0][1]) # pylint: disable=protected-access
+        """Test a response factory decoder exceptions"""
+        self.assertRaises(ModbusException, self.client._helper, self.bad[0][1])  # pylint: disable=protected-access
         self.assertEqual(self.client.decode(self.bad[1][1]).function_code, self.bad[1][0],
-                "Failed to decode error PDU")
+                         "Failed to decode error PDU")
 
     def test_requests_working(self):
-        """ Test a working request factory decoders """
+        """Test a working request factory decoders"""
         for func, msg in self.request:
             try:
                 self.server.decode(msg)
             except ModbusException:
-                self.fail("Failed to Decode Request Message", func) # pylint: disable=too-many-function-args
+                self.fail("Failed to Decode Request Message", func)  # pylint: disable=too-many-function-args
 
     def test_client_factory_fails(self):
-        """ Tests that a client factory will fail to decode a bad message """
-        self.client._helper = _raise_exception # pylint: disable=protected-access
+        """Tests that a client factory will fail to decode a bad message"""
+        self.client._helper = _raise_exception  # pylint: disable=protected-access
         actual = self.client.decode(None)
         self.assertEqual(actual, None)
 
     def test_server_factory_fails(self):
-        """ Tests that a server factory will fail to decode a bad message """
-        self.server._helper = _raise_exception # pylint: disable=protected-access
+        """Tests that a server factory will fail to decode a bad message"""
+        self.server._helper = _raise_exception  # pylint: disable=protected-access
         actual = self.server.decode(None)
         self.assertEqual(actual, None)
 
     def test_server_register_custom_request(self):
-        """ Test server register custom request. """
+        """Test server register custom request."""
         class CustomRequest(ModbusRequest):
-            """ Custom request. """
+            """Custom request."""
+
             function_code = 0xff
         self.server.register(CustomRequest)
         self.assertTrue(self.client.lookupPduClass(CustomRequest.function_code))
@@ -156,30 +159,33 @@ class CustomRequest(ModbusRequest):
         self.assertTrue(self.server.lookupPduClass(CustomRequest.function_code))
 
     def test_client_register_custom_response(self):
-        """ Test client register custom response. """
+        """Test client register custom response."""
         class CustomResponse(ModbusResponse):
-            """ Custom response. """
+            """Custom response."""
+
             function_code = 0xff
         self.client.register(CustomResponse)
         self.assertTrue(self.client.lookupPduClass(CustomResponse.function_code))
         CustomResponse.sub_function_code = 0xff
         self.client.register(CustomResponse)
         self.assertTrue(self.client.lookupPduClass(CustomResponse.function_code))
-#---------------------------------------------------------------------------#
-# I don't actually know what is supposed to be returned here, I assume that
-# since the high bit is set, it will simply echo the resulting message
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  I don't actually know what is supposed to be returned here, I assume that
+#  since the high bit is set, it will simply echo the resulting message
+# ---------------------------------------------------------------------------#
+
     def test_request_errors(self):
-        """ Test a request factory decoder exceptions """
+        """Test a request factory decoder exceptions"""
         for func, msg in self.bad:
             result = self.server.decode(msg)
             self.assertEqual(result.ErrorCode, 1,
-                    "Failed to decode invalid requests")
+                             "Failed to decode invalid requests")
             self.assertEqual(result.execute(None).function_code, func,
-                    "Failed to create correct response message")
+                             "Failed to create correct response message")
+
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_file_message.py b/test/test_file_message.py
index 295cbd29e..a0646b106 100644
--- a/test/test_file_message.py
+++ b/test/test_file_message.py
@@ -1,6 +1,5 @@
 #!/usr/bin/env python3
-""" Bit Message Test Fixture
---------------------------------
+"""Bit Message Test Fixture.
 
 This fixture tests the functionality of all the
 bit based request/response messages:
@@ -22,97 +21,98 @@
 
 from .modbus_mocks import MockContext
 
-#---------------------------------------------------------------------------#
-# Fixture
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Fixture
+# ---------------------------------------------------------------------------#
+
+
 class ModbusBitMessageTests(unittest.TestCase):
-    """ Modbus bit message tests. """
-    #-----------------------------------------------------------------------#
-    # Setup/TearDown
-    #-----------------------------------------------------------------------#
+    """Modbus bit message tests."""
+
+    # -----------------------------------------------------------------------#
+    #  Setup/TearDown
+    # -----------------------------------------------------------------------#
 
     def setUp(self):
-        """ Initializes the test environment and builds request/result
-        encoding pairs
-        """
+        """Initialize the test environment and builds request/result encoding pairs."""
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
 
-    #-----------------------------------------------------------------------#
-    # Read Fifo Queue
-    #-----------------------------------------------------------------------#
+    # -----------------------------------------------------------------------#
+    #  Read Fifo Queue
+    # -----------------------------------------------------------------------#
 
     def test_read_fifo_queue_request_encode(self):
-        """ Test basic bit message encoding/decoding """
-        handle  = ReadFifoQueueRequest(0x1234)
-        result  = handle.encode()
+        """Test basic bit message encoding/decoding"""
+        handle = ReadFifoQueueRequest(0x1234)
+        result = handle.encode()
         self.assertEqual(result, b'\x12\x34')
 
     def test_read_fifo_queue_request_decode(self):
-        """ Test basic bit message encoding/decoding """
-        handle  = ReadFifoQueueRequest(0x0000)
+        """Test basic bit message encoding/decoding"""
+        handle = ReadFifoQueueRequest(0x0000)
         handle.decode(b'\x12\x34')
         self.assertEqual(handle.address, 0x1234)
 
     def test_read_fifo_queue_request(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         context = MockContext()
-        handle  = ReadFifoQueueRequest(0x1234)
-        result  = handle.execute(context)
+        handle = ReadFifoQueueRequest(0x1234)
+        result = handle.execute(context)
         self.assertTrue(isinstance(result, ReadFifoQueueResponse))
 
         handle.address = -1
-        result  = handle.execute(context)
+        result = handle.execute(context)
         self.assertEqual(ModbusExceptions.IllegalValue,
-                result.exception_code)
+                         result.exception_code)
 
-        handle.values = [0x00]*33
-        result  = handle.execute(context)
+        handle.values = [0x00] * 33
+        result = handle.execute(context)
         self.assertEqual(ModbusExceptions.IllegalValue,
-                result.exception_code)
+                         result.exception_code)
 
     def test_read_fifo_queue_request_error(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         context = MockContext()
-        handle  = ReadFifoQueueRequest(0x1234)
-        handle.values = [0x00]*32
+        handle = ReadFifoQueueRequest(0x1234)
+        handle.values = [0x00] * 32
         result = handle.execute(context)
         self.assertEqual(result.function_code, 0x98)
 
     def test_read_fifo_queue_response_encode(self):
-        """ Test that the read fifo queue response can encode """
+        """Test that the read fifo queue response can encode"""
         message = b'\x00\n\x00\x08\x00\x01\x00\x02\x00\x03\x00\x04'
-        handle  = ReadFifoQueueResponse([1,2,3,4])
-        result  = handle.encode()
+        handle = ReadFifoQueueResponse([1, 2, 3, 4])
+        result = handle.encode()
         self.assertEqual(result, message)
 
     def test_read_fifo_queue_response_decode(self):
-        """ Test that the read fifo queue response can decode """
+        """Test that the read fifo queue response can decode"""
         message = b'\x00\n\x00\x08\x00\x01\x00\x02\x00\x03\x00\x04'
-        handle  = ReadFifoQueueResponse([1,2,3,4])
+        handle = ReadFifoQueueResponse([1, 2, 3, 4])
         handle.decode(message)
-        self.assertEqual(handle.values, [1,2,3,4])
+        self.assertEqual(handle.values, [1, 2, 3, 4])
 
     def test_rtu_frame_size(self):
-        """ Test that the read fifo queue response can decode """
+        """Test that the read fifo queue response can decode"""
         message = b'\x00\n\x00\x08\x00\x01\x00\x02\x00\x03\x00\x04'
-        result  = ReadFifoQueueResponse.calculateRtuFrameSize(message)
+        result = ReadFifoQueueResponse.calculateRtuFrameSize(message)
         self.assertEqual(result, 14)
 
-    #-----------------------------------------------------------------------#
-    # File Record
-    #-----------------------------------------------------------------------#
+    # -----------------------------------------------------------------------#
+    #  File Record
+    # -----------------------------------------------------------------------#
 
     def test_file_record_length(self):
-        """ Test file record length generation """
+        """Test file record length generation"""
         record = FileRecord(file_number=0x01, record_number=0x02,
-            record_data=b'\x00\x01\x02\x04')
+                            record_data=b'\x00\x01\x02\x04')
         self.assertEqual(record.record_length, 0x02)
         self.assertEqual(record.response_length, 0x05)
 
     def test_file_record_compare(self):
-        """ Test file record comparison operations """
+        """Test file record comparison operations"""
         record1 = FileRecord(file_number=0x01, record_number=0x02, record_data=b'\x00\x01\x02\x04')
         record2 = FileRecord(file_number=0x01, record_number=0x02, record_data=b'\x00\x0a\x0e\x04')
         record3 = FileRecord(file_number=0x02, record_number=0x03, record_data=b'\x00\x01\x02\x04')
@@ -127,130 +127,130 @@ def test_file_record_compare(self):
         self.assertEqual(str(record2), "FileRecord(file=1, record=2, length=2)")
         self.assertEqual(str(record3), "FileRecord(file=2, record=3, length=2)")
 
-    #-----------------------------------------------------------------------#
-    # Read File Record Request
-    #-----------------------------------------------------------------------#
+    # -----------------------------------------------------------------------#
+    #  Read File Record Request
+    # -----------------------------------------------------------------------#
 
     def test_read_file_record_request_encode(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         records = [FileRecord(file_number=0x01, record_number=0x02)]
-        handle  = ReadFileRecordRequest(records)
-        result  = handle.encode()
+        handle = ReadFileRecordRequest(records)
+        result = handle.encode()
         self.assertEqual(result, b'\x07\x06\x00\x01\x00\x02\x00\x00')
 
     def test_read_file_record_request_decode(self):
-        """ Test basic bit message encoding/decoding """
-        record  = FileRecord(file_number=0x04, record_number=0x01, record_length=0x02)
+        """Test basic bit message encoding/decoding"""
+        record = FileRecord(file_number=0x04, record_number=0x01, record_length=0x02)
         request = b'\x0e\x06\x00\x04\x00\x01\x00\x02\x06\x00\x03\x00\x09\x00\x02'
-        handle  = ReadFileRecordRequest()
+        handle = ReadFileRecordRequest()
         handle.decode(request)
         self.assertEqual(handle.records[0], record)
 
     def test_read_file_record_request_rtu_frame_size(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         request = b'\x00\x00\x0e\x06\x00\x04\x00\x01\x00\x02\x06\x00\x03\x00\x09\x00\x02'
-        handle  = ReadFileRecordRequest()
-        size    = handle.calculateRtuFrameSize(request)
+        handle = ReadFileRecordRequest()
+        size = handle.calculateRtuFrameSize(request)
         self.assertEqual(size, 0x0e + 5)
 
     def test_read_file_record_request_execute(self):
-        """ Test basic bit message encoding/decoding """
-        handle  = ReadFileRecordRequest()
-        result  = handle.execute(None)
+        """Test basic bit message encoding/decoding"""
+        handle = ReadFileRecordRequest()
+        result = handle.execute(None)
         self.assertTrue(isinstance(result, ReadFileRecordResponse))
 
-    #-----------------------------------------------------------------------#
-    # Read File Record Response
-    #-----------------------------------------------------------------------#
+    # -----------------------------------------------------------------------#
+    #  Read File Record Response
+    # -----------------------------------------------------------------------#
 
     def test_read_file_record_response_encode(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         records = [FileRecord(record_data=b'\x00\x01\x02\x03')]
-        handle  = ReadFileRecordResponse(records)
-        result  = handle.encode()
+        handle = ReadFileRecordResponse(records)
+        result = handle.encode()
         self.assertEqual(result, b'\x06\x06\x02\x00\x01\x02\x03')
 
     def test_read_file_record_response_decode(self):
-        """ Test basic bit message encoding/decoding """
-        record  = FileRecord(file_number=0x00, record_number=0x00,
-            record_data=b'\x0d\xfe\x00\x20')
+        """Test basic bit message encoding/decoding"""
+        record = FileRecord(file_number=0x00, record_number=0x00,
+                            record_data=b'\x0d\xfe\x00\x20')
         request = b'\x0c\x05\x06\x0d\xfe\x00\x20\x05\x05\x06\x33\xcd\x00\x40'
-        handle  = ReadFileRecordResponse()
+        handle = ReadFileRecordResponse()
         handle.decode(request)
         self.assertEqual(handle.records[0], record)
 
     def test_read_file_record_response_rtu_frame_size(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         request = b'\x00\x00\x0c\x05\x06\x0d\xfe\x00\x20\x05\x05\x06\x33\xcd\x00\x40'
-        handle  = ReadFileRecordResponse()
-        size    = handle.calculateRtuFrameSize(request)
+        handle = ReadFileRecordResponse()
+        size = handle.calculateRtuFrameSize(request)
         self.assertEqual(size, 0x0c + 5)
 
-    #-----------------------------------------------------------------------#
-    # Write File Record Request
-    #-----------------------------------------------------------------------#
+    # -----------------------------------------------------------------------#
+    #  Write File Record Request
+    # -----------------------------------------------------------------------#
 
     def test_write_file_record_request_encode(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         records = [FileRecord(file_number=0x01, record_number=0x02,
-                record_data=b'\x00\x01\x02\x03')]
-        handle  = WriteFileRecordRequest(records)
-        result  = handle.encode()
+                              record_data=b'\x00\x01\x02\x03')]
+        handle = WriteFileRecordRequest(records)
+        result = handle.encode()
         self.assertEqual(result, b'\x0b\x06\x00\x01\x00\x02\x00\x02\x00\x01\x02\x03')
 
     def test_write_file_record_request_decode(self):
-        """ Test basic bit message encoding/decoding """
-        record  = FileRecord(file_number=0x04, record_number=0x07,
-            record_data=b'\x06\xaf\x04\xbe\x10\x0d')
+        """Test basic bit message encoding/decoding"""
+        record = FileRecord(file_number=0x04, record_number=0x07,
+                            record_data=b'\x06\xaf\x04\xbe\x10\x0d')
         request = b'\x0d\x06\x00\x04\x00\x07\x00\x03\x06\xaf\x04\xbe\x10\x0d'
-        handle  = WriteFileRecordRequest()
+        handle = WriteFileRecordRequest()
         handle.decode(request)
         self.assertEqual(handle.records[0], record)
 
     def test_write_file_record_request_rtu_frame_size(self):
-        """ Test write file record request rtu frame size calculation """
+        """Test write file record request rtu frame size calculation"""
         request = b'\x00\x00\x0d\x06\x00\x04\x00\x07\x00\x03\x06\xaf\x04\xbe\x10\x0d'
-        handle  = WriteFileRecordRequest()
-        size    = handle.calculateRtuFrameSize(request)
+        handle = WriteFileRecordRequest()
+        size = handle.calculateRtuFrameSize(request)
         self.assertEqual(size, 0x0d + 5)
 
     def test_write_file_record_request_execute(self):
-        """ Test basic bit message encoding/decoding """
-        handle  = WriteFileRecordRequest()
-        result  = handle.execute(None)
+        """Test basic bit message encoding/decoding"""
+        handle = WriteFileRecordRequest()
+        result = handle.execute(None)
         self.assertTrue(isinstance(result, WriteFileRecordResponse))
 
-    #-----------------------------------------------------------------------#
-    # Write File Record Response
-    #-----------------------------------------------------------------------#
+    # -----------------------------------------------------------------------#
+    #  Write File Record Response
+    # -----------------------------------------------------------------------#
 
     def test_write_file_record_response_encode(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         records = [FileRecord(file_number=0x01, record_number=0x02,
-            record_data=b'\x00\x01\x02\x03')]
-        handle  = WriteFileRecordResponse(records)
-        result  = handle.encode()
+                              record_data=b'\x00\x01\x02\x03')]
+        handle = WriteFileRecordResponse(records)
+        result = handle.encode()
         self.assertEqual(result, b'\x0b\x06\x00\x01\x00\x02\x00\x02\x00\x01\x02\x03')
 
     def test_write_file_record_response_decode(self):
-        """ Test basic bit message encoding/decoding """
-        record  = FileRecord(file_number=0x04, record_number=0x07,
-            record_data=b'\x06\xaf\x04\xbe\x10\x0d')
+        """Test basic bit message encoding/decoding"""
+        record = FileRecord(file_number=0x04, record_number=0x07,
+                            record_data=b'\x06\xaf\x04\xbe\x10\x0d')
         request = b'\x0d\x06\x00\x04\x00\x07\x00\x03\x06\xaf\x04\xbe\x10\x0d'
-        handle  = WriteFileRecordResponse()
+        handle = WriteFileRecordResponse()
         handle.decode(request)
         self.assertEqual(handle.records[0], record)
 
     def test_write_file_record_response_rtu_frame_size(self):
-        """ Test write file record response rtu frame size calculation """
+        """Test write file record response rtu frame size calculation"""
         request = b'\x00\x00\x0d\x06\x00\x04\x00\x07\x00\x03\x06\xaf\x04\xbe\x10\x0d'
-        handle  = WriteFileRecordResponse()
-        size    = handle.calculateRtuFrameSize(request)
+        handle = WriteFileRecordResponse()
+        size = handle.calculateRtuFrameSize(request)
         self.assertEqual(size, 0x0d + 5)
 
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_fixes.py b/test/test_fixes.py
index f7c12f32f..cd403f31d 100644
--- a/test/test_fixes.py
+++ b/test/test_fixes.py
@@ -1,26 +1,28 @@
 #!/usr/bin/env python3
-""" Test fixes. """
+"""Test fixes."""
 import logging
 import unittest
 
+
 class ModbusFixesTest(unittest.TestCase):
-    """ Unittest for the pymodbus._version code. """
+    """Unittest for the pymodbus._version code."""
 
     def test_true_false_defined(self):
-        """ Test that True and False are defined on all versions"""
+        """Test that True and False are defined on all versions"""
         try:
-            True,False
+            True, False
         except NameError:
             self.assertEqual(True, 1)
             self.assertEqual(False, 1)
 
     def test_null_logger_attached(self):
-        """ Test that the null logger is attached"""
+        """Test that the null logger is attached"""
         logger = logging.getLogger('pymodbus')
         self.assertEqual(len(logger.handlers), 1)
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_framers.py b/test/test_framers.py
index 32eb21c03..2b17ebf02 100644
--- a/test/test_framers.py
+++ b/test/test_framers.py
@@ -1,4 +1,4 @@
-""" Test framers. """
+"""Test framers."""
 from unittest.mock import Mock, patch
 import pytest
 
@@ -13,58 +13,58 @@
 
 @pytest.fixture
 def rtu_framer():
-    """ RTU framer. """
+    """RTU framer."""
     return ModbusRtuFramer(ClientDecoder())
 
 
 @pytest.fixture
 def ascii_framer():
-    """ Ascii framer. """
+    """Ascii framer."""
     return ModbusAsciiFramer(ClientDecoder())
 
 
 @pytest.fixture
 def binary_framer():
-    """ Binary framer. """
+    """Binary framer."""
     return ModbusBinaryFramer(ClientDecoder())
 
 
-@pytest.mark.parametrize("framer",  [ModbusRtuFramer,
-                                     ModbusAsciiFramer,
-                                     ModbusBinaryFramer,
-                                     ])
+@pytest.mark.parametrize("framer", [ModbusRtuFramer,
+                                    ModbusAsciiFramer,
+                                    ModbusBinaryFramer,
+                                    ])
 def test_framer_initialization(framer):
-    """ Test framer initialization. """
+    """Test framer initialization."""
     decoder = ClientDecoder()
     framer = framer(decoder)
-    assert framer.client is None #nosec
-    assert framer._buffer == b'' #nosec pylint: disable=protected-access
-    assert framer.decoder == decoder #nosec
+    assert framer.client is None  # nosec
+    assert framer._buffer == b''  # nosec pylint: disable=protected-access
+    assert framer.decoder == decoder  # nosec
     if isinstance(framer, ModbusAsciiFramer):
-        assert framer._header == {'lrc': '0000', 'len': 0, 'uid': 0x00} #nosec pylint: disable=protected-access
-        assert framer._hsize == 0x02 #nosec pylint: disable=protected-access
-        assert framer._start == b':' #nosec pylint: disable=protected-access
-        assert framer._end == b"\r\n" #nosec pylint: disable=protected-access
+        assert framer._header == {'lrc': '0000', 'len': 0, 'uid': 0x00}  # nosec pylint: disable=protected-access
+        assert framer._hsize == 0x02  # nosec pylint: disable=protected-access
+        assert framer._start == b':'  # nosec pylint: disable=protected-access
+        assert framer._end == b"\r\n"  # nosec pylint: disable=protected-access
     elif isinstance(framer, ModbusRtuFramer):
-        assert framer._header == {'uid': 0x00, 'len': 0, 'crc': b'\x00\x00'} #nosec pylint: disable=protected-access
-        assert framer._hsize == 0x01 #nosec pylint: disable=protected-access
-        assert framer._end == b'\x0d\x0a' #nosec pylint: disable=protected-access
-        assert framer._min_frame_size == 4 #nosec pylint: disable=protected-access
+        assert framer._header == {'uid': 0x00, 'len': 0, 'crc': b'\x00\x00'}  # nosec pylint: disable=protected-access
+        assert framer._hsize == 0x01  # nosec pylint: disable=protected-access
+        assert framer._end == b'\x0d\x0a'  # nosec pylint: disable=protected-access
+        assert framer._min_frame_size == 4  # nosec pylint: disable=protected-access
     else:
-        assert framer._header == {'crc': 0x0000, 'len': 0, 'uid': 0x00} #nosec pylint: disable=protected-access
-        assert framer._hsize == 0x01 #nosec pylint: disable=protected-access
-        assert framer._start == b'\x7b' #nosec pylint: disable=protected-access
-        assert framer._end == b'\x7d' #nosec pylint: disable=protected-access
-        assert framer._repeat == [b'}'[0], b'{'[0]] #nosec pylint: disable=protected-access
+        assert framer._header == {'crc': 0x0000, 'len': 0, 'uid': 0x00}  # nosec pylint: disable=protected-access
+        assert framer._hsize == 0x01  # nosec pylint: disable=protected-access
+        assert framer._start == b'\x7b'  # nosec pylint: disable=protected-access
+        assert framer._end == b'\x7d'  # nosec pylint: disable=protected-access
+        assert framer._repeat == [b'}'[0], b'{'[0]]  # nosec pylint: disable=protected-access
 
 
 @pytest.mark.parametrize("data", [(b'', {}),
                                   (b'abcd', {'fcode': 98, 'unit': 97})])
-def test_decode_data(rtu_framer, data): # pylint: disable=redefined-outer-name
-    """ Test decode data. """
+def test_decode_data(rtu_framer, data):  # pylint: disable=redefined-outer-name
+    """Test decode data."""
     data, expected = data
     decoded = rtu_framer.decode_data(data)
-    assert decoded == expected #nosec
+    assert decoded == expected  # nosec
 
 
 @pytest.mark.parametrize("data", [
@@ -73,11 +73,11 @@ def test_decode_data(rtu_framer, data): # pylint: disable=redefined-outer-name
     (b'\x11\x03\x06\xAE\x41\x56\x52\x43\x40\x49\xAD', True),  # valid frame
     (b'\x11\x03\x06\xAE\x41\x56\x52\x43\x40\x49\xAC', False),  # invalid frame CRC
 ])
-def test_check_frame(rtu_framer, data): # pylint: disable=redefined-outer-name
-    """ Test check frame. """
+def test_check_frame(rtu_framer, data):  # pylint: disable=redefined-outer-name
+    """Test check frame."""
     data, expected = data
-    rtu_framer._buffer = data # pylint: disable=protected-access
-    assert expected == rtu_framer.checkFrame() #nosec
+    rtu_framer._buffer = data  # pylint: disable=protected-access
+    assert expected == rtu_framer.checkFrame()  # nosec
 
 
 @pytest.mark.parametrize("data", [
@@ -86,24 +86,24 @@ def test_check_frame(rtu_framer, data): # pylint: disable=redefined-outer-name
     (b'\x11\x03\x06\xAE\x41\x56\x52\x43\x40\x49\xAD\x12\x03',  # real case, frame size is 11
      {'uid': 0x00, 'len': 11, 'crc': b'\x00\x00'}, b'\x12\x03'),
 ])
-def test_rtu_advance_framer(rtu_framer, data): # pylint: disable=redefined-outer-name
-    """ Test rtu advance framer. """
+def test_rtu_advance_framer(rtu_framer, data):  # pylint: disable=redefined-outer-name
+    """Test rtu advance framer."""
     before_buf, before_header, after_buf = data
 
-    rtu_framer._buffer = before_buf # pylint: disable=protected-access
-    rtu_framer._header = before_header # pylint: disable=protected-access
+    rtu_framer._buffer = before_buf  # pylint: disable=protected-access
+    rtu_framer._header = before_header  # pylint: disable=protected-access
     rtu_framer.advanceFrame()
-    assert rtu_framer._header == {'uid': 0x00, 'len': 0, 'crc': b'\x00\x00'} #nosec pylint: disable=protected-access
-    assert rtu_framer._buffer == after_buf #nosec pylint: disable=protected-access
+    assert rtu_framer._header == {'uid': 0x00, 'len': 0, 'crc': b'\x00\x00'}  # nosec pylint: disable=protected-access
+    assert rtu_framer._buffer == after_buf  # nosec pylint: disable=protected-access
 
 
 @pytest.mark.parametrize("data", [b'', b'abcd'])
-def test_rtu_reset_framer(rtu_framer, data): # pylint: disable=redefined-outer-name
-    """ Test rtu reset framer. """
-    rtu_framer._buffer = data # pylint: disable=protected-access
+def test_rtu_reset_framer(rtu_framer, data):  # pylint: disable=redefined-outer-name
+    """Test rtu reset framer."""
+    rtu_framer._buffer = data  # pylint: disable=protected-access
     rtu_framer.resetFrame()
-    assert rtu_framer._header == {'uid': 0x00, 'len': 0, 'crc': b'\x00\x00'} #nosec pylint: disable=protected-access
-    assert rtu_framer._buffer == b'' #nosec pylint: disable=protected-access
+    assert rtu_framer._header == {'uid': 0x00, 'len': 0, 'crc': b'\x00\x00'}  # nosec pylint: disable=protected-access
+    assert rtu_framer._buffer == b''  # nosec pylint: disable=protected-access
 
 
 @pytest.mark.parametrize("data", [
@@ -115,12 +115,12 @@ def test_rtu_reset_framer(rtu_framer, data): # pylint: disable=redefined-outer-n
     (b'\x11\x03\x06\xAE\x41\x56\x52\x43\x40\x49\xAD', True),
     (b'\x11\x03\x06\xAE\x41\x56\x52\x43\x40\x49\xAD\xAB\xCD', True),
 ])
-def test_is_frame_ready(rtu_framer, data): # pylint: disable=redefined-outer-name
-    """ Test is frame ready. """
+def test_is_frame_ready(rtu_framer, data):  # pylint: disable=redefined-outer-name
+    """Test is frame ready."""
     data, expected = data
-    rtu_framer._buffer = data # pylint: disable=protected-access
+    rtu_framer._buffer = data  # pylint: disable=protected-access
     # rtu_framer.advanceFrame()
-    assert rtu_framer.isFrameReady() == expected #nosec
+    assert rtu_framer.isFrameReady() == expected  # nosec
 
 
 @pytest.mark.parametrize("data", [
@@ -130,8 +130,8 @@ def test_is_frame_ready(rtu_framer, data): # pylint: disable=redefined-outer-nam
     b'\x11\x03\x06',
     b'\x11\x03\x06\xAE\x41\x56\x52\x43\x40\x43',
 ])
-def test_rtu_populate_header_fail(rtu_framer, data): # pylint: disable=redefined-outer-name
-    """ Test rtu populate header fail. """
+def test_rtu_populate_header_fail(rtu_framer, data):  # pylint: disable=redefined-outer-name
+    """Test rtu populate header fail."""
     with pytest.raises(IndexError):
         rtu_framer.populateHeader(data)
 
@@ -141,33 +141,33 @@ def test_rtu_populate_header_fail(rtu_framer, data): # pylint: disable=redefined
     (b'\x11\x03\x06\xAE\x41\x56\x52\x43\x40\x49\xAD\x11\x03', {
         'crc': b'\x49\xAD', 'uid': 17, 'len': 11})
 ])
-def test_rtu_populate_header(rtu_framer, data): # pylint: disable=redefined-outer-name
-    """ Test rtu populate header. """
+def test_rtu_populate_header(rtu_framer, data):  # pylint: disable=redefined-outer-name
+    """Test rtu populate header."""
     buffer, expected = data
     rtu_framer.populateHeader(buffer)
-    assert rtu_framer._header == expected #nosec pylint: disable=protected-access
+    assert rtu_framer._header == expected  # nosec pylint: disable=protected-access
 
 
-def test_add_to_frame(rtu_framer): # pylint: disable=redefined-outer-name
-    """ Test add to frame. """
-    assert rtu_framer._buffer == b'' #nosec pylint: disable=protected-access
+def test_add_to_frame(rtu_framer):  # pylint: disable=redefined-outer-name
+    """Test add to frame."""
+    assert rtu_framer._buffer == b''  # nosec pylint: disable=protected-access
     rtu_framer.addToFrame(b'abcd')
-    assert rtu_framer._buffer == b'abcd' #nosec pylint: disable=protected-access
+    assert rtu_framer._buffer == b'abcd'  # nosec pylint: disable=protected-access
 
 
-def test_get_frame(rtu_framer): # pylint: disable=redefined-outer-name
-    """ Test get frame. """
+def test_get_frame(rtu_framer):  # pylint: disable=redefined-outer-name
+    """Test get frame."""
     rtu_framer.addToFrame(b'\x02\x01\x01\x00Q\xcc')
     rtu_framer.populateHeader(b'\x02\x01\x01\x00Q\xcc')
-    assert rtu_framer.getFrame() == b'\x01\x01\x00' #nosec
+    assert rtu_framer.getFrame() == b'\x01\x01\x00'  # nosec
 
 
-def test_populate_result(rtu_framer): # pylint: disable=redefined-outer-name
-    """ Test populate result. """
-    rtu_framer._header['uid'] = 255 # pylint: disable=protected-access
+def test_populate_result(rtu_framer):  # pylint: disable=redefined-outer-name
+    """Test populate result."""
+    rtu_framer._header['uid'] = 255  # pylint: disable=protected-access
     result = Mock()
     rtu_framer.populateResult(result)
-    assert result.unit_id == 255 #nosec
+    assert result.unit_id == 255  # nosec
 
 
 @pytest.mark.parametrize("data", [
@@ -181,27 +181,27 @@ def test_populate_result(rtu_framer): # pylint: disable=redefined-outer-name
     (b'\x11\x03\x06\xAE\x41\x56\x52\x43\x40\x49\xAD', 17, False, True),  # good frame
     (b'\x11\x03\x06\xAE\x41\x56\x52\x43\x40\x49\xAD', 16, True, False),  # incorrect unit id
     (b'\x11\x03\x06\xAE\x41\x56\x52\x43\x40\x49\xAD\x11\x03', 17, False, True),
-        # good frame + part of next frame
+    # good frame + part of next frame
 ])
-def test_rtu_incoming_packet(rtu_framer, data): # pylint: disable=redefined-outer-name
-    """ Test rtu process incoming packet. """
+def test_rtu_incoming_packet(rtu_framer, data):  # pylint: disable=redefined-outer-name
+    """Test rtu process incoming packet."""
     buffer, units, reset_called, process_called = data
 
     with patch.object(rtu_framer, '_process') as mock_process, \
             patch.object(rtu_framer, 'resetFrame') as mock_reset:
         rtu_framer.processIncomingPacket(buffer, Mock(), units)
-        assert mock_process.call_count == (1 if process_called else 0) #nosec
-        assert mock_reset.call_count == (1 if reset_called else 0) #nosec
+        assert mock_process.call_count == (1 if process_called else 0)  # nosec
+        assert mock_reset.call_count == (1 if reset_called else 0)  # nosec
 
 
-def test_build_packet(rtu_framer): # pylint: disable=redefined-outer-name
-    """ Test build packet. """
+def test_build_packet(rtu_framer):  # pylint: disable=redefined-outer-name
+    """Test build packet."""
     message = ReadCoilsRequest(1, 10)
-    assert rtu_framer.buildPacket(message) == b'\x00\x01\x00\x01\x00\n\xec\x1c' #nosec
+    assert rtu_framer.buildPacket(message) == b'\x00\x01\x00\x01\x00\n\xec\x1c'  # nosec
 
 
-def test_send_packet(rtu_framer): # pylint: disable=redefined-outer-name
-    """ Test send packet. """
+def test_send_packet(rtu_framer):  # pylint: disable=redefined-outer-name
+    """Test send packet."""
     message = b'\x00\x01\x00\x01\x00\n\xec\x1c'
     client = Mock()
     client.state = ModbusTransactionState.TRANSACTION_COMPLETE
@@ -211,51 +211,51 @@ def test_send_packet(rtu_framer): # pylint: disable=redefined-outer-name
     client.idle_time.return_value = 1
     client.send.return_value = len(message)
     rtu_framer.client = client
-    assert rtu_framer.sendPacket(message) == len(message) #nosec
+    assert rtu_framer.sendPacket(message) == len(message)  # nosec
     client.state = ModbusTransactionState.PROCESSING_REPLY
-    assert rtu_framer.sendPacket(message) == len(message) #nosec
+    assert rtu_framer.sendPacket(message) == len(message)  # nosec
 
 
-def test_recv_packet(rtu_framer): # pylint: disable=redefined-outer-name
-    """ Test receive packet. """
+def test_recv_packet(rtu_framer):  # pylint: disable=redefined-outer-name
+    """Test receive packet."""
     message = b'\x00\x01\x00\x01\x00\n\xec\x1c'
     client = Mock()
     client.recv.return_value = message
     rtu_framer.client = client
-    assert rtu_framer.recvPacket(len(message)) == message #nosec
+    assert rtu_framer.recvPacket(len(message)) == message  # nosec
 
 
-def test_process(rtu_framer): # pylint: disable=redefined-outer-name
-    """ Test process. """
+def test_process(rtu_framer):  # pylint: disable=redefined-outer-name
+    """Test process."""
     def callback(res):
         return res
 
-    rtu_framer._buffer = b'\x00\x01\x00\x01\x00\n\xec\x1c' # pylint: disable=protected-access
+    rtu_framer._buffer = b'\x00\x01\x00\x01\x00\n\xec\x1c'  # pylint: disable=protected-access
     with pytest.raises(ModbusIOException):
-        rtu_framer._process(callback) # pylint: disable=protected-access
+        rtu_framer._process(callback)  # pylint: disable=protected-access
 
 
-def test_get_raw_frame(rtu_framer): # pylint: disable=redefined-outer-name
-    """ Test get raw frame. """
-    rtu_framer._buffer = b'\x00\x01\x00\x01\x00\n\xec\x1c' # pylint: disable=protected-access
-    assert rtu_framer.getRawFrame() == rtu_framer._buffer #nosec pylint: disable=protected-access
+def test_get_raw_frame(rtu_framer):  # pylint: disable=redefined-outer-name
+    """Test get raw frame."""
+    rtu_framer._buffer = b'\x00\x01\x00\x01\x00\n\xec\x1c'  # pylint: disable=protected-access
+    assert rtu_framer.getRawFrame() == rtu_framer._buffer  # nosec pylint: disable=protected-access
 
 
-def test_validate_unit_id(rtu_framer): # pylint: disable=redefined-outer-name
-    """ Test validate unit. """
-    rtu_framer.populateHeader( b'\x00\x01\x00\x01\x00\n\xec\x1c')
-    assert rtu_framer._validate_unit_id([0], False) #nosec pylint: disable=protected-access
-    assert rtu_framer._validate_unit_id([1], True) #nosec pylint: disable=protected-access
+def test_validate_unit_id(rtu_framer):  # pylint: disable=redefined-outer-name
+    """Test validate unit."""
+    rtu_framer.populateHeader(b'\x00\x01\x00\x01\x00\n\xec\x1c')
+    assert rtu_framer._validate_unit_id([0], False)  # nosec pylint: disable=protected-access
+    assert rtu_framer._validate_unit_id([1], True)  # nosec pylint: disable=protected-access
 
 
 @pytest.mark.parametrize('data', [b':010100010001FC\r\n',
                          b''])
-def test_decode_ascii_data(ascii_framer, data): # pylint: disable=redefined-outer-name
-    """ Test decode ascii. """
+def test_decode_ascii_data(ascii_framer, data):  # pylint: disable=redefined-outer-name
+    """Test decode ascii."""
     data = ascii_framer.decode_data(data)
-    assert isinstance(data, dict) #nosec
+    assert isinstance(data, dict)  # nosec
     if data:
-        assert data.get("unit") == 1 #nosec
-        assert data.get("fcode") == 1 #nosec
+        assert data.get("unit") == 1  # nosec
+        assert data.get("fcode") == 1  # nosec
     else:
-        assert not data #nosec
+        assert not data  # nosec
diff --git a/test/test_interfaces.py b/test/test_interfaces.py
index 0e5bd8691..f20d9c140 100644
--- a/test/test_interfaces.py
+++ b/test/test_interfaces.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test interfaces. """
+"""Test interfaces."""
 import unittest
 
 from pymodbus.interfaces import (
@@ -11,26 +11,28 @@
 )
 from pymodbus.exceptions import NotImplementedException
 
-class _SingleInstance(Singleton): # pylint: disable=too-few-public-methods
-    """ Single instance. """
+
+class _SingleInstance(Singleton):  # pylint: disable=too-few-public-methods
+    """Single instance."""
+
 
 class ModbusInterfaceTestsTest(unittest.TestCase):
-    """ Unittest for the pymodbus.interfaces module. """
+    """Unittest for the pymodbus.interfaces module."""
 
     def setUp(self):
-        """ Initializes the test environment """
+        """Initialize the test environment"""
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
 
     def test_singleton_interface(self):
-        """ Test that the singleton interface works """
-        first  = _SingleInstance()
+        """Test that the singleton interface works"""
+        first = _SingleInstance()
         second = _SingleInstance()
         self.assertEqual(first, second)
 
     def test_modbus_decoder_interface(self):
-        """ Test that the base class isn't implemented """
+        """Test that the base class isn't implemented"""
         x_base = None
         instance = IModbusDecoder()
         self.assertRaises(NotImplementedException, lambda: instance.decode(x_base))
@@ -40,7 +42,7 @@ def test_modbus_decoder_interface(self):
                           lambda: instance.register(x_base))
 
     def test_modbus_framer_interface(self):
-        """ Test that the base class isn't implemented """
+        """Test that the base class isn't implemented"""
         x_base = None
         instance = IModbusFramer()
         self.assertRaises(NotImplementedException, instance.checkFrame)
@@ -48,30 +50,31 @@ def test_modbus_framer_interface(self):
         self.assertRaises(NotImplementedException, instance.isFrameReady)
         self.assertRaises(NotImplementedException, instance.getFrame)
         self.assertRaises(NotImplementedException, lambda:
-                instance.addToFrame(x_base))
+                          instance.addToFrame(x_base))
         self.assertRaises(NotImplementedException, lambda:
-                instance.populateResult(x_base))
+                          instance.populateResult(x_base))
         self.assertRaises(NotImplementedException, lambda:
-                instance.processIncomingPacket(x_base,x_base))
+                          instance.processIncomingPacket(x_base, x_base))
         self.assertRaises(NotImplementedException, lambda:
-                instance.buildPacket(x_base))
+                          instance.buildPacket(x_base))
 
     def test_modbus_slave_context_interface(self):
-        """ Test that the base class isn't implemented """
+        """Test that the base class isn't implemented"""
         x_base = None
         instance = IModbusSlaveContext()
         self.assertRaises(NotImplementedException, instance.reset)
-        self.assertRaises(NotImplementedException, lambda: instance.validate(x_base,x_base,x_base))
-        self.assertRaises(NotImplementedException, lambda: instance.getValues(x_base,x_base,x_base))
-        self.assertRaises(NotImplementedException, lambda: instance.setValues(x_base,x_base,x_base))
+        self.assertRaises(NotImplementedException, lambda: instance.validate(x_base, x_base, x_base))
+        self.assertRaises(NotImplementedException, lambda: instance.getValues(x_base, x_base, x_base))
+        self.assertRaises(NotImplementedException, lambda: instance.setValues(x_base, x_base, x_base))
 
     def test_modbus_payload_builder_interface(self):
-        """ Test that the base class isn't implemented """
+        """Test that the base class isn't implemented"""
         instance = IPayloadBuilder()
-        self.assertRaises(NotImplementedException, lambda: instance.build()) # pylint: disable=unnecessary-lambda
+        self.assertRaises(NotImplementedException, lambda: instance.build())  # pylint: disable=unnecessary-lambda
+
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_mei_messages.py b/test/test_mei_messages.py
index 7fc5b660b..cdf537cb5 100644
--- a/test/test_mei_messages.py
+++ b/test/test_mei_messages.py
@@ -1,5 +1,4 @@
-""" MEI Message Test Fixture
---------------------------------
+"""MEI Message Test Fixture.
 
 This fixture tests the functionality of all the
 mei based request/response messages:
@@ -12,42 +11,44 @@
 from pymodbus.constants import DeviceInformation
 from pymodbus.device import ModbusControlBlock
 
-#---------------------------------------------------------------------------#
-# Fixture
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Fixture
+# ---------------------------------------------------------------------------#
+
+
 class ModbusMeiMessageTest(unittest.TestCase):
-    """ Unittest for the pymodbus.mei_message module. """
+    """Unittest for the pymodbus.mei_message module."""
 
-    #-----------------------------------------------------------------------#
-    # Read Device Information
-    #-----------------------------------------------------------------------#
+    # -----------------------------------------------------------------------#
+    #  Read Device Information
+    # -----------------------------------------------------------------------#
 
     def test_read_device_information_request_encode(self):
-        """ Test basic bit message encoding/decoding """
-        params  = {'read_code':DeviceInformation.Basic, 'object_id':0x00 }
-        handle  = ReadDeviceInformationRequest(**params)
-        result  = handle.encode()
+        """Test basic bit message encoding/decoding"""
+        params = {'read_code': DeviceInformation.Basic, 'object_id': 0x00}
+        handle = ReadDeviceInformationRequest(**params)
+        result = handle.encode()
         self.assertEqual(result, b'\x0e\x01\x00')
         self.assertEqual("ReadDeviceInformationRequest(1,0)", str(handle))
 
     def test_read_device_information_request_decode(self):
-        """ Test basic bit message encoding/decoding """
-        handle  = ReadDeviceInformationRequest()
+        """Test basic bit message encoding/decoding"""
+        handle = ReadDeviceInformationRequest()
         handle.decode(b'\x0e\x01\x00')
         self.assertEqual(handle.read_code, DeviceInformation.Basic)
         self.assertEqual(handle.object_id, 0x00)
 
     def test_read_device_information_request(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         context = None
         control = ModbusControlBlock()
-        control.Identity.VendorName  = "Company"
+        control.Identity.VendorName = "Company"
         control.Identity.ProductCode = "Product"
         control.Identity.MajorMinorRevision = "v2.1.12"
         control.Identity.update({0x81: ['Test', 'Repeated']})
 
-        handle  = ReadDeviceInformationRequest()
-        result  = handle.execute(context)
+        handle = ReadDeviceInformationRequest()
+        result = handle.execute(context)
         self.assertTrue(isinstance(result, ReadDeviceInformationResponse))
         self.assertEqual(result.information[0x00], "Company")
         self.assertEqual(result.information[0x01], "Product")
@@ -61,8 +62,8 @@ def test_read_device_information_request(self):
         self.assertEqual(result.information[0x81], ['Test', 'Repeated'])
 
     def test_read_device_information_request_error(self):
-        """ Test basic bit message encoding/decoding """
-        handle  = ReadDeviceInformationRequest()
+        """Test basic bit message encoding/decoding"""
+        handle = ReadDeviceInformationRequest()
         handle.read_code = -1
         self.assertEqual(handle.execute(None).function_code, 0xab)
         handle.read_code = 0x05
@@ -73,17 +74,17 @@ def test_read_device_information_request_error(self):
         self.assertEqual(handle.execute(None).function_code, 0xab)
 
     def test_read_device_information_encode(self):
-        """ Test that the read fifo queue response can encode """
-        message  = b'\x0e\x01\x83\x00\x00\x03'
+        """Test that the read fifo queue response can encode"""
+        message = b'\x0e\x01\x83\x00\x00\x03'
         message += b'\x00\x07Company\x01\x07Product\x02\x07v2.1.12'
-        dataset  = {
+        dataset = {
             0x00: 'Company',
             0x01: 'Product',
             0x02: 'v2.1.12',
         }
-        handle  = ReadDeviceInformationResponse(
+        handle = ReadDeviceInformationResponse(
             read_code=DeviceInformation.Basic, information=dataset)
-        result  = handle.encode()
+        result = handle.encode()
         self.assertEqual(result, message)
         self.assertEqual("ReadDeviceInformationResponse(1)", str(handle))
 
@@ -102,33 +103,33 @@ def test_read_device_information_encode(self):
         self.assertEqual(result, message)
 
     def test_read_device_information_encode_long(self):
-        """ Test that the read fifo queue response can encode """
+        """Test that the read fifo queue response can encode"""
         longstring = "Lorem ipsum dolor sit amet, consectetur adipiscing " \
                      "elit. Vivamus rhoncus massa turpis, sit amet ultrices" \
                      " orci semper ut. Aliquam tristique sapien in lacus " \
                      "pharetra, in convallis nunc consectetur. Nunc velit " \
                      "elit, vehicula tempus tempus sed. "
 
-        message  = b'\x0e\x01\x83\xFF\x80\x03'
+        message = b'\x0e\x01\x83\xFF\x80\x03'
         message += b'\x00\x07Company\x01\x07Product\x02\x07v2.1.12'
-        dataset  = {
+        dataset = {
             0x00: 'Company',
             0x01: 'Product',
             0x02: 'v2.1.12',
             0x80: longstring
         }
-        handle  = ReadDeviceInformationResponse(
+        handle = ReadDeviceInformationResponse(
             read_code=DeviceInformation.Basic, information=dataset)
-        result  = handle.encode()
+        result = handle.encode()
         self.assertEqual(result, message)
         self.assertEqual("ReadDeviceInformationResponse(1)", str(handle))
 
     def test_read_device_information_decode(self):
-        """ Test that the read device information response can decode """
-        message  = b'\x0e\x01\x01\x00\x00\x05'
+        """Test that the read device information response can decode"""
+        message = b'\x0e\x01\x01\x00\x00\x05'
         message += b'\x00\x07Company\x01\x07Product\x02\x07v2.1.12'
         message += b'\x81\x04Test\x81\x08Repeated\x81\x07Another'
-        handle  = ReadDeviceInformationResponse(read_code=0x00, information=[])
+        handle = ReadDeviceInformationResponse(read_code=0x00, information=[])
         handle.decode(message)
         self.assertEqual(handle.read_code, DeviceInformation.Basic)
         self.assertEqual(handle.conformity, 0x01)
@@ -138,17 +139,17 @@ def test_read_device_information_decode(self):
         self.assertEqual(handle.information[0x81], [b'Test', b'Repeated', b'Another'])
 
     def test_rtu_frame_size(self):
-        """ Test that the read device information response can decode """
+        """Test that the read device information response can decode"""
         message = b'\x04\x2B\x0E\x01\x81\x00\x01\x01\x00\x06\x66\x6F\x6F\x62\x61\x72\xD7\x3B'
-        result  = ReadDeviceInformationResponse.calculateRtuFrameSize(message)
+        result = ReadDeviceInformationResponse.calculateRtuFrameSize(message)
         self.assertEqual(result, 18)
         message = b'\x00\x2B\x0E\x02\x00\x4D\x47'
         result = ReadDeviceInformationRequest.calculateRtuFrameSize(message)
         self.assertEqual(result, 7)
 
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_other_messages.py b/test/test_other_messages.py
index de8e33d29..09ce4cebc 100644
--- a/test/test_other_messages.py
+++ b/test/test_other_messages.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test other messages. """
+"""Test other messages."""
 import unittest
 import mock
 
@@ -7,9 +7,10 @@
 
 
 class ModbusOtherMessageTest(unittest.TestCase):
-    """ Unittest for the pymodbus.other_message module. """
+    """Unittest for the pymodbus.other_message module."""
 
     def setUp(self):
+        """Do setup."""
         self.requests = [
             pymodbus_message.ReadExceptionStatusRequest,
             pymodbus_message.GetCommEventCounterRequest,
@@ -20,24 +21,24 @@ def setUp(self):
         self.responses = [
             lambda: pymodbus_message.ReadExceptionStatusResponse(0x12),
             lambda: pymodbus_message.GetCommEventCounterResponse(0x12),
-                pymodbus_message.GetCommEventLogResponse,
+            pymodbus_message.GetCommEventLogResponse,
             lambda: pymodbus_message.ReportSlaveIdResponse(0x12),
         ]
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment."""
         del self.requests
         del self.responses
 
     def test_other_messages_to_string(self):
-        """ Test other messages to string. """
+        """Test other messages to string."""
         for message in self.requests:
             self.assertNotEqual(str(message()), None)
         for message in self.responses:
             self.assertNotEqual(str(message()), None)
 
     def test_read_exception_status(self):
-        """ Test read exception status. """
+        """Test read exception status."""
         request = pymodbus_message.ReadExceptionStatusRequest()
         request.decode(b'\x12')
         self.assertEqual(request.encode(), b'')
@@ -49,7 +50,7 @@ def test_read_exception_status(self):
         self.assertEqual(response.status, 0x12)
 
     def test_get_comm_event_counter(self):
-        """ Test get comm event counter. """
+        """Test get comm event counter."""
         request = pymodbus_message.GetCommEventCounterRequest()
         request.decode(b'\x12')
         self.assertEqual(request.encode(), b'')
@@ -65,7 +66,7 @@ def test_get_comm_event_counter(self):
         self.assertEqual(response.encode(), b'\xFF\xFF\x00\x12')
 
     def test_get_comm_event_log(self):
-        """ Test get comm event log. """
+        """Test get comm event log."""
         request = pymodbus_message.GetCommEventLogRequest()
         request.decode(b'\x12')
         self.assertEqual(request.encode(), b'')
@@ -83,17 +84,17 @@ def test_get_comm_event_log(self):
         self.assertEqual(response.encode(), b'\x06\xff\xff\x00\x12\x00\x12')
 
     def test_get_comm_event_log_with_events(self):
-        """ Test get comm event log with events. """
-        response = pymodbus_message.GetCommEventLogResponse(events=[0x12,0x34,0x56])
+        """Test get comm event log with events."""
+        response = pymodbus_message.GetCommEventLogResponse(events=[0x12, 0x34, 0x56])
         self.assertEqual(response.encode(), b'\x09\x00\x00\x00\x00\x00\x00\x12\x34\x56')
         response.decode(b'\x09\x00\x00\x00\x12\x00\x12\x12\x34\x56')
         self.assertEqual(response.status, True)
         self.assertEqual(response.message_count, 0x12)
         self.assertEqual(response.event_count, 0x12)
-        self.assertEqual(response.events, [0x12,0x34,0x56])
+        self.assertEqual(response.events, [0x12, 0x34, 0x56])
 
     def test_report_slave_id_request(self):
-        """ Test report slave id request. """
+        """Test report slave id request."""
         with mock.patch("pymodbus.other_message.DeviceInformationFactory") as dif:
             # First test regular identity strings
             identity = {
@@ -133,7 +134,7 @@ def test_report_slave_id_request(self):
             self.assertEqual(response.identifier, expected_identity)
 
     def test_report_slave_id(self):
-        """ Test report slave id. """
+        """Test report slave id."""
         with mock.patch("pymodbus.other_message.DeviceInformationFactory") as dif:
             dif.get.return_value = {}
             request = pymodbus_message.ReportSlaveIdRequest()
@@ -151,8 +152,9 @@ def test_report_slave_id(self):
             response.status = False
             self.assertEqual(response.encode(), b'\x03\x12\x00\x00')
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_payload.py b/test/test_payload.py
index 9e02bc1d2..7b3d23b77 100644
--- a/test/test_payload.py
+++ b/test/test_payload.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
-""" Payload Utilities Test Fixture
---------------------------------
+"""Payload Utilities Test Fixture.
+
 This fixture tests the functionality of the payload
 utilities.
 
@@ -12,45 +12,45 @@
 from pymodbus.constants import Endian
 from pymodbus.payload import BinaryPayloadBuilder, BinaryPayloadDecoder
 
-#---------------------------------------------------------------------------#
-# Fixture
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Fixture
+# ---------------------------------------------------------------------------#
+
+
 class ModbusPayloadUtilityTests(unittest.TestCase):
-    """ Modbus payload utility tests. """
+    """Modbus payload utility tests."""
 
     # ----------------------------------------------------------------------- #
     # Setup/TearDown
     # ----------------------------------------------------------------------- #
 
     def setUp(self):
-        """ Initializes the test environment and builds request/result
-        encoding pairs
-        """
+        """Initialize the test environment and builds request/result encoding pairs."""
         self.little_endian_payload = \
-                       b'\x01\x02\x00\x03\x00\x00\x00\x04\x00\x00\x00\x00' \
-                       b'\x00\x00\x00\xff\xfe\xff\xfd\xff\xff\xff\xfc\xff' \
-                       b'\xff\xff\xff\xff\xff\xff\x00\x00\xa0\x3f\x00\x00' \
-                       b'\x00\x00\x00\x00\x19\x40\x01\x00\x74\x65\x73\x74' \
-                       b'\x11'
+            b'\x01\x02\x00\x03\x00\x00\x00\x04\x00\x00\x00\x00' \
+            b'\x00\x00\x00\xff\xfe\xff\xfd\xff\xff\xff\xfc\xff' \
+            b'\xff\xff\xff\xff\xff\xff\x00\x00\xa0\x3f\x00\x00' \
+            b'\x00\x00\x00\x00\x19\x40\x01\x00\x74\x65\x73\x74' \
+            b'\x11'
 
         self.big_endian_payload = \
-                       b'\x01\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00' \
-                       b'\x00\x00\x04\xff\xff\xfe\xff\xff\xff\xfd\xff\xff' \
-                       b'\xff\xff\xff\xff\xff\xfc\x3f\xa0\x00\x00\x40\x19' \
-                       b'\x00\x00\x00\x00\x00\x00\x00\x01\x74\x65\x73\x74' \
-                       b'\x11'
+            b'\x01\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00' \
+            b'\x00\x00\x04\xff\xff\xfe\xff\xff\xff\xfd\xff\xff' \
+            b'\xff\xff\xff\xff\xff\xfc\x3f\xa0\x00\x00\x40\x19' \
+            b'\x00\x00\x00\x00\x00\x00\x00\x01\x74\x65\x73\x74' \
+            b'\x11'
 
         self.bitstring = [True, False, False, False, True, False, False, False]
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
 
     # ----------------------------------------------------------------------- #
     # Payload Builder Tests
     # ----------------------------------------------------------------------- #
 
     def test_little_endian_payload_builder(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         builder = BinaryPayloadBuilder(byteorder=Endian.Little,
                                        wordorder=Endian.Little)
         builder.add_8bit_uint(1)
@@ -69,7 +69,7 @@ def test_little_endian_payload_builder(self):
         self.assertEqual(self.little_endian_payload, builder.to_string())
 
     def test_big_endian_payload_builder(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         builder = BinaryPayloadBuilder(byteorder=Endian.Big)
         builder.add_8bit_uint(1)
         builder.add_16bit_uint(2)
@@ -87,7 +87,7 @@ def test_big_endian_payload_builder(self):
         self.assertEqual(self.big_endian_payload, builder.to_string())
 
     def test_payload_builder_reset(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         builder = BinaryPayloadBuilder()
         builder.add_8bit_uint(0x12)
         builder.add_8bit_uint(0x34)
@@ -100,7 +100,7 @@ def test_payload_builder_reset(self):
         self.assertEqual([], builder.build())
 
     def test_payload_builder_with_raw_payload(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         _coils1 = [False, False, True, True, False, True, False, False, False,
                    False, False, True, False, False, True, False, False, True,
                    True, True, True, False, False, False, False, True, False,
@@ -130,44 +130,44 @@ def test_payload_builder_with_raw_payload(self):
     # ----------------------------------------------------------------------- #
 
     def test_little_endian_payload_decoder(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         decoder = BinaryPayloadDecoder(self.little_endian_payload,
                                        byteorder=Endian.Little,
                                        wordorder=Endian.Little)
-        self.assertEqual(1,      decoder.decode_8bit_uint())
-        self.assertEqual(2,      decoder.decode_16bit_uint())
-        self.assertEqual(3,      decoder.decode_32bit_uint())
-        self.assertEqual(4,      decoder.decode_64bit_uint())
-        self.assertEqual(-1,     decoder.decode_8bit_int())
-        self.assertEqual(-2,     decoder.decode_16bit_int())
-        self.assertEqual(-3,     decoder.decode_32bit_int())
-        self.assertEqual(-4,     decoder.decode_64bit_int())
-        self.assertEqual(1.25,   decoder.decode_32bit_float())
-        self.assertEqual(6.25,   decoder.decode_64bit_float())
-        self.assertEqual(None,   decoder.skip_bytes(2))
+        self.assertEqual(1, decoder.decode_8bit_uint())
+        self.assertEqual(2, decoder.decode_16bit_uint())
+        self.assertEqual(3, decoder.decode_32bit_uint())
+        self.assertEqual(4, decoder.decode_64bit_uint())
+        self.assertEqual(-1, decoder.decode_8bit_int())
+        self.assertEqual(-2, decoder.decode_16bit_int())
+        self.assertEqual(-3, decoder.decode_32bit_int())
+        self.assertEqual(-4, decoder.decode_64bit_int())
+        self.assertEqual(1.25, decoder.decode_32bit_float())
+        self.assertEqual(6.25, decoder.decode_64bit_float())
+        self.assertEqual(None, decoder.skip_bytes(2))
         self.assertEqual('test', decoder.decode_string(4).decode())
         self.assertEqual(self.bitstring, decoder.decode_bits())
 
     def test_big_endian_payload_decoder(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         decoder = BinaryPayloadDecoder(self.big_endian_payload,
                                        byteorder=Endian.Big)
-        self.assertEqual(1,      decoder.decode_8bit_uint())
-        self.assertEqual(2,      decoder.decode_16bit_uint())
-        self.assertEqual(3,      decoder.decode_32bit_uint())
-        self.assertEqual(4,      decoder.decode_64bit_uint())
-        self.assertEqual(-1,     decoder.decode_8bit_int())
-        self.assertEqual(-2,     decoder.decode_16bit_int())
-        self.assertEqual(-3,     decoder.decode_32bit_int())
-        self.assertEqual(-4,     decoder.decode_64bit_int())
-        self.assertEqual(1.25,   decoder.decode_32bit_float())
-        self.assertEqual(6.25,   decoder.decode_64bit_float())
-        self.assertEqual(None,   decoder.skip_bytes(2))
+        self.assertEqual(1, decoder.decode_8bit_uint())
+        self.assertEqual(2, decoder.decode_16bit_uint())
+        self.assertEqual(3, decoder.decode_32bit_uint())
+        self.assertEqual(4, decoder.decode_64bit_uint())
+        self.assertEqual(-1, decoder.decode_8bit_int())
+        self.assertEqual(-2, decoder.decode_16bit_int())
+        self.assertEqual(-3, decoder.decode_32bit_int())
+        self.assertEqual(-4, decoder.decode_64bit_int())
+        self.assertEqual(1.25, decoder.decode_32bit_float())
+        self.assertEqual(6.25, decoder.decode_64bit_float())
+        self.assertEqual(None, decoder.skip_bytes(2))
         self.assertEqual(b'test', decoder.decode_string(4))
         self.assertEqual(self.bitstring, decoder.decode_bits())
 
     def test_payload_decoder_reset(self):
-        """ Test the payload decoder reset functionality """
+        """Test the payload decoder reset functionality"""
         decoder = BinaryPayloadDecoder(b'\x12\x34')
         self.assertEqual(0x12, decoder.decode_8bit_uint())
         self.assertEqual(0x34, decoder.decode_8bit_uint())
@@ -175,7 +175,7 @@ def test_payload_decoder_reset(self):
         self.assertEqual(0x3412, decoder.decode_16bit_uint())
 
     def test_payload_decoder_register_factory(self):
-        """ Test the payload decoder reset functionality """
+        """Test the payload decoder reset functionality"""
         payload = [1, 2, 3, 4]
         decoder = BinaryPayloadDecoder.fromRegisters(payload, byteorder=Endian.Little)
         encoded = b'\x00\x01\x00\x02\x00\x03\x00\x04'
@@ -186,10 +186,10 @@ def test_payload_decoder_register_factory(self):
         self.assertEqual(encoded, decoder.decode_string(8))
 
         self.assertRaises(ParameterException,
-            lambda: BinaryPayloadDecoder.fromRegisters('abcd'))
+                          lambda: BinaryPayloadDecoder.fromRegisters('abcd'))
 
     def test_payload_decoder_coil_factory(self):
-        """ Test the payload decoder reset functionality """
+        """Test the payload decoder reset functionality"""
         payload = [1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1]
         decoder = BinaryPayloadDecoder.fromCoils(payload, byteorder=Endian.Little)
         encoded = b'\x88\x11'
@@ -200,11 +200,11 @@ def test_payload_decoder_coil_factory(self):
         self.assertEqual(encoded, decoder.decode_string(2))
 
         self.assertRaises(ParameterException,
-            lambda: BinaryPayloadDecoder.fromCoils('abcd'))
+                          lambda: BinaryPayloadDecoder.fromCoils('abcd'))
 
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_pdu.py b/test/test_pdu.py
index 36a551428..039415502 100644
--- a/test/test_pdu.py
+++ b/test/test_pdu.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test pdu. """
+"""Test pdu."""
 import unittest
 from pymodbus.pdu import (
     ModbusResponse,
@@ -12,26 +12,27 @@
     NotImplementedException,
 )
 
+
 class SimplePduTest(unittest.TestCase):
-    """ Unittest for the pymod.pdu module. """
+    """Unittest for the pymod.pdu module."""
 
     def setUp(self):
-        """ Initializes the test environment """
+        """Initialize the test environment"""
         self.bad_requests = (
-                ModbusRequest(),
-                ModbusResponse(),
+            ModbusRequest(),
+            ModbusResponse(),
         )
         self.illegal = IllegalFunctionRequest(1)
-        self.exception = ExceptionResponse(1,1)
+        self.exception = ExceptionResponse(1, 1)
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
         del self.bad_requests
         del self.illegal
         del self.exception
 
     def test_not_impelmented(self):
-        """ Test a base classes for not implemented functions """
+        """Test a base classes for not implemented functions"""
         for request in self.bad_requests:
             self.assertRaises(NotImplementedException, request.encode)
 
@@ -39,7 +40,7 @@ def test_not_impelmented(self):
             self.assertRaises(NotImplementedException, request.decode, None)
 
     def test_error_methods(self):
-        """ Test all error methods """
+        """Test all error methods"""
         self.illegal.decode("12345")
         self.illegal.execute(None)
 
@@ -49,40 +50,40 @@ def test_error_methods(self):
         self.assertEqual(self.exception.exception_code, 1)
 
     def test_request_exception_factory(self):
-        """ Test all error methods """
+        """Test all error methods"""
         request = ModbusRequest()
         request.function_code = 1
-        errors = dict((ModbusExceptions.decode(c), c) for c in range(1,20))
+        errors = dict((ModbusExceptions.decode(c), c) for c in range(1, 20))
         for error, code in iter(errors.items()):
             result = request.doException(code)
             self.assertEqual(str(result), f"Exception Response(129, 1, {error})")
 
     def test_calculate_rtu_frame_size(self):
-        """ Test the calculation of Modbus/RTU frame sizes """
+        """Test the calculation of Modbus/RTU frame sizes"""
         self.assertRaises(NotImplementedException,
                           ModbusRequest.calculateRtuFrameSize, b'')
-        ModbusRequest._rtu_frame_size = 5 # pylint: disable=protected-access
+        ModbusRequest._rtu_frame_size = 5  # pylint: disable=protected-access
         self.assertEqual(ModbusRequest.calculateRtuFrameSize(b''), 5)
         del ModbusRequest._rtu_frame_size
 
-        ModbusRequest._rtu_byte_count_pos = 2 # pylint: disable=protected-access
+        ModbusRequest._rtu_byte_count_pos = 2  # pylint: disable=protected-access
         self.assertEqual(ModbusRequest.calculateRtuFrameSize(
             b'\x11\x01\x05\xcd\x6b\xb2\x0e\x1b\x45\xe6'), 0x05 + 5)
         del ModbusRequest._rtu_byte_count_pos
 
         self.assertRaises(NotImplementedException,
                           ModbusResponse.calculateRtuFrameSize, b'')
-        ModbusResponse._rtu_frame_size = 12 # pylint: disable=protected-access
+        ModbusResponse._rtu_frame_size = 12  # pylint: disable=protected-access
         self.assertEqual(ModbusResponse.calculateRtuFrameSize(b''), 12)
         del ModbusResponse._rtu_frame_size
-        ModbusResponse._rtu_byte_count_pos = 2 # pylint: disable=protected-access
+        ModbusResponse._rtu_byte_count_pos = 2  # pylint: disable=protected-access
         self.assertEqual(ModbusResponse.calculateRtuFrameSize(
             b'\x11\x01\x05\xcd\x6b\xb2\x0e\x1b\x45\xe6'), 0x05 + 5)
         del ModbusResponse._rtu_byte_count_pos
 
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_ptwisted.py b/test/test_ptwisted.py
index 3df0bc822..7d04013da 100644
--- a/test/test_ptwisted.py
+++ b/test/test_ptwisted.py
@@ -1,22 +1,25 @@
 #!/usr/bin/env python3
-""" Test ptwisted. """
+"""Test ptwisted."""
 import unittest
 
-#---------------------------------------------------------------------------#
-# Fixture
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Fixture
+# ---------------------------------------------------------------------------#
+
+
 class TwistedInternalCodeTest(unittest.TestCase):
-    """ Unittest for the pymodbus.internal.ptwisted code. """
+    """Unittest for the pymodbus.internal.ptwisted code."""
 
-    #-----------------------------------------------------------------------#
-    # Setup/TearDown
-    #-----------------------------------------------------------------------#
+    # -----------------------------------------------------------------------#
+    #  Setup/TearDown
+    # -----------------------------------------------------------------------#
 
     def test_install_conch(self):
-        """ Test that we can install the conch backend """
+        """Test that we can install the conch backend"""
+
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_register_read_messages.py b/test/test_register_read_messages.py
index 98627d3b0..c3cdc101e 100644
--- a/test/test_register_read_messages.py
+++ b/test/test_register_read_messages.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test register read messages. """
+"""Test register read messages."""
 import unittest
 
 from pymodbus.register_read_message import (
@@ -16,12 +16,14 @@
 
 from .modbus_mocks import MockContext, FakeList
 
-#---------------------------------------------------------------------------#
-# Fixture
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Fixture
+# ---------------------------------------------------------------------------#
+
+
 class ReadRegisterMessagesTest(unittest.TestCase):
-    """ Register Message Test Fixture
-    --------------------------------
+    """Register Message Test Fixture.
+
     This fixture tests the functionality of all the
     register based request/response messages:
 
@@ -30,130 +32,131 @@ class ReadRegisterMessagesTest(unittest.TestCase):
     """
 
     def setUp(self):
-        """ Initializes the test environment and builds request/result
-        encoding pairs
-        """
+        """Initialize the test environment and builds request/result encoding pairs."""
         arguments = {
-            'read_address':  1, 'read_count': 5,
-            'write_address': 1, 'write_registers': [0x00]*5,
+            'read_address': 1, 'read_count': 5,
+            'write_address': 1, 'write_registers': [0x00] * 5,
         }
-        self.value  = 0xabcd
+        self.value = 0xabcd
         self.values = [0xa, 0xb, 0xc]
-        self.request_read  = {
-            ReadRegistersRequestBase(1, 5)                  :b'\x00\x01\x00\x05',
-            ReadHoldingRegistersRequest(1, 5)               :b'\x00\x01\x00\x05',
-            ReadInputRegistersRequest(1,5)                  :b'\x00\x01\x00\x05',
-            ReadWriteMultipleRegistersRequest(**arguments)  :b'\x00\x01\x00\x05\x00\x01\x00'
-                                                             b'\x05\x0a\x00\x00\x00\x00\x00'
-                                                             b'\x00\x00\x00\x00\x00',
+        self.request_read = {
+            ReadRegistersRequestBase(1, 5): b'\x00\x01\x00\x05',
+            ReadHoldingRegistersRequest(1, 5): b'\x00\x01\x00\x05',
+            ReadInputRegistersRequest(1, 5): b'\x00\x01\x00\x05',
+            ReadWriteMultipleRegistersRequest(**arguments): b'\x00\x01\x00\x05\x00\x01\x00'
+            b'\x05\x0a\x00\x00\x00\x00\x00'
+            b'\x00\x00\x00\x00\x00',
         }
-        self.response_read  = {
-            ReadRegistersResponseBase(self.values)          :b'\x06\x00\x0a\x00\x0b\x00\x0c',
-            ReadHoldingRegistersResponse(self.values)       :b'\x06\x00\x0a\x00\x0b\x00\x0c',
-            ReadInputRegistersResponse(self.values)         :b'\x06\x00\x0a\x00\x0b\x00\x0c',
-            ReadWriteMultipleRegistersResponse(self.values) :b'\x06\x00\x0a\x00\x0b\x00\x0c',
+        self.response_read = {
+            ReadRegistersResponseBase(self.values): b'\x06\x00\x0a\x00\x0b\x00\x0c',
+            ReadHoldingRegistersResponse(self.values): b'\x06\x00\x0a\x00\x0b\x00\x0c',
+            ReadInputRegistersResponse(self.values): b'\x06\x00\x0a\x00\x0b\x00\x0c',
+            ReadWriteMultipleRegistersResponse(self.values): b'\x06\x00\x0a\x00\x0b\x00\x0c',
         }
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment."""
         del self.request_read
         del self.response_read
 
     def test_read_register_response_base(self):
-        """ Test read register response. """
+        """Test read register response."""
         response = ReadRegistersResponseBase(list(range(10)))
         for index in range(10):
             self.assertEqual(response.getRegister(index), index)
 
     def test_register_read_requests(self):
-        """ Test register read requests. """
+        """Test register read requests."""
         for request, response in iter(self.request_read.items()):
             self.assertEqual(request.encode(), response)
 
     def test_register_read_responses(self):
-        """ Test register read response. """
+        """Test register read response."""
         for request, response in iter(self.response_read.items()):
             self.assertEqual(request.encode(), response)
 
     def test_register_read_response_decode(self):
-        """ Test register read response. """
+        """Test register read response."""
         registers = [
-            [0x0a,0x0b,0x0c],
-            [0x0a,0x0b,0x0c],
-            [0x0a,0x0b,0x0c],
-            [0x0a,0x0b,0x0c, 0x0a,0x0b,0x0c],
+            [0x0a, 0x0b, 0x0c],
+            [0x0a, 0x0b, 0x0c],
+            [0x0a, 0x0b, 0x0c],
+            [0x0a, 0x0b, 0x0c, 0x0a, 0x0b, 0x0c],
         ]
-        values = sorted(self.response_read.items(), key=lambda x: str(x)) # pylint: disable=unnecessary-lambda
+        values = sorted(self.response_read.items(), key=lambda x: str(x))  # pylint: disable=unnecessary-lambda
         for packet, register in zip(values, registers):
             request, response = packet
             request.decode(response)
             self.assertEqual(request.registers, register)
 
     def test_register_read_requests_count_errors(self):
-        """ This tests that the register request messages
+        """This tests that the register request messages.
+
         will break on counts that are out of range
         """
         mock = FakeList(0x800)
         requests = [
             ReadHoldingRegistersRequest(1, 0x800),
-            ReadInputRegistersRequest(1,0x800),
+            ReadInputRegistersRequest(1, 0x800),
             ReadWriteMultipleRegistersRequest(read_address=1,
-                read_count=0x800, write_address=1, write_registers=5),
+                                              read_count=0x800, write_address=1, write_registers=5),
             ReadWriteMultipleRegistersRequest(read_address=1,
-                read_count=5, write_address=1, write_registers=mock),
+                                              read_count=5, write_address=1, write_registers=mock),
         ]
         for request in requests:
             result = request.execute(None)
             self.assertEqual(ModbusExceptions.IllegalValue,
-                result.exception_code)
+                             result.exception_code)
 
     def test_register_read_requests_validate_errors(self):
-        """ This tests that the register request messages
+        """This tests that the register request messages.
+
         will break on counts that are out of range
         """
         context = MockContext()
         requests = [
             ReadHoldingRegistersRequest(-1, 5),
-            ReadInputRegistersRequest(-1,5),
-            #ReadWriteMultipleRegistersRequest(-1,5,1,5),
-            #ReadWriteMultipleRegistersRequest(1,5,-1,5),
+            ReadInputRegistersRequest(-1, 5),
+            # ReadWriteMultipleRegistersRequest(-1,5,1,5),
+            # ReadWriteMultipleRegistersRequest(1,5,-1,5),
         ]
         for request in requests:
             result = request.execute(context)
             self.assertEqual(ModbusExceptions.IllegalAddress,
-                result.exception_code)
+                             result.exception_code)
 
     def test_register_read_requests_execute(self):
-        """ This tests that the register request messages
+        """This tests that the register request messages.
+
         will break on counts that are out of range
         """
         context = MockContext(True)
         requests = [
             ReadHoldingRegistersRequest(-1, 5),
-            ReadInputRegistersRequest(-1,5),
+            ReadInputRegistersRequest(-1, 5),
         ]
         for request in requests:
             response = request.execute(context)
             self.assertEqual(request.function_code, response.function_code)
 
     def test_read_write_multiple_registers_request(self):
-        """ Test read/write multiple registers. """
+        """Test read/write multiple registers."""
         context = MockContext(True)
         request = ReadWriteMultipleRegistersRequest(read_address=1,
-            read_count=10, write_address=1, write_registers=[0x00])
+                                                    read_count=10, write_address=1, write_registers=[0x00])
         response = request.execute(context)
         self.assertEqual(request.function_code, response.function_code)
 
     def test_read_write_multiple_registers_validate(self):
-        """ Test read/write multiple registers. """
+        """Test read/write multiple registers."""
         context = MockContext()
-        context.validate = lambda f,a,c: a == 1
+        context.validate = lambda f, a, c: a == 1
         request = ReadWriteMultipleRegistersRequest(read_address=1,
-            read_count=10, write_address=2, write_registers=[0x00])
+                                                    read_count=10, write_address=2, write_registers=[0x00])
         response = request.execute(context)
         self.assertEqual(response.exception_code, ModbusExceptions.IllegalAddress)
 
-        context.validate = lambda f,a,c: a == 2
+        context.validate = lambda f, a, c: a == 2
         response = request.execute(context)
         self.assertEqual(response.exception_code, ModbusExceptions.IllegalAddress)
 
@@ -162,26 +165,27 @@ def test_read_write_multiple_registers_validate(self):
         self.assertEqual(response.exception_code, ModbusExceptions.IllegalValue)
 
     def test_read_write_multiple_registers_request_decode(self):
-        """ Test read/write multiple registers. """
-        request, response = next((k,v) for k,v in self.request_read.items()
-            if getattr(k, 'function_code', 0) == 23)
+        """Test read/write multiple registers."""
+        request, response = next((k, v) for k, v in self.request_read.items()
+                                 if getattr(k, 'function_code', 0) == 23)
         request.decode(response)
         self.assertEqual(request.read_address, 0x01)
         self.assertEqual(request.write_address, 0x01)
         self.assertEqual(request.read_count, 0x05)
         self.assertEqual(request.write_count, 0x05)
         self.assertEqual(request.write_byte_count, 0x0a)
-        self.assertEqual(request.write_registers, [0x00]*5)
+        self.assertEqual(request.write_registers, [0x00] * 5)
 
     def test_serializing_to_string(self):
-        """ Test serializing to string. """
+        """Test serializing to string."""
         for request in iter(self.request_read.keys()):
-            self.assertTrue(str(request) is not None) #NOSONAR
+            self.assertTrue(str(request) is not None)  # NOSONAR
         for request in iter(self.response_read.keys()):
-            self.assertTrue(str(request) is not None) #NOSONAR
+            self.assertTrue(str(request) is not None)  # NOSONAR
+
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_register_write_messages.py b/test/test_register_write_messages.py
index c07534540..4742e1dd7 100644
--- a/test/test_register_write_messages.py
+++ b/test/test_register_write_messages.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test register write messages. """
+"""Test register write messages."""
 import unittest
 from pymodbus.register_write_message import (
     MaskWriteRegisterRequest,
@@ -15,12 +15,14 @@
 
 from .modbus_mocks import MockContext
 
-#---------------------------------------------------------------------------#
-# Fixture
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Fixture
+# ---------------------------------------------------------------------------#
+
+
 class WriteRegisterMessagesTest(unittest.TestCase):
-    """ Register Message Test Fixture
-    --------------------------------
+    """Register Message Test Fixture.
+
     This fixture tests the functionality of all the
     register based request/response messages:
 
@@ -29,60 +31,58 @@ class WriteRegisterMessagesTest(unittest.TestCase):
     """
 
     def setUp(self):
-        """ Initializes the test environment and builds request/result
-        encoding pairs
-        """
-        self.value  = 0xabcd
+        """Initialize the test environment and builds request/result encoding pairs."""
+        self.value = 0xabcd
         self.values = [0xa, 0xb, 0xc]
         builder = BinaryPayloadBuilder(byteorder=Endian.Big)
         builder.add_16bit_uint(0x1234)
         self.payload = builder.build()
-        self.write  = {
-            WriteSingleRegisterRequest(1, self.value)       :
+        self.write = {
+            WriteSingleRegisterRequest(1, self.value):
                 b'\x00\x01\xab\xcd',
-            WriteSingleRegisterResponse(1, self.value)      :
+            WriteSingleRegisterResponse(1, self.value):
                 b'\x00\x01\xab\xcd',
-            WriteMultipleRegistersRequest(1, self.values)   :
+            WriteMultipleRegistersRequest(1, self.values):
                 b'\x00\x01\x00\x03\x06\x00\n\x00\x0b\x00\x0c',
-            WriteMultipleRegistersResponse(1, 5)            :
+            WriteMultipleRegistersResponse(1, 5):
                 b'\x00\x01\x00\x05',
 
             WriteSingleRegisterRequest(1, self.payload[0],
-                skip_encode=True): b'\x00\x01\x12\x34',
+                                       skip_encode=True): b'\x00\x01\x12\x34',
             WriteMultipleRegistersRequest(1, self.payload,
-                skip_encode=True): b'\x00\x01\x00\x01\x02\x12\x34',
+                                          skip_encode=True): b'\x00\x01\x00\x01\x02\x12\x34',
         }
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
         del self.write
 
     def test_register_write_requests_encode(self):
-        """ Test register write requests encode. """
+        """Test register write requests encode."""
         for request, response in iter(self.write.items()):
             self.assertEqual(request.encode(), response)
 
     def test_register_write_requests_decode(self):
-        """ Test register write requests decode. """
-        addresses = [1,1,1,1]
-        values = sorted(self.write.items(), key=lambda x: str(x)) # pylint: disable=unnecessary-lambda
+        """Test register write requests decode."""
+        addresses = [1, 1, 1, 1]
+        values = sorted(self.write.items(), key=lambda x: str(x))  # pylint: disable=unnecessary-lambda
         for packet, address in zip(values, addresses):
             request, response = packet
             request.decode(response)
             self.assertEqual(request.address, address)
 
     def test_invalid_write_multiple_registers_request(self):
-        """ Test invalid write multiple registers request. """
+        """Test invalid write multiple registers request."""
         request = WriteMultipleRegistersRequest(0, None)
         self.assertEqual(request.values, [])
 
     def test_serializing_to_string(self):
-        """ Test serializing to string. """
+        """Test serializing to string."""
         for request in iter(self.write.keys()):
-            self.assertTrue(str(request) is not None) #NOSONAR
+            self.assertTrue(str(request) is not None)  # NOSONAR
 
     def test_write_single_register_request(self):
-        """ Test write single register request. """
+        """Test write single register request."""
         context = MockContext()
         request = WriteSingleRegisterRequest(0x00, 0xf0000)
         result = request.execute(context)
@@ -97,22 +97,22 @@ def test_write_single_register_request(self):
         self.assertEqual(result.function_code, request.function_code)
 
     def test_write_multiple_register_request(self):
-        """ test write multiple register request. """
+        """Test write multiple register request."""
         context = MockContext()
-        request = WriteMultipleRegistersRequest(0x00, [0x00]*10)
+        request = WriteMultipleRegistersRequest(0x00, [0x00] * 10)
         result = request.execute(context)
         self.assertEqual(result.exception_code, ModbusExceptions.IllegalAddress)
 
-        request.count = 0x05 # bytecode != code * 2
+        request.count = 0x05  # bytecode != code * 2
         result = request.execute(context)
         self.assertEqual(result.exception_code, ModbusExceptions.IllegalValue)
 
-        request.count = 0x800 # outside of range
+        request.count = 0x800  # outside of range
         result = request.execute(context)
         self.assertEqual(result.exception_code, ModbusExceptions.IllegalValue)
 
         context.valid = True
-        request = WriteMultipleRegistersRequest(0x00, [0x00]*10)
+        request = WriteMultipleRegistersRequest(0x00, [0x00] * 10)
         result = request.execute(context)
         self.assertEqual(result.function_code, request.function_code)
 
@@ -121,13 +121,13 @@ def test_write_multiple_register_request(self):
         # -----------------------------------------------------------------------#
 
     def test_mask_write_register_request_encode(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         handle = MaskWriteRegisterRequest(0x0000, 0x0101, 0x1010)
         result = handle.encode()
         self.assertEqual(result, b'\x00\x00\x01\x01\x10\x10')
 
     def test_mask_write_register_request_decode(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         request = b'\x00\x04\x00\xf2\x00\x25'
         handle = MaskWriteRegisterRequest()
         handle.decode(request)
@@ -136,14 +136,14 @@ def test_mask_write_register_request_decode(self):
         self.assertEqual(handle.or_mask, 0x0025)
 
     def test_mask_write_register_request_execute(self):
-        """ Test write register request valid execution """
+        """Test write register request valid execution"""
         context = MockContext(valid=True, default=0x0000)
         handle = MaskWriteRegisterRequest(0x0000, 0x0101, 0x1010)
         result = handle.execute(context)
         self.assertTrue(isinstance(result, MaskWriteRegisterResponse))
 
     def test_mask_write_register_request_invalid_execute(self):
-        """ Test write register request execute with invalid data """
+        """Test write register request execute with invalid data"""
         context = MockContext(valid=False, default=0x0000)
         handle = MaskWriteRegisterRequest(0x0000, -1, 0x1010)
         result = handle.execute(context)
@@ -165,13 +165,13 @@ def test_mask_write_register_request_invalid_execute(self):
         # -----------------------------------------------------------------------#
 
     def test_mask_write_register_response_encode(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         handle = MaskWriteRegisterResponse(0x0000, 0x0101, 0x1010)
         result = handle.encode()
         self.assertEqual(result, b'\x00\x00\x01\x01\x10\x10')
 
     def test_mask_write_register_response_decode(self):
-        """ Test basic bit message encoding/decoding """
+        """Test basic bit message encoding/decoding"""
         request = b'\x00\x04\x00\xf2\x00\x25'
         handle = MaskWriteRegisterResponse()
         handle.decode(request)
@@ -180,9 +180,8 @@ def test_mask_write_register_response_decode(self):
         self.assertEqual(handle.or_mask, 0x0025)
 
 
-
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_remote_datastore.py b/test/test_remote_datastore.py
index c73a91be6..996cb4330 100644
--- a/test/test_remote_datastore.py
+++ b/test/test_remote_datastore.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test remote datastore. """
+"""Test remote datastore."""
 import unittest
 from pymodbus.exceptions import NotImplementedException
 from pymodbus.datastore.remote import RemoteSlaveContext
@@ -9,59 +9,61 @@
 from pymodbus.pdu import ExceptionResponse
 from .modbus_mocks import mock
 
+
 class RemoteModbusDataStoreTest(unittest.TestCase):
-    """ Unittest for the pymodbus.datastore.remote module. """
+    """Unittest for the pymodbus.datastore.remote module."""
 
     def test_remote_slave_context(self):
-        """ Test a modbus remote slave context """
+        """Test a modbus remote slave context"""
         context = RemoteSlaveContext(None)
         self.assertNotEqual(str(context), None)
-        self.assertRaises(NotImplementedException, lambda: context.reset()) # pylint: disable=unnecessary-lambda
+        self.assertRaises(NotImplementedException, lambda: context.reset())  # pylint: disable=unnecessary-lambda
 
-    def test_remote_slave_set_values(self): # pylint: disable=no-self-use
-        """ Test setting values against a remote slave context """
-        client  = mock()
-        client.write_coils = lambda a,b: WriteMultipleCoilsResponse()
+    def test_remote_slave_set_values(self):  # pylint: disable=no-self-use
+        """Test setting values against a remote slave context"""
+        client = mock()
+        client.write_coils = lambda a, b: WriteMultipleCoilsResponse()
 
         context = RemoteSlaveContext(client)
         context.setValues(1, 0, [1])
 
     def test_remote_slave_get_values(self):
-        """ Test getting values from a remote slave context """
-        client  = mock()
-        client.read_coils = lambda a,b: ReadCoilsResponse([1]*10)
-        client.read_input_registers = lambda a,b: ReadInputRegistersResponse([10]*10)
-        client.read_holding_registers = lambda a,b: ExceptionResponse(0x15)
+        """Test getting values from a remote slave context"""
+        client = mock()
+        client.read_coils = lambda a, b: ReadCoilsResponse([1] * 10)
+        client.read_input_registers = lambda a, b: ReadInputRegistersResponse([10] * 10)
+        client.read_holding_registers = lambda a, b: ExceptionResponse(0x15)
 
         context = RemoteSlaveContext(client)
-        result  = context.getValues(1, 0, 10)
-        self.assertEqual(result, [1]*10)
+        result = context.getValues(1, 0, 10)
+        self.assertEqual(result, [1] * 10)
 
-        result  = context.getValues(4, 0, 10)
-        self.assertEqual(result, [10]*10)
+        result = context.getValues(4, 0, 10)
+        self.assertEqual(result, [10] * 10)
 
-        result  = context.getValues(3, 0, 10)
-        self.assertNotEqual(result, [10]*10)
+        result = context.getValues(3, 0, 10)
+        self.assertNotEqual(result, [10] * 10)
 
     def test_remote_slave_validate_values(self):
-        """ Test validating against a remote slave context """
-        client  = mock()
-        client.read_coils = lambda a,b: ReadCoilsResponse([1]*10)
-        client.read_input_registers = lambda a,b: ReadInputRegistersResponse([10]*10)
-        client.read_holding_registers = lambda a,b: ExceptionResponse(0x15)
+        """Test validating against a remote slave context"""
+        client = mock()
+        client.read_coils = lambda a, b: ReadCoilsResponse([1] * 10)
+        client.read_input_registers = lambda a, b: ReadInputRegistersResponse([10] * 10)
+        client.read_holding_registers = lambda a, b: ExceptionResponse(0x15)
 
         context = RemoteSlaveContext(client)
-        result  = context.validate(1, 0, 10)
+        result = context.validate(1, 0, 10)
         self.assertTrue(result)
 
-        result  = context.validate(4, 0, 10)
+        result = context.validate(4, 0, 10)
         self.assertTrue(result)
 
-        result  = context.validate(3, 0, 10)
+        result = context.validate(3, 0, 10)
         self.assertFalse(result)
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_server_async.py b/test/test_server_async.py
index ce51bb49e..0ed1bf036 100644
--- a/test/test_server_async.py
+++ b/test/test_server_async.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test server async. """
+"""Test server async."""
 import sys
 import platform
 from threading import Thread
@@ -33,25 +33,24 @@
 
 
 class AsynchronousServerTest(unittest.TestCase):
-    """ Unittest for the pymodbus.server.asynchronous module. """
+    """Unittest for the pymodbus.server.asynchronous module."""
 
     # ----------------------------------------------------------------------- #
     # Setup/TearDown
     # ----------------------------------------------------------------------- #
     def setUp(self):
-        """ Initializes the test environment. """
+        """Initialize the test environment."""
         values = dict((i, '') for i in range(10))
         ModbusDeviceIdentification(info=values)
 
     def tearDown(self):
-        """ Cleans up the test environment """
-
+        """Clean up the test environment"""
 
     # ----------------------------------------------------------------------- #
     # Test ModbusTcpProtocol
     # ----------------------------------------------------------------------- #
     def test_tcp_server_startup(self):
-        """ Test that the modbus tcp asynchronous server starts correctly """
+        """Test that the modbus tcp asynchronous server starts correctly"""
         with patch('twisted.internet.reactor') as mock_reactor:
             console = False
             call_count = 1
@@ -60,7 +59,7 @@ def test_tcp_server_startup(self):
             self.assertEqual(mock_reactor.run.call_count, 1)
 
     def test_connection_made(self):
-        """ Test connection made. """
+        """Test connection made."""
         protocol = ModbusTcpProtocol()
         protocol.transport = MagicMock()
         protocol.factory = MagicMock()
@@ -68,13 +67,13 @@ def test_connection_made(self):
         protocol.connectionMade()
         self.assertIsInstance(protocol.framer, ModbusSocketFramer)
 
-    def test_connection_lost(self): # pylint: disable=no-self-use
-        """ Test connection lost. """
+    def test_connection_lost(self):  # pylint: disable=no-self-use
+        """Test connection lost."""
         protocol = ModbusTcpProtocol()
         protocol.connectionLost("What ever reason")
 
     def test_data_received(self):
-        """ Test data received. """
+        """Test data received."""
         protocol = ModbusTcpProtocol()
         # mock_data = "Hello world!"
         mock_data = b"\x00\x01\x12\x34\x00\x04\xff\x02\x12\x34"
@@ -93,46 +92,47 @@ def test_data_received(self):
         self.assertEqual(protocol.dataReceived(mock_data), None)
 
     def test_tcp_execute_success(self):
-        """ Test tcp execute. """
+        """Test tcp execute."""
         protocol = ModbusTcpProtocol()
         protocol.store = MagicMock()
         request = MagicMock()
-        protocol._send = MagicMock() # pylint: disable=protected-access
+        protocol._send = MagicMock()  # pylint: disable=protected-access
 
         # test if _send being called
-        protocol._execute(request) # pylint: disable=protected-access
-        self.assertTrue(protocol._send.called) # pylint: disable=protected-access
+        protocol._execute(request)  # pylint: disable=protected-access
+        self.assertTrue(protocol._send.called)  # pylint: disable=protected-access
 
     def test_tcp_execute_failure(self):
-        """ Test tcp execute. """
+        """Test tcp execute."""
         protocol = ModbusTcpProtocol()
         protocol.factory = MagicMock()
         protocol.factory.store = MagicMock()
         protocol.store = MagicMock()
         protocol.factory.ignore_missing_slaves = False
         request = MagicMock()
-        protocol._send = MagicMock() # pylint: disable=protected-access
+        protocol._send = MagicMock()  # pylint: disable=protected-access
 
         # CASE-1: test NoSuchSlaveException exceptions
         request.execute.side_effect = NoSuchSlaveException()
-        protocol._execute(request) # pylint: disable=protected-access
+        protocol._execute(request)  # pylint: disable=protected-access
         self.assertTrue(request.doException.called)
 
         # CASE-2: NoSuchSlaveException with ignore_missing_slaves = true
         protocol.ignore_missing_slaves = True
         request.execute.side_effect = NoSuchSlaveException()
-        self.assertEqual(protocol._execute(request), None) # pylint: disable=protected-access
+        self.assertEqual(protocol._execute(request), None)  # pylint: disable=protected-access
 
         # test other exceptions
         request.execute.side_effect = ModbusIOException()
-        protocol._execute(request) # pylint: disable=protected-access
-        self.assertTrue(protocol._send.called) # pylint: disable=protected-access
+        protocol._execute(request)  # pylint: disable=protected-access
+        self.assertTrue(protocol._send.called)  # pylint: disable=protected-access
 
     def test_send_tcp(self):
-        """ Test send tcp. """
+        """Test send tcp."""
+
+        class MockMsg:  # pylint: disable=too-few-public-methods
+            """Mock message."""
 
-        class MockMsg: # pylint: disable=too-few-public-methods
-            """ Mock message. """
             def __init__(self, msg, resp=False):
                 self.should_respond = resp
                 self.msg = msg
@@ -147,19 +147,19 @@ def __init__(self, msg, resp=False):
         protocol.framer.buildPacket = MagicMock(return_value=mock_msg)
         protocol.transport = MagicMock()
 
-        protocol._send(mock_data) # pylint: disable=protected-access
+        protocol._send(mock_data)  # pylint: disable=protected-access
 
         self.assertTrue(protocol.framer.buildPacket.called)
         self.assertTrue(protocol.transport.write.called)
 
         mock_data = MockMsg(resp=False, msg="helloworld")
-        self.assertEqual(protocol._send(mock_data), None) # pylint: disable=protected-access
+        self.assertEqual(protocol._send(mock_data), None)  # pylint: disable=protected-access
 
     # ----------------------------------------------------------------------- #
     # Test ModbusServerFactory
     # ----------------------------------------------------------------------- #
     def test_modbus_server_factory(self):
-        """ Test the base class for all the clients """
+        """Test the base class for all the clients"""
         factory = ModbusServerFactory(store=None)
         self.assertEqual(factory.control.Identity.VendorName, '')
 
@@ -171,7 +171,7 @@ def test_modbus_server_factory(self):
     # Test ModbusUdpProtocol
     # ----------------------------------------------------------------------- #
     def test_udp_server_initialize(self):
-        """ Test UDP server. """
+        """Test UDP server."""
         protocol = ModbusUdpProtocol(store=None)
         self.assertEqual(protocol.control.Identity.VendorName, '')
 
@@ -180,7 +180,7 @@ def test_udp_server_initialize(self):
         self.assertEqual(protocol.control.Identity.VendorName, 'VendorName')
 
     def test_udp_server_startup(self):
-        """ Test that the modbus udp asynchronous server starts correctly """
+        """Test that the modbus udp asynchronous server starts correctly"""
         with patch('twisted.internet.reactor') as mock_reactor:
             StartUdpServer(context=None)
             self.assertEqual(mock_reactor.listenUDP.call_count, 1)
@@ -188,16 +188,16 @@ def test_udp_server_startup(self):
 
     @no_twisted_serial_on_windows_with_pypy
     @patch("twisted.internet.serialport.SerialPort")
-    def test_serial_server_startup(self, mock_sp): # pylint: disable=unused-argument
-        """ Test that the modbus serial asynchronous server starts correctly """
+    def test_serial_server_startup(self, mock_sp):  # pylint: disable=unused-argument
+        """Test that the modbus serial asynchronous server starts correctly"""
         with patch('twisted.internet.reactor') as mock_reactor:
             StartSerialServer(context=None, port=pytest.SERIAL_PORT)
             self.assertEqual(mock_reactor.run.call_count, 1)
 
     @no_twisted_serial_on_windows_with_pypy
     @patch("twisted.internet.serialport.SerialPort")
-    def test_stop_server_from_main_thread(self, mock_sp): # pylint: disable=unused-argument
-        """ Stop asynchronous server. """
+    def test_stop_server_from_main_thread(self, mock_sp):  # pylint: disable=unused-argument
+        """Stop asynchronous server."""
         with patch('twisted.internet.reactor') as mock_reactor:
             StartSerialServer(context=None, port=pytest.SERIAL_PORT)
             self.assertEqual(mock_reactor.run.call_count, 1)
@@ -206,8 +206,8 @@ def test_stop_server_from_main_thread(self, mock_sp): # pylint: disable=unused-a
 
     @no_twisted_serial_on_windows_with_pypy
     @patch("twisted.internet.serialport.SerialPort")
-    def test_stop_server_from_thread(self, mock_sp): # pylint: disable=unused-argument
-        """ Stop asynchronous server from child thread. """
+    def test_stop_server_from_thread(self, mock_sp):  # pylint: disable=unused-argument
+        """Stop asynchronous server from child thread."""
         with patch('twisted.internet.reactor') as mock_reactor:
             StartSerialServer(context=None, port=pytest.SERIAL_PORT)
             self.assertEqual(mock_reactor.run.call_count, 1)
@@ -217,19 +217,19 @@ def test_stop_server_from_thread(self, mock_sp): # pylint: disable=unused-argume
             self.assertEqual(mock_reactor.callFromThread.call_count, 1)
 
     def test_datagram_received(self):
-        """ Test datagram received. """
+        """Test datagram received."""
         mock_data = b"\x00\x01\x12\x34\x00\x04\xff\x02\x12\x34"
         mock_addr = 0x01
         protocol = ModbusUdpProtocol(store=None)
         protocol.framer.processIncomingPacket = MagicMock()
         protocol.control.ListenOnly = False
-        protocol._execute = MagicMock() # pylint: disable=protected-access
+        protocol._execute = MagicMock()  # pylint: disable=protected-access
 
         protocol.datagramReceived(mock_data, mock_addr)
         self.assertTrue(protocol.framer.processIncomingPacket.called)
 
     def test_send_udp(self):
-        """ Test send UDP. """
+        """Test send UDP."""
         protocol = ModbusUdpProtocol(store=None)
         mock_data = b"\x00\x01\x12\x34\x00\x04\xff\x02\x12\x34"
         mock_addr = 0x01
@@ -239,56 +239,56 @@ def test_send_udp(self):
         protocol.framer.buildPacket = MagicMock(return_value=mock_data)
         protocol.transport = MagicMock()
 
-        protocol._send(mock_data, mock_addr) # pylint: disable=protected-access
+        protocol._send(mock_data, mock_addr)  # pylint: disable=protected-access
 
         self.assertTrue(protocol.framer.buildPacket.called)
         self.assertTrue(protocol.transport.write.called)
 
     def test_udp_execute_success(self):
-        """ Test UDP execute success. """
+        """Test UDP execute success."""
         protocol = ModbusUdpProtocol(store=None)
         mock_addr = 0x01
         protocol.store = MagicMock()
         request = MagicMock()
-        protocol._send = MagicMock() # pylint: disable=protected-access
+        protocol._send = MagicMock()  # pylint: disable=protected-access
 
         # test if _send being called
-        protocol._execute(request, mock_addr) # pylint: disable=protected-access
-        self.assertTrue(protocol._send.called) # pylint: disable=protected-access
+        protocol._execute(request, mock_addr)  # pylint: disable=protected-access
+        self.assertTrue(protocol._send.called)  # pylint: disable=protected-access
 
     def test_udp_execute_failure(self):
-        """ Test UDP execute failure. """
+        """Test UDP execute failure."""
         protocol = ModbusUdpProtocol(store=None)
         mock_addr = 0x01
         protocol.store = MagicMock()
         request = MagicMock()
-        protocol._send = MagicMock() # pylint: disable=protected-access
+        protocol._send = MagicMock()  # pylint: disable=protected-access
 
         # CASE-1: test NoSuchSlaveException exceptions
         request.execute.side_effect = NoSuchSlaveException()
-        protocol._execute(request, mock_addr) # pylint: disable=protected-access
+        protocol._execute(request, mock_addr)  # pylint: disable=protected-access
         self.assertTrue(request.doException.called)
 
         # CASE-2: NoSuchSlaveException with ignore_missing_slaves = true
         protocol.ignore_missing_slaves = True
         request.execute.side_effect = NoSuchSlaveException()
-        self.assertEqual(protocol._execute(request, mock_addr), None) # pylint: disable=protected-access
+        self.assertEqual(protocol._execute(request, mock_addr), None)  # pylint: disable=protected-access
 
         # test other exceptions
         request.execute.side_effect = ModbusIOException()
-        protocol._execute(request, mock_addr) # pylint: disable=protected-access
-        self.assertTrue(protocol._send.called) # pylint: disable=protected-access
+        protocol._execute(request, mock_addr)  # pylint: disable=protected-access
+        self.assertTrue(protocol._send.called)  # pylint: disable=protected-access
 
     def test_stop_server(self):
-        """ Test stop server. """
-        from twisted.internet import reactor # pylint: disable=import-outside-toplevel
+        """Test stop server."""
+        from twisted.internet import reactor  # pylint: disable=import-outside-toplevel
         reactor.stop = MagicMock()
         StopServer()
 
         self.assertTrue(reactor.stop.called)
 
     def test_is_main_thread(self):
-        """ Test is main thread. """
+        """Test is main thread."""
         self.assertTrue(_is_main_thread())
 
 
diff --git a/test/test_server_asyncio.py b/test/test_server_asyncio.py
index bebb7a6e1..586abef95 100755
--- a/test/test_server_asyncio.py
+++ b/test/test_server_asyncio.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test server asyncio. """
+"""Test server asyncio."""
 import logging
 import asyncio
 import time
@@ -26,8 +26,8 @@
 _logger = logging.getLogger()
 
 
-class AsyncioServerTest(asynctest.TestCase): # pylint: disable=too-many-public-methods
-    """ Unittest for the pymodbus.server.asyncio module.
+class AsyncioServerTest(asynctest.TestCase):  # pylint: disable=too-many-public-methods
+    """Unittest for the pymodbus.server.asyncio module.
 
     The scope of this unit test is the life-cycle management of the network
     connections and server objects.
@@ -36,10 +36,10 @@ class AsyncioServerTest(asynctest.TestCase): # pylint: disable=too-many-public-m
     """
 
     # -----------------------------------------------------------------------#
-    # Setup/TearDown
+    #  Setup/TearDown
     # -----------------------------------------------------------------------#
     def setUp(self):
-        """ Initialize the test environment by setting up a dummy store and context. """
+        """Initialize the test environment by setting up a dummy store and context."""
         self.store = ModbusSlaveContext(di=ModbusSequentialDataBlock(0, [17] * 100),
                                         co=ModbusSequentialDataBlock(0, [17] * 100),
                                         hr=ModbusSequentialDataBlock(0, [17] * 100),
@@ -47,31 +47,31 @@ def setUp(self):
         self.context = ModbusServerContext(slaves=self.store, single=True)
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
 
     # -----------------------------------------------------------------------#
-    # Test ModbusConnectedRequestHandler
-    #-----------------------------------------------------------------------#
+    #  Test ModbusConnectedRequestHandler
+    # -----------------------------------------------------------------------#
 
     async def test_start_tcp_server(self):
-        """ Test that the modbus tcp asyncio server starts correctly """
+        """Test that the modbus tcp asyncio server starts correctly"""
         identity = ModbusDeviceIdentification(info_name={'VendorName': 'VendorName'})
-        self.loop = asynctest.Mock(self.loop) # pylint: disable=attribute-defined-outside-init
-        server = await StartTcpServer(context=self.context,loop=self.loop,identity=identity)
+        self.loop = asynctest.Mock(self.loop)  # pylint: disable=attribute-defined-outside-init
+        server = await StartTcpServer(context=self.context, loop=self.loop, identity=identity)
         self.assertEqual(server.control.Identity.VendorName, 'VendorName')
         self.loop.create_server.assert_called_once()
 
     async def test_tcp_server_serve_no_defer(self):
-        """ Test StartTcpServer without deferred start (immediate execution of server) """
-        with patch('asyncio.base_events.Server.serve_forever', #NOSONAR
-                new_callable=asynctest.CoroutineMock) as serve:
-            await StartTcpServer(context=self.context,address=("127.0.0.1",
-                    0), loop=self.loop, defer_start=False)
+        """Test StartTcpServer without deferred start (immediate execution of server)"""
+        with patch('asyncio.base_events.Server.serve_forever',  # NOSONAR
+                   new_callable=asynctest.CoroutineMock) as serve:
+            await StartTcpServer(context=self.context, address=("127.0.0.1",
+                                                                0), loop=self.loop, defer_start=False)
             serve.assert_awaited()
 
     async def test_tcp_server_serve_forever_twice(self):
-        """ Call on serve_forever() twice should result in a runtime error """
-        server = await StartTcpServer(context=self.context,address=("127.0.0.1", 0), loop=self.loop)
+        """Call on serve_forever() twice should result in a runtime error"""
+        server = await StartTcpServer(context=self.context, address=("127.0.0.1", 0), loop=self.loop)
         asyncio.create_task(server.serve_forever())
         await server.serving
         with self.assertRaises(RuntimeError):
@@ -80,48 +80,48 @@ async def test_tcp_server_serve_forever_twice(self):
         server.server_close()
 
     async def test_tcp_server_receive_data(self):
-        """ Test data sent on socket is received by internals - doesn't not process data """
+        """Test data sent on socket is received by internals - doesn't not process data"""
         data = b'\x01\x00\x00\x00\x00\x06\x01\x03\x00\x00\x00\x19'
-        server = await StartTcpServer(context=self.context,address=("127.0.0.1", 0),loop=self.loop)
+        server = await StartTcpServer(context=self.context, address=("127.0.0.1", 0), loop=self.loop)
         asyncio.create_task(server.serve_forever())
 
         await server.serving
-        with patch('pymodbus.transaction.ModbusSocketFramer.processIncomingPacket', #NOSONAR
-                new_callable=Mock) as process:
+        with patch('pymodbus.transaction.ModbusSocketFramer.processIncomingPacket',  # NOSONAR
+                   new_callable=Mock) as process:
             # process = server.framer.processIncomingPacket = Mock()
             connected = self.loop.create_future()
             random_port = server.server.sockets[0].getsockname()[1]  # get the random server port
 
             class BasicClient(asyncio.BaseProtocol):
-                """ Basic client. """
+                """Basic client."""
 
                 def connection_made(self, transport):
-                    """ Connection made. """
-                    self.transport = transport # pylint: disable=attribute-defined-outside-init
+                    """Get Connection made."""
+                    self.transport = transport  # pylint: disable=attribute-defined-outside-init
                     self.transport.write(data)
                     connected.set_result(True)
 
                 def eof_received(self):
-                    """ EOF received. """
+                    """EOF received."""
 
-            await self.loop.create_connection(BasicClient, host='127.0.0.1',port=random_port)
-            await asyncio.sleep(0.1) # this may be better done
+            await self.loop.create_connection(BasicClient, host='127.0.0.1', port=random_port)
+            await asyncio.sleep(0.1)  # this may be better done
             # by making an internal hook in the actual implementation
             # if this unit test fails on a machine,
             # see if increasing the sleep time makes a difference,
             # if it does blame author for a fix
 
             process.assert_called_once()
-            self.assertTrue( process.call_args[1]["data"] == data )
+            self.assertTrue(process.call_args[1]["data"] == data)
             server.server_close()
 
     @pytest.mark.skipif(pytest.IS_WINDOWS, reason="To fix")
     async def test_tcp_server_roundtrip(self):
-        """ Test sending and receiving data on tcp socket """
-        data = b"\x01\x00\x00\x00\x00\x06\x01\x03\x00\x00\x00\x01" # unit 1, read register
+        """Test sending and receiving data on tcp socket"""
+        data = b"\x01\x00\x00\x00\x00\x06\x01\x03\x00\x00\x00\x01"  # unit 1, read register
         expected_response = b'\x01\x00\x00\x00\x00\x05\x01\x03\x02\x00\x11'
-                # value of 17 as per context
-        server = await StartTcpServer(context=self.context,address=("127.0.0.1", 0),loop=self.loop)
+        # value of 17 as per context
+        server = await StartTcpServer(context=self.context, address=("127.0.0.1", 0), loop=self.loop)
         asyncio.create_task(server.serve_forever())
         await server.serving
         random_port = server.server.sockets[0].getsockname()[1]  # get the random server port
@@ -129,25 +129,25 @@ async def test_tcp_server_roundtrip(self):
         received_value = None
 
         class BasicClient(asyncio.BaseProtocol):
-            """ Basic client. """
+            """Basic client."""
 
             def connection_made(self, transport):
-                """ Connection made. """
-                self.transport = transport # pylint: disable=attribute-defined-outside-init
+                """Get Connection made."""
+                self.transport = transport  # pylint: disable=attribute-defined-outside-init
                 self.transport.write(data)
                 connected.set_result(True)
 
-            def data_received(self, data): # pylint: disable=no-self-use
-                """ Data received. """
+            def data_received(self, data):  # pylint: disable=no-self-use
+                """Get Data received."""
                 nonlocal received_value, done
                 received_value = data
                 done.set_result(True)
 
             def eof_received(self):
-                """ EOF received. """
+                """EOF received."""
 
         transport, _ = await self.loop.create_connection(BasicClient,
-                host='127.0.0.1', port=random_port)
+                                                         host='127.0.0.1', port=random_port)
         await asyncio.wait_for(done, timeout=0.1)
 
         self.assertEqual(received_value, expected_response)
@@ -158,10 +158,9 @@ def eof_received(self):
 
     @pytest.mark.skipif(pytest.IS_WINDOWS, reason="To fix")
     async def test_tcp_server_connection_lost(self):
-        """ Test tcp stream interruption """
-
+        """Test tcp stream interruption"""
         server = await StartTcpServer(context=self.context,
-                address=("127.0.0.1", 0), loop=self.loop)
+                                      address=("127.0.0.1", 0), loop=self.loop)
         asyncio.create_task(server.serve_forever())
         await server.serving
         random_port = server.server.sockets[0].getsockname()[1]  # get the random server port
@@ -169,15 +168,15 @@ async def test_tcp_server_connection_lost(self):
         time.sleep(1)
 
         class BasicClient(asyncio.BaseProtocol):
-            """ Basic client. """
+            """Basic client."""
 
             def connection_made(self, transport):
-                """ Connection made. """
-                self.transport = transport # pylint: disable=attribute-defined-outside-init
+                """Get Connection made."""
+                self.transport = transport  # pylint: disable=attribute-defined-outside-init
                 step1.set_result(True)
 
         _, protocol = await self.loop.create_connection(BasicClient,
-                host='127.0.0.1', port=random_port)
+                                                        host='127.0.0.1', port=random_port)
         await step1
         # On Windows we seem to need to give this an extra chance to finish,
         # otherwise there ends up being an active connection at the assert.
@@ -185,17 +184,16 @@ def connection_made(self, transport):
         self.assertEqual(len(server.active_connections), 1)
 
         protocol.transport.close()
-            # close isn't synchronous and there's no
-            # notification that it's done
+        # close isn't synchronous and there's no
+        # notification that it's done
         await asyncio.sleep(0.2)  # so we have to wait a bit
         self.assertFalse(server.active_connections)
 
         server.server_close()
 
-
     async def test_tcp_server_close_active_connection(self):
-        """ Test server_close() while there are active TCP connections """
-        server = await StartTcpServer(context=self.context,address=("127.0.0.1", 0),loop=self.loop)
+        """Test server_close() while there are active TCP connections"""
+        server = await StartTcpServer(context=self.context, address=("127.0.0.1", 0), loop=self.loop)
         asyncio.create_task(server.serve_forever())
 
         await server.serving
@@ -206,11 +204,11 @@ async def test_tcp_server_close_active_connection(self):
         self.loop.create_future()
 
         class BasicClient(asyncio.BaseProtocol):
-            """ Basic client. """
+            """Basic client."""
 
             def connection_made(self, transport):
-                """ Connection made. """
-                self.transport = transport # pylint: disable=attribute-defined-outside-init
+                """Get Connection made."""
+                self.transport = transport  # pylint: disable=attribute-defined-outside-init
                 step1.set_result(True)
 
         await self.loop.create_connection(BasicClient, host='127.0.0.1', port=random_port)
@@ -224,15 +222,14 @@ def connection_made(self, transport):
         # close isn't synchronous and there's no notification that it's done
         # so we have to wait a bit
         await asyncio.sleep(0.5)
-        self.assertTrue( not server.active_connections )
-
+        self.assertTrue(not server.active_connections)
 
     async def test_tcp_server_no_slave(self):
-        """ Test unknown slave unit exception """
-        context = ModbusServerContext(slaves={0x01: self.store, 0x02: self.store  }, single=False)
+        """Test unknown slave unit exception"""
+        context = ModbusServerContext(slaves={0x01: self.store, 0x02: self.store}, single=False)
         data = b"\x01\x00\x00\x00\x00\x06\x05\x03\x00\x00\x00\x01"
-                # get slave 5 function 3 (holding register)
-        server = await StartTcpServer(context=context,address=("127.0.0.1", 0),loop=self.loop)
+        # get slave 5 function 3 (holding register)
+        server = await StartTcpServer(context=context, address=("127.0.0.1", 0), loop=self.loop)
         asyncio.create_task(server.serve_forever())
         await server.serving
         random_port = server.server.sockets[0].getsockname()[1]  # get the random server port
@@ -241,22 +238,22 @@ async def test_tcp_server_no_slave(self):
         eof = self.loop.create_future()
 
         class BasicClient(asyncio.BaseProtocol):
-            """ Basic client. """
+            """Basic client."""
 
             def connection_made(self, transport):
-                """ Connection made. """
-                self.transport = transport # pylint: disable=attribute-defined-outside-init
+                """Get Connection made."""
+                self.transport = transport  # pylint: disable=attribute-defined-outside-init
                 transport.write(data)
                 connect.set_result(True)
                 _logger.debug("Client connected")
 
-            def data_received(self, data): #NOSONAR pylint: disable=no-self-use,unused-argument
-                """ Data received. """
+            def data_received(self, data):  # NOSONAR pylint: disable=no-self-use,unused-argument
+                """Get Data received."""
                 receive.set_result(True)
                 _logger.debug("Client received data")
 
-            def eof_received(self): # pylint: disable=no-self-use
-                """ EOF received. """
+            def eof_received(self):  # pylint: disable=no-self-use
+                """Get EOF received."""
                 eof.set_result(True)
                 _logger.debug("Client stream eof")
 
@@ -265,12 +262,11 @@ def eof_received(self): # pylint: disable=no-self-use
         self.assertFalse(eof.done())
         server.server_close()
 
-
     async def test_tcp_server_modbus_error(self):
-        """ Test sending garbage data on a TCP socket should drop the connection """
+        """Test sending garbage data on a TCP socket should drop the connection"""
         data = b"\x01\x00\x00\x00\x00\x06\x01\x03\x00\x00\x00\x01"
-            # get slave 5 function 3 (holding register)
-        server = await StartTcpServer(context=self.context,address=("127.0.0.1", 0),loop=self.loop)
+        # get slave 5 function 3 (holding register)
+        server = await StartTcpServer(context=self.context, address=("127.0.0.1", 0), loop=self.loop)
         asyncio.create_task(server.serve_forever())
 
         await server.serving
@@ -281,69 +277,69 @@ async def test_tcp_server_modbus_error(self):
             random_port = server.server.sockets[0].getsockname()[1]  # get the random server port
 
             class BasicClient(asyncio.BaseProtocol):
-                """ Basic client. """
+                """Basic client."""
+
                 def connection_made(self, transport):
-                    """ Connection made. """
+                    """Get connection made."""
                     _logger.debug("Client connected")
-                    self.transport = transport # pylint: disable=attribute-defined-outside-init
+                    self.transport = transport  # pylint: disable=attribute-defined-outside-init
                     transport.write(data)
                     connect.set_result(True)
 
-                def data_received(self, data): #NOSONAR pylint: disable=no-self-use,unused-argument
-                    """ Data receivec. """
+                def data_received(self, data):  # NOSONAR pylint: disable=no-self-use,unused-argument
+                    """Get data received."""
                     _logger.debug("Client received data")
                     receive.set_result(True)
 
-                def eof_received(self): # pylint: disable=no-self-use
-                    """ EOF received. """
+                def eof_received(self):  # pylint: disable=no-self-use
+                    """EOF received."""
                     _logger.debug("Client stream eof")
                     eof.set_result(True)
 
             transport, _ = await self.loop.create_connection(BasicClient,
-                    host='127.0.0.1', port=random_port)
+                                                             host='127.0.0.1', port=random_port)
             await asyncio.wait_for(connect, timeout=0.1)
             await asyncio.wait_for(receive, timeout=0.1)
             self.assertFalse(eof.done())
             transport.close()
             server.server_close()
 
-
     async def test_tcp_server_internal_exception(self):
-        """ Test sending garbage data on a TCP socket should drop the connection """
+        """Test sending garbage data on a TCP socket should drop the connection"""
         data = b"\x01\x00\x00\x00\x00\x06\x01\x03\x00\x00\x00\x01"
-            # get slave 5 function 3 (holding register)
-        server = await StartTcpServer(context=self.context,address=("127.0.0.1", 0),loop=self.loop)
+        # get slave 5 function 3 (holding register)
+        server = await StartTcpServer(context=self.context, address=("127.0.0.1", 0), loop=self.loop)
         asyncio.create_task(server.serve_forever())
 
         await server.serving
         with patch("pymodbus.register_read_message.ReadHoldingRegistersRequest.execute",
                    side_effect=Exception):
             connect, receive, eof = self.loop.create_future(),\
-                    self.loop.create_future(), self.loop.create_future()
+                self.loop.create_future(), self.loop.create_future()
             random_port = server.server.sockets[0].getsockname()[1]  # get the random server port
 
             class BasicClient(asyncio.BaseProtocol):
-                """ Basic client. """
+                """Basic client."""
 
                 def connection_made(self, transport):
-                    """ Connection made. """
+                    """Get connection made."""
                     _logger.debug("Client connected")
-                    self.transport = transport # pylint: disable=attribute-defined-outside-init
+                    self.transport = transport  # pylint: disable=attribute-defined-outside-init
                     transport.write(data)
                     connect.set_result(True)
 
-                def data_received(self, data): #NOSONAR pylint: disable=no-self-use,unused-argument
-                    """ Data received. """
+                def data_received(self, data):  # NOSONAR pylint: disable=no-self-use,unused-argument
+                    """Get data received."""
                     _logger.debug("Client received data")
                     receive.set_result(True)
 
-                def eof_received(self): # pylint: disable=no-self-use
-                    """ EOF received. """
+                def eof_received(self):  # pylint: disable=no-self-use
+                    """EOF received."""
                     _logger.debug("Client stream eof")
                     eof.set_result(True)
 
             transport, _ = await self.loop.create_connection(BasicClient,
-                    host='127.0.0.1', port=random_port)
+                                                             host='127.0.0.1', port=random_port)
             await asyncio.wait_for(connect, timeout=0.1)
             await asyncio.wait_for(receive, timeout=0.1)
             self.assertFalse(eof.done())
@@ -355,30 +351,30 @@ def eof_received(self): # pylint: disable=no-self-use
 
     # -----------------------------------------------------------------------#
     async def test_start_tls_server(self):
-        """ Test that the modbus tls asyncio server starts correctly """
+        """Test that the modbus tls asyncio server starts correctly"""
         with patch.object(ssl.SSLContext, 'load_cert_chain'):
             identity = ModbusDeviceIdentification(info={0x00: 'VendorName'})
-            self.loop = asynctest.Mock(self.loop) # pylint: disable=attribute-defined-outside-init
+            self.loop = asynctest.Mock(self.loop)  # pylint: disable=attribute-defined-outside-init
             server = await StartTlsServer(context=self.context, loop=self.loop, identity=identity)
             self.assertEqual(server.control.Identity.VendorName, 'VendorName')
             self.assertTrue(server.sslctx is not None)
             self.loop.create_server.assert_called_once()
 
     async def test_tls_server_serve_forever(self):
-        """ Test StartTcpServer serve_forever() method """
+        """Test StartTcpServer serve_forever() method"""
         with patch('asyncio.base_events.Server.serve_forever',
-                new_callable=asynctest.CoroutineMock) as serve:
+                   new_callable=asynctest.CoroutineMock) as serve:
             with patch.object(ssl.SSLContext, 'load_cert_chain'):
                 server = await StartTlsServer(context=self.context,
-                        address=("127.0.0.1", 0), loop=self.loop)
+                                              address=("127.0.0.1", 0), loop=self.loop)
                 await server.serve_forever()
                 serve.assert_awaited()
 
     async def test_tls_server_serve_forever_twice(self):
-        """ Call on serve_forever() twice should result in a runtime error """
+        """Call on serve_forever() twice should result in a runtime error"""
         with patch.object(ssl.SSLContext, 'load_cert_chain'):
             server = await StartTlsServer(context=self.context,
-                    address=("127.0.0.1", 0), loop=self.loop)
+                                          address=("127.0.0.1", 0), loop=self.loop)
             asyncio.create_task(server.serve_forever())
             await server.serving
             with pytest.raises(RuntimeError):
@@ -390,26 +386,25 @@ async def test_tls_server_serve_forever_twice(self):
     # -----------------------------------------------------------------------#
 
     async def test_start_udp_server(self):
-        """ Test that the modbus udp asyncio server starts correctly """
+        """Test that the modbus udp asyncio server starts correctly"""
         identity = ModbusDeviceIdentification(info={0x00: 'VendorName'})
-        self.loop = asynctest.Mock(self.loop) # pylint: disable=attribute-defined-outside-init
-        server = await StartUdpServer(context=self.context,loop=self.loop,identity=identity)
+        self.loop = asynctest.Mock(self.loop)  # pylint: disable=attribute-defined-outside-init
+        server = await StartUdpServer(context=self.context, loop=self.loop, identity=identity)
         self.assertEqual(server.control.Identity.VendorName, 'VendorName')
         self.loop.create_datagram_endpoint.assert_called_once()
 
     async def test_udp_server_serve_forever_start(self):
-        """ Test StartUdpServer serve_forever() method """
+        """Test StartUdpServer serve_forever() method"""
         with patch('asyncio.base_events.Server.serve_forever',
-            new_callable=asynctest.CoroutineMock) as serve:
+                   new_callable=asynctest.CoroutineMock) as serve:
             server = await StartTcpServer(context=self.context,
-                        address=("127.0.0.1", 0), loop=self.loop)
+                                          address=("127.0.0.1", 0), loop=self.loop)
             await server.serve_forever()
             serve.assert_awaited()
 
-
     async def test_udp_server_serve_forever_close(self):
-        """ Test StartUdpServer serve_forever() method """
-        server = await StartUdpServer(context=self.context,address=("127.0.0.1", 0), loop=self.loop)
+        """Test StartUdpServer serve_forever() method"""
+        server = await StartUdpServer(context=self.context, address=("127.0.0.1", 0), loop=self.loop)
         asyncio.create_task(server.serve_forever())
 
         await server.serving
@@ -421,51 +416,49 @@ async def test_udp_server_serve_forever_close(self):
         self.assertTrue(server.protocol.is_closing())
 
     async def test_udp_server_serve_forever_twice(self):
-        """ Call on serve_forever() twice should result in a runtime error """
+        """Call on serve_forever() twice should result in a runtime error"""
         identity = ModbusDeviceIdentification(info={0x00: 'VendorName'})
-        server = await StartUdpServer(context=self.context,address=("127.0.0.1", 0),
-                                      loop=self.loop,identity=identity)
+        server = await StartUdpServer(context=self.context, address=("127.0.0.1", 0),
+                                      loop=self.loop, identity=identity)
         asyncio.create_task(server.serve_forever())
         await server.serving
         with self.assertRaises(RuntimeError):
             await server.serve_forever()
         server.server_close()
 
-
     async def test_udp_server_receive_data(self):
-        """ Test that the sending data on datagram socket gets data pushed to framer """
-        server = await StartUdpServer(context=self.context,address=("127.0.0.1", 0),loop=self.loop)
+        """Test that the sending data on datagram socket gets data pushed to framer"""
+        server = await StartUdpServer(context=self.context, address=("127.0.0.1", 0), loop=self.loop)
         asyncio.create_task(server.serve_forever())
         await server.serving
         with patch('pymodbus.transaction.ModbusSocketFramer.processIncomingPacket',
-                new_callable=Mock) as process:
+                   new_callable=Mock) as process:
             server.endpoint.datagram_received(data=b"12345", addr=("127.0.0.1", 12345))
             await asyncio.sleep(0.1)
             process.seal()
             process.assert_called_once()
-            self.assertTrue( process.call_args[1]["data"] == b"12345" )
+            self.assertTrue(process.call_args[1]["data"] == b"12345")
 
             server.server_close()
 
-
     async def test_udp_server_send_data(self):
-        """ Test that the modbus udp asyncio server correctly sends data outbound """
+        """Test that the modbus udp asyncio server correctly sends data outbound"""
         ModbusDeviceIdentification(info={0x00: 'VendorName'})
         data = b'x\01\x00\x00\x00\x00\x06\x01\x03\x00\x00\x00\x19'
-        server = await StartUdpServer(context=self.context,address=("127.0.0.1", 0))
+        server = await StartUdpServer(context=self.context, address=("127.0.0.1", 0))
         asyncio.create_task(server.serve_forever())
 
         await server.serving
-        random_port = server.protocol._sock.getsockname()[1] # pylint: disable=protected-access
+        random_port = server.protocol._sock.getsockname()[1]  # pylint: disable=protected-access
         received = server.endpoint.datagram_received = Mock(wraps=server.endpoint.datagram_received)
         done = self.loop.create_future()
         received_value = None
 
         class BasicClient(asyncio.DatagramProtocol):
-            """ Basic client. """
+            """Basic client."""
 
             def connection_made(self, transport):
-                self.transport = transport # pylint: disable=attribute-defined-outside-init
+                self.transport = transport  # pylint: disable=attribute-defined-outside-init
                 self.transport.sendto(data)
 
             def datagram_received(self, data, addr):
@@ -475,8 +468,8 @@ def datagram_received(self, data, addr):
                 done.set_result(True)
                 self.transport.close()
 
-        await self.loop.create_datagram_endpoint( BasicClient,
-            remote_addr=('127.0.0.1', random_port))
+        await self.loop.create_datagram_endpoint(BasicClient,
+                                                 remote_addr=('127.0.0.1', random_port))
 
         await asyncio.sleep(0.1)
 
@@ -488,27 +481,26 @@ def datagram_received(self, data, addr):
         self.assertTrue(server.protocol.is_closing())
         await asyncio.sleep(0.1)
 
-
     async def test_udp_server_roundtrip(self):
-        """ Test sending and receiving data on udp socket"""
-        data = b"\x01\x00\x00\x00\x00\x06\x01\x03\x00\x00\x00\x01" # unit 1, read register
+        """Test sending and receiving data on udp socket"""
+        data = b"\x01\x00\x00\x00\x00\x06\x01\x03\x00\x00\x00\x01"  # unit 1, read register
         expected_response = b'\x01\x00\x00\x00\x00\x05'\
-                            b'\x01\x03\x02\x00\x11' # value of 17 as per context
-        server = await StartUdpServer(context=self.context,address=("127.0.0.1", 0),loop=self.loop)
+                            b'\x01\x03\x02\x00\x11'  # value of 17 as per context
+        server = await StartUdpServer(context=self.context, address=("127.0.0.1", 0), loop=self.loop)
         asyncio.create_task(server.serve_forever())
 
         await server.serving
 
-        random_port = server.protocol._sock.getsockname()[1] # pylint: disable=protected-access
+        random_port = server.protocol._sock.getsockname()[1]  # pylint: disable=protected-access
 
         _, done = self.loop.create_future(), self.loop.create_future()
         received_value = None
 
         class BasicClient(asyncio.DatagramProtocol):
-            """ Basic client. """
+            """Basic client."""
 
             def connection_made(self, transport):
-                self.transport = transport # pylint: disable=attribute-defined-outside-init
+                self.transport = transport  # pylint: disable=attribute-defined-outside-init
                 self.transport.sendto(data)
 
             def datagram_received(self, data, addr):
@@ -518,7 +510,7 @@ def datagram_received(self, data, addr):
                 done.set_result(True)
 
         transport, _ = await self.loop.create_datagram_endpoint(BasicClient,
-                                                remote_addr=('127.0.0.1', random_port))
+                                                                remote_addr=('127.0.0.1', random_port))
         await asyncio.wait_for(done, timeout=0.1)
 
         self.assertEqual(received_value, expected_response)
@@ -528,24 +520,25 @@ def datagram_received(self, data, addr):
         server.server_close()
 
     async def test_udp_server_exception(self):
-        """ Test sending garbage data on a TCP socket should drop the connection """
+        """Test sending garbage data on a TCP socket should drop the connection"""
         garbage = b'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF'
-        server = await StartUdpServer(context=self.context,address=("127.0.0.1", 0),loop=self.loop)
+        server = await StartUdpServer(context=self.context, address=("127.0.0.1", 0), loop=self.loop)
         asyncio.create_task(server.serve_forever())
 
         await server.serving
         with patch('pymodbus.transaction.ModbusSocketFramer.processIncomingPacket',
                    new_callable=lambda: Mock(side_effect=Exception)):
             connect, receive, _ = self.loop.create_future(),\
-                            self.loop.create_future(), self.loop.create_future()
-            random_port = server.protocol._sock.getsockname()[1]  # get the random server port pylint: disable=protected-access
+                self.loop.create_future(), self.loop.create_future()
+            # get the random server port pylint: disable=protected-access
+            random_port = server.protocol._sock.getsockname()[1]
 
             class BasicClient(asyncio.DatagramProtocol):
-                """ Basic client. """
+                """Basic client."""
 
                 def connection_made(self, transport):
                     _logger.debug("Client connected")
-                    self.transport = transport # pylint: disable=attribute-defined-outside-init
+                    self.transport = transport  # pylint: disable=attribute-defined-outside-init
                     transport.sendto(garbage)
                     connect.set_result(True)
 
@@ -558,58 +551,58 @@ def datagram_received(self, data, addr):
                                                             remote_addr=('127.0.0.1', random_port))
             await asyncio.wait_for(connect, timeout=0.1)
             self.assertFalse(receive.done())
-            self.assertFalse(server.protocol._sock._closed) # pylint: disable=protected-access
+            self.assertFalse(server.protocol._sock._closed)  # pylint: disable=protected-access
 
             server.server_close()
 
     # -----------------------------------------------------------------------#
     # Test ModbusServerFactory
     # -----------------------------------------------------------------------#
-    def test_modbus_server_factory(self): # pylint: disable=no-self-use
-        """ Test the base class for all the clients """
+    def test_modbus_server_factory(self):  # pylint: disable=no-self-use
+        """Test the base class for all the clients"""
         with pytest.warns(DeprecationWarning):
             ModbusServerFactory(store=None)
 
-    def test_stop_server(self): # pylint: disable=no-self-use
-        """ Test stop server. """
+    def test_stop_server(self):  # pylint: disable=no-self-use
+        """Test stop server."""
         with pytest.warns(DeprecationWarning):
             StopServer()
 
     async def test_tcp_server_exception(self):
-        """ Sending garbage data on a TCP socket should drop the connection """
+        """Sending garbage data on a TCP socket should drop the connection"""
         garbage = b'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF'
         server = await StartTcpServer(context=self.context,
-                            address=("127.0.0.1", 0), loop=self.loop)
+                                      address=("127.0.0.1", 0), loop=self.loop)
         asyncio.create_task(server.serve_forever())
         await server.serving
         with patch('pymodbus.transaction.ModbusSocketFramer.processIncomingPacket',
                    new_callable=lambda: Mock(side_effect=Exception)):
             connect, receive, eof = self.loop.create_future(),\
-                                    self.loop.create_future(), self.loop.create_future()
+                self.loop.create_future(), self.loop.create_future()
             random_port = server.server.sockets[0].getsockname()[1]  # get the random server port
 
             class BasicClient(asyncio.BaseProtocol):
-                """ Basic client. """
+                """Basic client."""
 
                 def connection_made(self, transport):
-                    """ Connection made. """
+                    """Get connection made."""
                     _logger.debug("Client connected")
-                    self.transport = transport # pylint: disable=attribute-defined-outside-init
+                    self.transport = transport  # pylint: disable=attribute-defined-outside-init
                     transport.write(garbage)
                     connect.set_result(True)
 
-                def data_received(self, data): #NOSONAR pylint: disable=no-self-use,unused-argument
-                    """ Data received. """
+                def data_received(self, data):  # NOSONAR pylint: disable=no-self-use,unused-argument
+                    """Get data received."""
                     _logger.debug("Client received data")
                     receive.set_result(True)
 
-                def eof_received(self): # pylint: disable=no-self-use
-                    """ Eof received. """
+                def eof_received(self):  # pylint: disable=no-self-use
+                    """Eof received."""
                     _logger.debug("Client stream eof")
                     eof.set_result(True)
 
             _, _ = await self.loop.create_connection(BasicClient, host='127.0.0.1',
-                                                    port=random_port)
+                                                     port=random_port)
             await asyncio.wait_for(connect, timeout=0.1)
             await asyncio.wait_for(eof, timeout=0.1)
             # neither of these should timeout if the test is successful
diff --git a/test/test_server_context.py b/test/test_server_context.py
index 979dce587..98357620b 100644
--- a/test/test_server_context.py
+++ b/test/test_server_context.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test server context. """
+"""Test server context."""
 import unittest
 from pymodbus.datastore import (
     ModbusSlaveContext,
@@ -7,96 +7,93 @@
 )
 from pymodbus.exceptions import NoSuchSlaveException
 
+
 class ModbusServerSingleContextTest(unittest.TestCase):
-    """ This is the unittest for the pymodbus.datastore.ModbusServerContext
-    using a single slave context.
-    """
+    """This is the unittest for the pymodbus.datastore.ModbusServerContext using a single slave context."""
 
     def setUp(self):
-        """ Sets up the test environment """
+        """Set up the test environment"""
         self.slave = ModbusSlaveContext()
         self.context = ModbusServerContext(slaves=self.slave, single=True)
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
         del self.context
 
     def test_single_context_gets(self):
-        """ Test getting on a single context """
+        """Test getting on a single context"""
         for slave_id in range(0, 0xff):
             self.assertEqual(self.slave, self.context[slave_id])
 
     def test_single_context_deletes(self):
-        """ Test removing on multiple context """
+        """Test removing on multiple context"""
         def _test():
             del self.context[0x00]
         self.assertRaises(NoSuchSlaveException, _test)
 
     def test_single_context_iter(self):
-        """ Test iterating over a single context """
+        """Test iterating over a single context"""
         expected = (0, self.slave)
         for slave in self.context:
             self.assertEqual(slave, expected)
 
     def test_single_context_default(self):
-        """ Test that the single context default values work """
+        """Test that the single context default values work"""
         self.context = ModbusServerContext()
         slave = self.context[0x00]
         self.assertEqual(slave, {})
 
     def test_single_context_set(self):
-        """ Test a setting a single slave context """
+        """Test a setting a single slave context"""
         slave = ModbusSlaveContext()
         self.context[0x00] = slave
         actual = self.context[0x00]
         self.assertEqual(slave, actual)
 
     def test_single_context_register(self):
-        """ Test single context register. """
+        """Test single context register."""
         request_db = [1, 2, 3]
         slave = ModbusSlaveContext()
         slave.register(0xff, 'custom_request', request_db)
-        self.assertEqual(slave.store["custom_request"],request_db)
-        self.assertEqual(slave.decode(0xff),'custom_request')
+        self.assertEqual(slave.store["custom_request"], request_db)
+        self.assertEqual(slave.decode(0xff), 'custom_request')
 
 
 class ModbusServerMultipleContextTest(unittest.TestCase):
-    """ This is the unittest for the pymodbus.datastore.ModbusServerContext
-    using multiple slave contexts.
-    """
+    """This is the unittest for the pymodbus.datastore.ModbusServerContext using multiple slave contexts."""
 
     def setUp(self):
-        """ Sets up the test environment """
-        self.slaves  = dict((id, ModbusSlaveContext()) for id in range(10))
+        """Set up the test environment"""
+        self.slaves = dict((id, ModbusSlaveContext()) for id in range(10))
         self.context = ModbusServerContext(slaves=self.slaves, single=False)
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
         del self.context
 
     def test_multiple_context_gets(self):
-        """ Test getting on multiple context """
+        """Test getting on multiple context"""
         for slave_id in range(0, 10):
             self.assertEqual(self.slaves[slave_id], self.context[slave_id])
 
     def test_multiple_context_deletes(self):
-        """ Test removing on multiple context """
+        """Test removing on multiple context"""
         del self.context[0x00]
         self.assertRaises(NoSuchSlaveException, lambda: self.context[0x00])
 
     def test_multiple_context_iter(self):
-        """ Test iterating over multiple context """
+        """Test iterating over multiple context"""
         for slave_id, slave in self.context:
             self.assertEqual(slave, self.slaves[slave_id])
             self.assertTrue(slave_id in self.context)
 
     def test_multiple_context_default(self):
-        """ Test that the multiple context default values work """
+        """Test that the multiple context default values work"""
         self.context = ModbusServerContext(single=False)
         self.assertRaises(NoSuchSlaveException, lambda: self.context[0x00])
 
     def test_multiple_context_set(self):
-        """ Test a setting multiple slave contexts """
+        """Test a setting multiple slave contexts"""
         slaves = dict((id, ModbusSlaveContext()) for id in range(10))
         for slave_id, slave in iter(slaves.items()):
             self.context[slave_id] = slave
@@ -104,8 +101,9 @@ def test_multiple_context_set(self):
             actual = self.context[slave_id]
             self.assertEqual(slave, actual)
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_server_sync.py b/test/test_server_sync.py
index a3503fad7..6ffcc440d 100644
--- a/test/test_server_sync.py
+++ b/test/test_server_sync.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test server sync. """
+"""Test server sync."""
 import ssl
 import socket
 import unittest
@@ -36,10 +36,10 @@
 # Mock Classes
 # --------------------------------------------------------------------------- #
 class MockServer:  # noqa: E302 pylint: disable=too-few-public-methods
-    """ Mock server. """
+    """Mock server."""
 
     def __init__(self):
-        """ Init. """
+        """Init."""
         self.framer = lambda _, client=None: "framer"
         self.decoder = "decoder"
         self.threads = []
@@ -47,25 +47,27 @@ def __init__(self):
 # --------------------------------------------------------------------------- #
 # Fixture
 # --------------------------------------------------------------------------- #
+
+
 class SynchronousServerTest(unittest.TestCase):  # noqa: E302
-    """ Unittest for the pymodbus.server.sync module. """
+    """Unittest for the pymodbus.server.sync module."""
 
     # ----------------------------------------------------------------------- #
     # Test Base Request Handler
     # ----------------------------------------------------------------------- #
 
     def test_base_handler_undefined_methods(self):
-        """ Test the base handler undefined methods"""
+        """Test the base handler undefined methods"""
         handler = socketserver.BaseRequestHandler(None, None, None)
         handler.__class__ = ModbusBaseRequestHandler
-        self.assertRaises(NotImplementedException, lambda: handler.send(None)) # pylint: disable=no-member
-        self.assertRaises(NotImplementedException, lambda: handler.handle()) # pylint: disable=unnecessary-lambda
+        self.assertRaises(NotImplementedException, lambda: handler.send(None))  # pylint: disable=no-member
+        self.assertRaises(NotImplementedException, lambda: handler.handle())  # pylint: disable=unnecessary-lambda
 
     def test_base_handler_methods(self):
-        """ Test the base class for all the clients """
+        """Test the base class for all the clients"""
         request = ReadCoilsRequest(1, 1)
         address = ('server', 12345)
-        server  = MockServer()  # noqa: E221
+        server = MockServer()  # noqa: E221
         with patch.object(ModbusBaseRequestHandler, 'handle') as mock_handle:
             with patch.object(ModbusBaseRequestHandler, 'send') as mock_send:
                 mock_handle.return_value = True
@@ -85,22 +87,22 @@ def test_base_handler_methods(self):
     # Test Single Request Handler
     # ----------------------------------------------------------------------- #
     def test_modbus_single_request_handler_send(self):
-        """ Test modbus single request handler. """
+        """Test modbus single request handler."""
         handler = socketserver.BaseRequestHandler(None, None, None)
         handler.__class__ = ModbusSingleRequestHandler
         handler.framer = Mock()
         handler.framer.buildPacket.return_value = b"message"
         handler.request = Mock()
         request = ReadCoilsResponse([1])
-        handler.send(request) # pylint: disable=no-member
+        handler.send(request)  # pylint: disable=no-member
         self.assertEqual(handler.request.send.call_count, 1)
 
         request.should_respond = False
-        handler.send(request) # pylint: disable=no-member
+        handler.send(request)  # pylint: disable=no-member
         self.assertEqual(handler.request.send.call_count, 1)
 
     def test_modbus_single_request_handler_handle(self):
-        """ Test modbus single request handler. """
+        """Test modbus single request handler."""
         handler = socketserver.BaseRequestHandler(None, None, None)
         handler.__class__ = ModbusSingleRequestHandler
         handler.framer = Mock()
@@ -116,7 +118,7 @@ def test_modbus_single_request_handler_handle(self):
         self.assertEqual(handler.framer.processIncomingPacket.call_count, 0)
 
         # run forever if we are running
-        def _callback1(parm1, parm2, *args, **kwargs): # pylint: disable=unused-argument
+        def _callback1(parm1, parm2, *args, **kwargs):  # pylint: disable=unused-argument
             handler.running = False  # stop infinite loop
         handler.framer.processIncomingPacket.side_effect = _callback1
         handler.running = True
@@ -127,7 +129,7 @@ def _callback1(parm1, parm2, *args, **kwargs): # pylint: disable=unused-argument
         self.assertEqual(handler.framer.processIncomingPacket.call_count, 1)
 
         # exceptions are simply ignored
-        def _callback2(parm1, parm2, *args, **kwargs): # pylint: disable=unused-argument
+        def _callback2(parm1, parm2, *args, **kwargs):  # pylint: disable=unused-argument
             if handler.framer.processIncomingPacket.call_count == 2:
                 raise Exception("example exception")
             handler.running = False  # stop infinite loop
@@ -141,22 +143,22 @@ def _callback2(parm1, parm2, *args, **kwargs): # pylint: disable=unused-argument
     # Test Connected Request Handler
     # ----------------------------------------------------------------------- #
     def test_modbus_connected_request_handler_send(self):
-        """ Test modbus connected request handler. """
+        """Test modbus connected request handler."""
         handler = socketserver.BaseRequestHandler(None, None, None)
         handler.__class__ = ModbusConnectedRequestHandler
         handler.framer = Mock()
         handler.framer.buildPacket.return_value = b"message"
         handler.request = Mock()
         request = ReadCoilsResponse([1])
-        handler.send(request) # pylint: disable=no-member
+        handler.send(request)  # pylint: disable=no-member
         self.assertEqual(handler.request.send.call_count, 1)
 
         request.should_respond = False
-        handler.send(request) # pylint: disable=no-member
+        handler.send(request)  # pylint: disable=no-member
         self.assertEqual(handler.request.send.call_count, 1)
 
     def test_modbus_connected_request_handler_handle(self):
-        """ Test modbus connected request handler. """
+        """Test modbus connected request handler."""
         handler = socketserver.BaseRequestHandler(None, None, None)
         handler.__class__ = ModbusConnectedRequestHandler
         handler.server = Mock()
@@ -171,7 +173,7 @@ def test_modbus_connected_request_handler_handle(self):
         self.assertEqual(handler.framer.processIncomingPacket.call_count, 0)
 
         # run forever if we are running
-        def _callback(parm1, parm2, *args, **kwargs): # pylint: disable=unused-argument
+        def _callback(parm1, parm2, *args, **kwargs):  # pylint: disable=unused-argument
             handler.running = False  # stop infinite loop
 
         handler.framer.processIncomingPacket.side_effect = _callback
@@ -201,7 +203,7 @@ def _callback(parm1, parm2, *args, **kwargs): # pylint: disable=unused-argument
     # Test Disconnected Request Handler
     # ----------------------------------------------------------------------- #
     def test_modbus_disconnected_request_handler_send(self):
-        """ Test modbus disconnect request handler. """
+        """Test modbus disconnect request handler."""
         handler = socketserver.BaseRequestHandler(None, None, None)
         handler.__class__ = ModbusDisconnectedRequestHandler
         handler.framer = Mock()
@@ -210,15 +212,15 @@ def test_modbus_disconnected_request_handler_send(self):
         handler.request = Mock()
         handler.socket = Mock()
         request = ReadCoilsResponse([1])
-        handler.send(request) # pylint: disable=no-member
+        handler.send(request)  # pylint: disable=no-member
         self.assertEqual(handler.socket.sendto.call_count, 1)
 
         request.should_respond = False
-        handler.send(request) # pylint:disable=no-member
+        handler.send(request)  # pylint:disable=no-member
         self.assertEqual(handler.socket.sendto.call_count, 1)
 
     def test_modbus_disconnected_request_handler_handle(self):
-        """ Test modbus disconned request handler. """
+        """Test modbus disconned request handler."""
         handler = socketserver.BaseRequestHandler(None, None, None)
         handler.__class__ = ModbusDisconnectedRequestHandler
         handler.framer = Mock()
@@ -232,7 +234,7 @@ def test_modbus_disconnected_request_handler_handle(self):
         self.assertEqual(handler.framer.processIncomingPacket.call_count, 0)
 
         # run forever if we are running
-        def _callback(parm1, parm2): # pylint: disable=unused-argument
+        def _callback(parm1, parm2):  # pylint: disable=unused-argument
             handler.running = False  # stop infinite loop
 
         handler.framer.processIncomingPacket.side_effect = _callback
@@ -264,7 +266,7 @@ def _callback(parm1, parm2): # pylint: disable=unused-argument
     # Test TCP Server
     # ----------------------------------------------------------------------- #
     def test_tcp_server_close(self):
-        """ test that the synchronous TCP server closes correctly """
+        """Test that the synchronous TCP server closes correctly"""
         identity = ModbusDeviceIdentification(info={0x00: 'VendorName'})
         server = ModbusTcpServer(context=None, identity=identity, bind_and_activate=False)
         server.threads.append(Mock(**{'running': True}))
@@ -273,7 +275,7 @@ def test_tcp_server_close(self):
         self.assertFalse(server.threads[0].running)
 
     def test_tcp_server_process(self):
-        """ test that the synchronous TCP server processes requests """
+        """Test that the synchronous TCP server processes requests"""
         with patch('socketserver.ThreadingTCPServer') as mock_server:
             server = ModbusTcpServer(None)
             server.process_request('request', 'client')
@@ -283,7 +285,7 @@ def test_tcp_server_process(self):
     # Test TLS Server
     # ----------------------------------------------------------------------- #
     def test_tls_ssl_ctx_provider(self):
-        """ test that sslctx_provider() produce SSLContext correctly """
+        """Test that sslctx_provider() produce SSLContext correctly"""
         with patch.object(ssl.SSLContext, 'load_cert_chain'):
             sslctx = sslctx_provider(reqclicert=True)
             self.assertIsNotNone(sslctx)
@@ -295,7 +297,7 @@ def test_tls_ssl_ctx_provider(self):
             self.assertEqual(sslctx_new, sslctx_old)
 
     def test_tls_server_init(self):
-        """ test that the synchronous TLS server initial correctly """
+        """Test that the synchronous TLS server initial correctly"""
         with patch.object(socketserver.TCPServer, 'server_activate'):
             with patch.object(ssl.SSLContext, 'load_cert_chain'):
                 identity = ModbusDeviceIdentification(info={0x00: 'VendorName'})
@@ -310,7 +312,7 @@ def test_tls_server_init(self):
                 server.server_close()
 
     def test_tls_server_close(self):
-        """ test that the synchronous TLS server closes correctly """
+        """Test that the synchronous TLS server closes correctly"""
         with patch.object(ssl.SSLContext, 'load_cert_chain'):
             identity = ModbusDeviceIdentification(info={0x00: 'VendorName'})
             server = ModbusTlsServer(context=None, identity=identity,
@@ -321,7 +323,7 @@ def test_tls_server_close(self):
             self.assertFalse(server.threads[0].running)
 
     def test_tls_server_process(self):
-        """ test that the synchronous TLS server processes requests """
+        """Test that the synchronous TLS server processes requests"""
         with patch('socketserver.ThreadingTCPServer') as mock_server:
             with patch.object(ssl.SSLContext, 'load_cert_chain'):
                 server = ModbusTlsServer(None)
@@ -332,7 +334,7 @@ def test_tls_server_process(self):
     # Test UDP Server
     # ----------------------------------------------------------------------- #
     def test_udp_server_close(self):
-        """ test that the synchronous UDP server closes correctly """
+        """Test that the synchronous UDP server closes correctly"""
         identity = ModbusDeviceIdentification(info={0x00: 'VendorName'})
         server = ModbusUdpServer(context=None, identity=identity,
                                  bind_and_activate=False)
@@ -343,7 +345,7 @@ def test_udp_server_close(self):
         self.assertFalse(server.threads[0].running)
 
     def test_udp_server_process(self):
-        """ test that the synchronous UDP server processes requests """
+        """Test that the synchronous UDP server processes requests"""
         with patch('socketserver.ThreadingUDPServer') as mock_server:
             server = ModbusUdpServer(None)
             request = ('data', 'socket')
@@ -354,26 +356,26 @@ def test_udp_server_process(self):
     # Test Serial Server
     # ----------------------------------------------------------------------- #
     def test_serial_server_connect(self):
-        """ Test serial server connect. """
+        """Test serial server connect."""
         with patch.object(serial, 'Serial') as mock_serial:
-            mock_serial.write = lambda x: len(x) # pylint: disable=unnecessary-lambda
+            mock_serial.write = lambda x: len(x)  # pylint: disable=unnecessary-lambda
             mock_serial.read = lambda size: '\x00' * size
             identity = ModbusDeviceIdentification(info={0x00: 'VendorName'})
             server = ModbusSerialServer(context=None, identity=identity, port="dummy")
             self.assertEqual(server.handler.__class__.__name__, "CustomSingleRequestHandler")
             self.assertEqual(server.control.Identity.VendorName, 'VendorName')
 
-            server._connect() # pylint: disable=protected-access
+            server._connect()  # pylint: disable=protected-access
 
         with patch.object(serial, 'Serial') as mock_serial:
-            mock_serial.write = lambda x: len(x) # pylint: disable=unnecessary-lambda
+            mock_serial.write = lambda x: len(x)  # pylint: disable=unnecessary-lambda
             mock_serial.read = lambda size: '\x00' * size
             mock_serial.side_effect = serial.SerialException()
             server = ModbusSerialServer(None, port="dummy")
             self.assertEqual(server.socket, None)
 
-    def test_serial_server_serve_forever(self): # pylint: disable=no-self-use
-        """ test that the synchronous serial server closes correctly """
+    def test_serial_server_serve_forever(self):  # pylint: disable=no-self-use
+        """Test that the synchronous serial server closes correctly"""
         with patch.object(serial, 'Serial'):
             with patch('pymodbus.server.sync.CustomSingleRequestHandler') as mock_handler:
                 server = ModbusSerialServer(None)
@@ -382,8 +384,8 @@ def test_serial_server_serve_forever(self): # pylint: disable=no-self-use
                 server.serve_forever()
                 instance.response_manipulator.assert_any_call()
 
-    def test_serial_server_close(self): # pylint: disable=no-self-use
-        """ test that the synchronous serial server closes correctly """
+    def test_serial_server_close(self):  # pylint: disable=no-self-use
+        """Test that the synchronous serial server closes correctly"""
         with patch.object(serial, 'Serial') as mock_serial:
             instance = mock_serial.return_value
             server = ModbusSerialServer(None)
@@ -393,25 +395,25 @@ def test_serial_server_close(self): # pylint: disable=no-self-use
     # ----------------------------------------------------------------------- #
     # Test Synchronous Factories
     # ----------------------------------------------------------------------- #
-    def test_start_tcp_server(self): # pylint: disable=no-self-use
-        """ Test the tcp server starting factory """
+    def test_start_tcp_server(self):  # pylint: disable=no-self-use
+        """Test the tcp server starting factory"""
         with patch.object(ModbusTcpServer, 'serve_forever'):
             StartTcpServer(bind_and_activate=False)
 
-    def test_start_tls_server(self): # pylint: disable=no-self-use
-        """ Test the tls server starting factory """
+    def test_start_tls_server(self):  # pylint: disable=no-self-use
+        """Test the tls server starting factory"""
         with patch.object(ModbusTlsServer, 'serve_forever'):
             with patch.object(ssl.SSLContext, 'load_cert_chain'):
                 StartTlsServer(bind_and_activate=False)
 
-    def test_start_udp_server(self): # pylint: disable=no-self-use
-        """ Test the udp server starting factory """
+    def test_start_udp_server(self):  # pylint: disable=no-self-use
+        """Test the udp server starting factory"""
         with patch.object(ModbusUdpServer, 'serve_forever'):
             with patch.object(socketserver.UDPServer, 'server_bind'):
                 StartUdpServer()
 
-    def test_start_serial_server(self): # pylint: disable=no-self-use
-        """ Test the serial server starting factory """
+    def test_start_serial_server(self):  # pylint: disable=no-self-use
+        """Test the serial server starting factory"""
         with patch.object(ModbusSerialServer, 'serve_forever'):
             StartSerialServer(port=pytest.SERIAL_PORT)
 
diff --git a/test/test_transaction.py b/test/test_transaction.py
index 3f9636fae..4689ca4c3 100755
--- a/test/test_transaction.py
+++ b/test/test_transaction.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-""" Test transaction. """
+"""Test transaction."""
 import unittest
 from itertools import count
 from binascii import a2b_hex
@@ -28,27 +28,27 @@
 )
 
 
-class ModbusTransactionTest(unittest.TestCase): # pylint: disable=too-many-public-methods
-    """ Unittest for the pymodbus.transaction module. """
+class ModbusTransactionTest(unittest.TestCase):  # pylint: disable=too-many-public-methods
+    """Unittest for the pymodbus.transaction module."""
 
     # ----------------------------------------------------------------------- #
     # Test Construction
     # ----------------------------------------------------------------------- #
     def setUp(self):
-        """ Sets up the test environment """
-        self.client   = None
-        self.decoder  = ServerDecoder()
-        self._tcp     = ModbusSocketFramer(decoder=self.decoder, client=None)
-        self._tls     = ModbusTlsFramer(decoder=self.decoder, client=None)
-        self._rtu     = ModbusRtuFramer(decoder=self.decoder, client=None)
-        self._ascii   = ModbusAsciiFramer(decoder=self.decoder, client=None)
-        self._binary  = ModbusBinaryFramer(decoder=self.decoder, client=None)
+        """Set up the test environment"""
+        self.client = None
+        self.decoder = ServerDecoder()
+        self._tcp = ModbusSocketFramer(decoder=self.decoder, client=None)
+        self._tls = ModbusTlsFramer(decoder=self.decoder, client=None)
+        self._rtu = ModbusRtuFramer(decoder=self.decoder, client=None)
+        self._ascii = ModbusAsciiFramer(decoder=self.decoder, client=None)
+        self._binary = ModbusBinaryFramer(decoder=self.decoder, client=None)
         self._manager = DictTransactionManager(self.client)
         self._queue_manager = FifoTransactionManager(self.client)
         self._tm = ModbusTransactionManager(self.client)
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
         del self._manager
         del self._tcp
         del self._tls
@@ -60,16 +60,16 @@ def tearDown(self):
     # ----------------------------------------------------------------------- #
 
     def test_calculate_expected_response_length(self):
-        """ Test calculate expected response length. """
+        """Test calculate expected response length."""
         self._tm.client = MagicMock()
         self._tm.client.framer = MagicMock()
-        self._tm._set_adu_size() # pylint: disable=protected-access
-        self.assertEqual(self._tm._calculate_response_length(0), None) # pylint: disable=protected-access
+        self._tm._set_adu_size()  # pylint: disable=protected-access
+        self.assertEqual(self._tm._calculate_response_length(0), None)  # pylint: disable=protected-access
         self._tm.base_adu_size = 10
-        self.assertEqual(self._tm._calculate_response_length(5), 15) # pylint: disable=protected-access
+        self.assertEqual(self._tm._calculate_response_length(5), 15)  # pylint: disable=protected-access
 
     def test_calculate_exception_length(self):
-        """ Test calculate exception length. """
+        """Test calculate exception length."""
         for framer, exception_length in (('ascii', 11),
                                          ('binary', 7),
                                          ('rtu', 5),
@@ -90,18 +90,18 @@ def test_calculate_exception_length(self):
             else:
                 self._tm.client.framer = MagicMock()
 
-            self._tm._set_adu_size() # pylint: disable=protected-access
-            self.assertEqual(self._tm._calculate_exception_length(), # pylint: disable=protected-access
+            self._tm._set_adu_size()  # pylint: disable=protected-access
+            self.assertEqual(self._tm._calculate_exception_length(),  # pylint: disable=protected-access
                              exception_length)
 
     @patch('pymodbus.transaction.time')
     def test_execute(self, mock_time):
-        """ Test execute. """
+        """Test execute."""
         mock_time.time.side_effect = count()
 
         client = MagicMock()
         client.framer = self._ascii
-        client.framer._buffer = b'deadbeef' # pylint: disable=protected-access
+        client.framer._buffer = b'deadbeef'  # pylint: disable=protected-access
         client.framer.processIncomingPacket = MagicMock()
         client.framer.processIncomingPacket.return_value = None
         client.framer.buildPacket = MagicMock()
@@ -119,7 +119,7 @@ def test_execute(self, mock_time):
         request.unit_id = 1
         request.function_code = 222
         trans = ModbusTransactionManager(client)
-        trans._recv = MagicMock(return_value=b'abcdef') # pylint: disable=protected-access
+        trans._recv = MagicMock(return_value=b'abcdef')  # pylint: disable=protected-access
         self.assertEqual(trans.retries, 3)
         self.assertEqual(trans.retry_on_empty, False)
 
@@ -128,7 +128,7 @@ def test_execute(self, mock_time):
         response = trans.execute(request)
         self.assertEqual(response, 'response')
         # No response
-        trans._recv = MagicMock(return_value=b'abcdef') # pylint: disable=protected-access
+        trans._recv = MagicMock(return_value=b'abcdef')  # pylint: disable=protected-access
         # tm._transact.return_value = (b'', None)
         trans.transactions = []
         trans.getTransaction = MagicMock()
@@ -138,13 +138,13 @@ def test_execute(self, mock_time):
 
         # No response with retries
         trans.retry_on_empty = True
-        trans._recv = MagicMock(side_effect=iter([b'', b'abcdef'])) # pylint: disable=protected-access
+        trans._recv = MagicMock(side_effect=iter([b'', b'abcdef']))  # pylint: disable=protected-access
         # tm._transact.side_effect = [(b'', None), (b'abcdef', None)]
         response = trans.execute(request)
         self.assertIsInstance(response, ModbusIOException)
 
         # wrong handle_local_echo
-        trans._recv = MagicMock(side_effect=iter([b'abcdef', b'deadbe', b'123456'])) # pylint: disable=protected-access
+        trans._recv = MagicMock(side_effect=iter([b'abcdef', b'deadbe', b'123456']))  # pylint: disable=protected-access
         client.handle_local_echo = True
         trans.retry_on_empty = False
         trans.retry_on_invalid = False
@@ -154,13 +154,14 @@ def test_execute(self, mock_time):
 
         # retry on invalid response
         trans.retry_on_invalid = True
-        trans._recv = MagicMock(side_effect=iter([b'', b'abcdef', b'deadbe', b'123456'])) # pylint: disable=protected-access
+        trans._recv = MagicMock(side_effect=iter(  # pylint: disable=protected-access
+            [b'', b'abcdef', b'deadbe', b'123456']))  # pylint: disable=protected-access
         # tm._transact.side_effect = [(b'', None), (b'abcdef', None)]
         response = trans.execute(request)
         self.assertIsInstance(response, ModbusIOException)
 
         # Unable to decode response
-        trans._recv = MagicMock(side_effect=ModbusIOException()) # pylint: disable=protected-access
+        trans._recv = MagicMock(side_effect=ModbusIOException())  # pylint: disable=protected-access
         # tm._transact.side_effect = [(b'abcdef', None)]
         client.framer.processIncomingPacket.side_effect = MagicMock(side_effect=ModbusIOException())
         self.assertIsInstance(trans.execute(request), ModbusIOException)
@@ -172,40 +173,39 @@ def test_execute(self, mock_time):
         self.assertEqual(response, b'Broadcast write sent - '
                                    b'no response expected')
 
-
     # ----------------------------------------------------------------------- #
     # Dictionary based transaction manager
     # ----------------------------------------------------------------------- #
 
     def test_dict_transaction_manager_tid(self):
-        """ Test the dict transaction manager TID """
+        """Test the dict transaction manager TID"""
         for tid in range(1, self._manager.getNextTID() + 10):
-            self.assertEqual(tid+1, self._manager.getNextTID())
+            self.assertEqual(tid + 1, self._manager.getNextTID())
         self._manager.reset()
         self.assertEqual(1, self._manager.getNextTID())
 
     def test_get_dict_fifo_transaction_manager_transaction(self):
-        """ Test the dict transaction manager """
-        class Request: # pylint: disable=too-few-public-methods
-            """ Request. """
+        """Test the dict transaction manager"""
+        class Request:  # pylint: disable=too-few-public-methods
+            """Request."""
 
         self._manager.reset()
         handle = Request()
-        handle.transaction_id = self._manager.getNextTID() # pylint: disable=attribute-defined-outside-init
-        handle.message = b"testing" # pylint: disable=attribute-defined-outside-init
+        handle.transaction_id = self._manager.getNextTID()  # pylint: disable=attribute-defined-outside-init
+        handle.message = b"testing"  # pylint: disable=attribute-defined-outside-init
         self._manager.addTransaction(handle)
         result = self._manager.getTransaction(handle.transaction_id)
         self.assertEqual(handle.message, result.message)
 
     def test_delete_dict_fifo_transaction_manager_transaction(self):
-        """ Test the dict transaction manager """
-        class Request: # pylint: disable=too-few-public-methods
-            """ Request. """
+        """Test the dict transaction manager"""
+        class Request:  # pylint: disable=too-few-public-methods
+            """Request."""
 
         self._manager.reset()
         handle = Request()
-        handle.transaction_id = self._manager.getNextTID() # pylint: disable=attribute-defined-outside-init
-        handle.message = b"testing" # pylint: disable=attribute-defined-outside-init
+        handle.transaction_id = self._manager.getNextTID()  # pylint: disable=attribute-defined-outside-init
+        handle.message = b"testing"  # pylint: disable=attribute-defined-outside-init
 
         self._manager.addTransaction(handle)
         self._manager.delTransaction(handle.transaction_id)
@@ -215,34 +215,34 @@ class Request: # pylint: disable=too-few-public-methods
     # Queue based transaction manager
     # ----------------------------------------------------------------------- #
     def test_fifo_transaction_manager_tid(self):
-        """ Test the fifo transaction manager TID """
+        """Test the fifo transaction manager TID"""
         for tid in range(1, self._queue_manager.getNextTID() + 10):
-            self.assertEqual(tid+1, self._queue_manager.getNextTID())
+            self.assertEqual(tid + 1, self._queue_manager.getNextTID())
         self._queue_manager.reset()
         self.assertEqual(1, self._queue_manager.getNextTID())
 
     def test_get_fifo_transaction_manager_transaction(self):
-        """ Test the fifo transaction manager """
-        class Request: # pylint: disable=too-few-public-methods
-            """ Request. """
+        """Test the fifo transaction manager"""
+        class Request:  # pylint: disable=too-few-public-methods
+            """Request."""
 
         self._queue_manager.reset()
         handle = Request()
-        handle.transaction_id = self._queue_manager.getNextTID() # pylint: disable=attribute-defined-outside-init
-        handle.message = b"testing" # pylint: disable=attribute-defined-outside-init
+        handle.transaction_id = self._queue_manager.getNextTID()  # pylint: disable=attribute-defined-outside-init
+        handle.message = b"testing"  # pylint: disable=attribute-defined-outside-init
         self._queue_manager.addTransaction(handle)
         result = self._queue_manager.getTransaction(handle.transaction_id)
         self.assertEqual(handle.message, result.message)
 
     def test_delete_fifo_transaction_manager_transaction(self):
-        """ Test the fifo transaction manager """
-        class Request: # pylint: disable=too-few-public-methods
-            """ Request. """
+        """Test the fifo transaction manager"""
+        class Request:  # pylint: disable=too-few-public-methods
+            """Request."""
 
         self._queue_manager.reset()
         handle = Request()
-        handle.transaction_id = self._queue_manager.getNextTID() # pylint: disable=attribute-defined-outside-init
-        handle.message = b"testing" # pylint: disable=attribute-defined-outside-init
+        handle.transaction_id = self._queue_manager.getNextTID()  # pylint: disable=attribute-defined-outside-init
+        handle.message = b"testing"  # pylint: disable=attribute-defined-outside-init
 
         self._queue_manager.addTransaction(handle)
         self._queue_manager.delTransaction(handle.transaction_id)
@@ -252,7 +252,7 @@ class Request: # pylint: disable=too-few-public-methods
     # TCP tests
     # ----------------------------------------------------------------------- #
     def test_tcp_framer_transaction_ready(self):
-        """ Test a tcp frame transaction """
+        """Test a tcp frame transaction"""
         msg = b"\x00\x01\x12\x34\x00\x04\xff\x02\x12\x34"
         self.assertFalse(self._tcp.isFrameReady())
         self.assertFalse(self._tcp.checkFrame())
@@ -265,7 +265,7 @@ def test_tcp_framer_transaction_ready(self):
         self.assertEqual(b'', self._ascii.getFrame())
 
     def test_tcp_framer_transaction_full(self):
-        """ Test a full tcp frame transaction """
+        """Test a full tcp frame transaction"""
         msg = b"\x00\x01\x12\x34\x00\x04\xff\x02\x12\x34"
         self._tcp.addToFrame(msg)
         self.assertTrue(self._tcp.checkFrame())
@@ -274,7 +274,7 @@ def test_tcp_framer_transaction_full(self):
         self._tcp.advanceFrame()
 
     def test_tcp_framer_transaction_half(self):
-        """ Test a half completed tcp frame transaction """
+        """Test a half completed tcp frame transaction"""
         msg1 = b"\x00\x01\x12\x34\x00"
         msg2 = b"\x04\xff\x02\x12\x34"
         self._tcp.addToFrame(msg1)
@@ -288,7 +288,7 @@ def test_tcp_framer_transaction_half(self):
         self._tcp.advanceFrame()
 
     def test_tcp_framer_transaction_half2(self):
-        """ Test a half completed tcp frame transaction """
+        """Test a half completed tcp frame transaction"""
         msg1 = b"\x00\x01\x12\x34\x00\x04\xff"
         msg2 = b"\x02\x12\x34"
         self._tcp.addToFrame(msg1)
@@ -302,7 +302,7 @@ def test_tcp_framer_transaction_half2(self):
         self._tcp.advanceFrame()
 
     def test_tcp_framer_transaction_half3(self):
-        """ Test a half completed tcp frame transaction """
+        """Test a half completed tcp frame transaction"""
         msg1 = b"\x00\x01\x12\x34\x00\x04\xff\x02\x12"
         msg2 = b"\x34"
         self._tcp.addToFrame(msg1)
@@ -316,7 +316,7 @@ def test_tcp_framer_transaction_half3(self):
         self._tcp.advanceFrame()
 
     def test_tcp_framer_transaction_short(self):
-        """ Test that we can get back on track after an invalid message """
+        """Test that we can get back on track after an invalid message"""
         msg1 = b"\x99\x99\x99\x99\x00\x01\x00\x01"
         msg2 = b"\x00\x01\x12\x34\x00\x04\xff\x02\x12\x34"
         self._tcp.addToFrame(msg1)
@@ -325,18 +325,18 @@ def test_tcp_framer_transaction_short(self):
         self.assertEqual(b'', result)
         self._tcp.advanceFrame()
         self._tcp.addToFrame(msg2)
-        self.assertEqual(10, len(self._tcp._buffer)) # pylint: disable=protected-access
+        self.assertEqual(10, len(self._tcp._buffer))  # pylint: disable=protected-access
         self.assertTrue(self._tcp.checkFrame())
         result = self._tcp.getFrame()
         self.assertEqual(msg2[7:], result)
         self._tcp.advanceFrame()
 
     def test_tcp_framer_populate(self):
-        """ Test a tcp frame packet build """
+        """Test a tcp frame packet build"""
         expected = ModbusRequest()
         expected.transaction_id = 0x0001
-        expected.protocol_id    = 0x1234
-        expected.unit_id        = 0xff
+        expected.protocol_id = 0x1234
+        expected.unit_id = 0xff
         msg = b"\x00\x01\x12\x34\x00\x04\xff\x02\x12\x34"
         self._tcp.addToFrame(msg)
         self.assertTrue(self._tcp.checkFrame())
@@ -347,14 +347,14 @@ def test_tcp_framer_populate(self):
         self._tcp.advanceFrame()
 
     def test_tcp_framer_packet(self):
-        """ Test a tcp frame packet build """
+        """Test a tcp frame packet build"""
         old_encode = ModbusRequest.encode
         ModbusRequest.encode = lambda self: b''
         message = ModbusRequest()
         message.transaction_id = 0x0001
-        message.protocol_id    = 0x1234
-        message.unit_id        = 0xff
-        message.function_code  = 0x01
+        message.protocol_id = 0x1234
+        message.unit_id = 0xff
+        message.function_code = 0x01
         expected = b"\x00\x01\x12\x34\x00\x02\xff\x01"
         actual = self._tcp.buildPacket(message)
         self.assertEqual(expected, actual)
@@ -364,7 +364,7 @@ def test_tcp_framer_packet(self):
     # TLS tests
     # ----------------------------------------------------------------------- #
     def framer_tls_framer_transaction_ready(self):
-        """ Test a tls frame transaction """
+        """Test a tls frame transaction"""
         msg = b"\x01\x12\x34\x00\x08"
         self.assertFalse(self._tls.isFrameReady())
         self.assertFalse(self._tls.checkFrame())
@@ -377,7 +377,7 @@ def framer_tls_framer_transaction_ready(self):
         self.assertEqual(b'', self._tls.getFrame())
 
     def framer_tls_framer_transaction_full(self):
-        """ Test a full tls frame transaction """
+        """Test a full tls frame transaction"""
         msg = b"\x01\x12\x34\x00\x08"
         self._tls.addToFrame(msg)
         self.assertTrue(self._tls.checkFrame())
@@ -386,7 +386,7 @@ def framer_tls_framer_transaction_full(self):
         self._tls.advanceFrame()
 
     def framer_tls_framer_transaction_half(self):
-        """ Test a half completed tls frame transaction """
+        """Test a half completed tls frame transaction"""
         msg1 = b""
         msg2 = b"\x01\x12\x34\x00\x08"
         self._tls.addToFrame(msg1)
@@ -400,7 +400,7 @@ def framer_tls_framer_transaction_half(self):
         self._tls.advanceFrame()
 
     def framer_tls_framer_transaction_short(self):
-        """ Test that we can get back on track after an invalid message """
+        """Test that we can get back on track after an invalid message"""
         msg1 = b""
         msg2 = b"\x01\x12\x34\x00\x08"
         self._tls.addToFrame(msg1)
@@ -409,14 +409,14 @@ def framer_tls_framer_transaction_short(self):
         self.assertEqual(b'', result)
         self._tls.advanceFrame()
         self._tls.addToFrame(msg2)
-        self.assertEqual(5, len(self._tls._buffer)) # pylint: disable=protected-access
+        self.assertEqual(5, len(self._tls._buffer))  # pylint: disable=protected-access
         self.assertTrue(self._tls.checkFrame())
         result = self._tls.getFrame()
         self.assertEqual(msg2[0:], result)
         self._tls.advanceFrame()
 
     def framer_tls_framer_decode(self):
-        """ Testmessage decoding """
+        """Testmessage decoding"""
         msg1 = b""
         msg2 = b"\x01\x12\x34\x00\x08"
         result = self._tls.decode_data(msg1)
@@ -426,71 +426,72 @@ def framer_tls_framer_decode(self):
         self._tls.advanceFrame()
 
     def framer_tls_incoming_packet(self):
-        """ Framer tls incoming packet. """
+        """Framer tls incoming packet."""
         msg = b"\x01\x12\x34\x00\x08"
 
         unit = 0x01
-        def mock_callback(self): # pylint: disable=unused-argument
-            """ Mock callback. """
 
-        self._tls._process = MagicMock() # pylint: disable=protected-access
+        def mock_callback(self):  # pylint: disable=unused-argument
+            """Mock callback."""
+
+        self._tls._process = MagicMock()  # pylint: disable=protected-access
         self._tls.isFrameReady = MagicMock(return_value=False)
         self._tls.processIncomingPacket(msg, mock_callback, unit)
         self.assertEqual(msg, self._tls.getRawFrame())
         self._tls.advanceFrame()
 
         self._tls.isFrameReady = MagicMock(return_value=True)
-        self._tls._validate_unit_id = MagicMock(return_value=False) # pylint: disable=protected-access
+        self._tls._validate_unit_id = MagicMock(return_value=False)  # pylint: disable=protected-access
         self._tls.processIncomingPacket(msg, mock_callback, unit)
         self.assertEqual(b'', self._tls.getRawFrame())
         self._tls.advanceFrame()
 
-        self._tls._validate_unit_id = MagicMock(return_value=True) # pylint: disable=protected-access
+        self._tls._validate_unit_id = MagicMock(return_value=True)  # pylint: disable=protected-access
         self._tls.processIncomingPacket(msg, mock_callback, unit)
         self.assertEqual(msg, self._tls.getRawFrame())
         self._tls.advanceFrame()
 
     def framer_tls_process(self):
-        """ Framer tls process. """
-        class MockResult: # pylint: disable=too-few-public-methods
-            """ Mock result. """
+        """Framer tls process."""
+        class MockResult:  # pylint: disable=too-few-public-methods
+            """Mock result."""
 
             def __init__(self, code):
-                """ Init. """
+                """Init."""
                 self.function_code = code
 
-        def mock_callback(self): # pylint: disable=unused-argument
-            """ Mock callback. """
+        def mock_callback(self):  # pylint: disable=unused-argument
+            """Mock callback."""
 
         self._tls.decoder.decode = MagicMock(return_value=None)
         self.assertRaises(ModbusIOException,
-                          lambda: self._tls._process(mock_callback)) # pylint: disable=protected-access
+                          lambda: self._tls._process(mock_callback))  # pylint: disable=protected-access
 
         result = MockResult(0x01)
         self._tls.decoder.decode = MagicMock(return_value=result)
         self.assertRaises(InvalidMessageReceivedException,
-                          lambda: self._tls._process(mock_callback, error=True)) # pylint: disable=protected-access
+                          lambda: self._tls._process(mock_callback, error=True))  # pylint: disable=protected-access
 
-        self._tls._process(mock_callback) # pylint: disable=protected-access
+        self._tls._process(mock_callback)  # pylint: disable=protected-access
         self.assertEqual(b'', self._tls.getRawFrame())
 
     def framer_tls_framer_populate(self):
-        """ Test a tls frame packet build """
+        """Test a tls frame packet build"""
         ModbusRequest()
         msg = b"\x01\x12\x34\x00\x08"
         self._tls.addToFrame(msg)
         self.assertTrue(self._tls.checkFrame())
         actual = ModbusRequest()
-        result = self._tls.populateResult(actual) # pylint: disable=assignment-from-none
+        result = self._tls.populateResult(actual)  # pylint: disable=assignment-from-none
         self.assertEqual(None, result)
         self._tls.advanceFrame()
 
     def framer_tls_framer_packet(self):
-        """ Test a tls frame packet build """
+        """Test a tls frame packet build"""
         old_encode = ModbusRequest.encode
         ModbusRequest.encode = lambda self: b''
         message = ModbusRequest()
-        message.function_code  = 0x01
+        message.function_code = 0x01
         expected = b"\x01"
         actual = self._tls.buildPacket(message)
         self.assertEqual(expected, actual)
@@ -500,7 +501,7 @@ def framer_tls_framer_packet(self):
     # RTU tests
     # ----------------------------------------------------------------------- #
     def test_rtu_framer_transaction_ready(self):
-        """ Test if the checks for a complete frame work """
+        """Test if the checks for a complete frame work"""
         self.assertFalse(self._rtu.isFrameReady())
 
         msg_parts = [b"\x00\x01\x00", b"\x00\x00\x01\xfc\x1b"]
@@ -513,7 +514,7 @@ def test_rtu_framer_transaction_ready(self):
         self.assertTrue(self._rtu.checkFrame())
 
     def test_rtu_framer_transaction_full(self):
-        """ Test a full rtu frame transaction """
+        """Test a full rtu frame transaction"""
         msg = b"\x00\x01\x00\x00\x00\x01\xfc\x1b"
         stripped_msg = msg[1:-2]
         self._rtu.addToFrame(msg)
@@ -523,7 +524,7 @@ def test_rtu_framer_transaction_full(self):
         self._rtu.advanceFrame()
 
     def test_rtu_framer_transaction_half(self):
-        """ Test a half completed rtu frame transaction """
+        """Test a half completed rtu frame transaction"""
         msg_parts = [b"\x00\x01\x00", b"\x00\x00\x01\xfc\x1b"]
         stripped_msg = b"".join(msg_parts)[1:-2]
         self._rtu.addToFrame(msg_parts[0])
@@ -536,14 +537,14 @@ def test_rtu_framer_transaction_half(self):
         self._rtu.advanceFrame()
 
     def test_rtu_framer_populate(self):
-        """ Test a rtu frame packet build """
+        """Test a rtu frame packet build"""
         request = ModbusRequest()
         msg = b"\x00\x01\x00\x00\x00\x01\xfc\x1b"
         self._rtu.addToFrame(msg)
         self._rtu.populateHeader()
         self._rtu.populateResult(request)
 
-        header_dict = self._rtu._header # pylint: disable=protected-access
+        header_dict = self._rtu._header  # pylint: disable=protected-access
         self.assertEqual(len(msg), header_dict['len'])
         self.assertEqual(int(msg[0]), header_dict['uid'])
         self.assertEqual(msg[-2:], header_dict['crc'])
@@ -551,33 +552,34 @@ def test_rtu_framer_populate(self):
         self.assertEqual(0x00, request.unit_id)
 
     def test_rtu_framer_packet(self):
-        """ Test a rtu frame packet build """
+        """Test a rtu frame packet build"""
         old_encode = ModbusRequest.encode
         ModbusRequest.encode = lambda self: b''
         message = ModbusRequest()
-        message.unit_id        = 0xff
-        message.function_code  = 0x01
-        expected = b"\xff\x01\x81\x80" # only header + CRC - no data
+        message.unit_id = 0xff
+        message.function_code = 0x01
+        expected = b"\xff\x01\x81\x80"  # only header + CRC - no data
         actual = self._rtu.buildPacket(message)
         self.assertEqual(expected, actual)
         ModbusRequest.encode = old_encode
 
     def test_rtu_decode_exception(self):
-        """ Test that the RTU framer can decode errors """
+        """Test that the RTU framer can decode errors"""
         message = b"\x00\x90\x02\x9c\x01"
         self._rtu.addToFrame(message)
         result = self._rtu.checkFrame()
         self.assertTrue(result)
 
     def test_process(self):
-        """ Test process. """
-        class MockResult: # pylint: disable=too-few-public-methods
-            """ Mock result. """
+        """Test process."""
+        class MockResult:  # pylint: disable=too-few-public-methods
+            """Mock result."""
+
             def __init__(self, code):
                 self.function_code = code
 
-        def mock_callback(self): # pylint: disable=unused-argument
-            """ Mock callback. """
+        def mock_callback(self):  # pylint: disable=unused-argument
+            """Mock callback."""
 
         mock_result = MockResult(code=0)
         self._rtu.getRawFrame = self._rtu.getFrame = MagicMock()
@@ -586,26 +588,28 @@ def mock_callback(self): # pylint: disable=unused-argument
         self._rtu.populateResult = MagicMock()
         self._rtu.advanceFrame = MagicMock()
 
-        self._rtu._process(mock_callback) # pylint: disable=protected-access
+        self._rtu._process(mock_callback)  # pylint: disable=protected-access
         self._rtu.populateResult.assert_called_with(mock_result)
         self._rtu.advanceFrame.assert_called_with()
         self.assertTrue(self._rtu.advanceFrame.called)
 
-        #Check errors
+        # Check errors
         self._rtu.decoder.decode = MagicMock(return_value=None)
-        self.assertRaises(ModbusIOException, lambda: self._rtu._process(mock_callback)) # pylint: disable=protected-access
+        self.assertRaises(ModbusIOException, lambda: self._rtu._process(  # pylint: disable=protected-access
+            mock_callback))
 
     def test_rtu_process_incoming_packets(self):
-        """ Test rtu process incoming packets. """
+        """Test rtu process incoming packets."""
         mock_data = b"\x00\x01\x00\x00\x00\x01\xfc\x1b"
         unit = 0x00
-        def mock_callback(self): # pylint: disable=unused-argument
-            """ Mock callback. """
+
+        def mock_callback(self):  # pylint: disable=unused-argument
+            """Mock callback."""
 
         self._rtu.addToFrame = MagicMock()
-        self._rtu._process = MagicMock() # pylint: disable=protected-access
+        self._rtu._process = MagicMock()  # pylint: disable=protected-access
         self._rtu.isFrameReady = MagicMock(return_value=False)
-        self._rtu._buffer = mock_data # pylint: disable=protected-access
+        self._rtu._buffer = mock_data  # pylint: disable=protected-access
 
         self._rtu.processIncomingPacket(mock_data, mock_callback, unit)
 
@@ -613,7 +617,7 @@ def mock_callback(self): # pylint: disable=unused-argument
     # ASCII tests
     # ----------------------------------------------------------------------- #
     def test_ascii_framer_transaction_ready(self):
-        """ Test a ascii frame transaction """
+        """Test a ascii frame transaction"""
         msg = b':F7031389000A60\r\n'
         self.assertFalse(self._ascii.isFrameReady())
         self.assertFalse(self._ascii.checkFrame())
@@ -626,7 +630,7 @@ def test_ascii_framer_transaction_ready(self):
         self.assertEqual(b'', self._ascii.getFrame())
 
     def test_ascii_framer_transaction_full(self):
-        """ Test a full ascii frame transaction """
+        """Test a full ascii frame transaction"""
         msg = b'sss:F7031389000A60\r\n'
         pack = a2b_hex(msg[6:-4])
         self._ascii.addToFrame(msg)
@@ -636,7 +640,7 @@ def test_ascii_framer_transaction_full(self):
         self._ascii.advanceFrame()
 
     def test_ascii_framer_transaction_half(self):
-        """ Test a half completed ascii frame transaction """
+        """Test a half completed ascii frame transaction"""
         msg1 = b'sss:F7031389'
         msg2 = b'000A60\r\n'
         pack = a2b_hex(msg1[6:] + msg2[:-4])
@@ -651,29 +655,30 @@ def test_ascii_framer_transaction_half(self):
         self._ascii.advanceFrame()
 
     def test_ascii_framer_populate(self):
-        """ Test a ascii frame packet build """
+        """Test a ascii frame packet build"""
         request = ModbusRequest()
         self._ascii.populateResult(request)
         self.assertEqual(0x00, request.unit_id)
 
     def test_ascii_framer_packet(self):
-        """ Test a ascii frame packet build """
+        """Test a ascii frame packet build"""
         old_encode = ModbusRequest.encode
         ModbusRequest.encode = lambda self: b''
         message = ModbusRequest()
-        message.unit_id        = 0xff
-        message.function_code  = 0x01
+        message.unit_id = 0xff
+        message.function_code = 0x01
         expected = b":FF0100\r\n"
         actual = self._ascii.buildPacket(message)
         self.assertEqual(expected, actual)
         ModbusRequest.encode = old_encode
 
     def test_ascii_process_incoming_packets(self):
-        """ Test ascii process incoming packet. """
+        """Test ascii process incoming packet."""
         mock_data = b':F7031389000A60\r\n'
         unit = 0x00
-        def mock_callback(mock_data, *args, **kwargs): # pylint: disable=unused-argument
-            """ Mock callback. """
+
+        def mock_callback(mock_data, *args, **kwargs):  # pylint: disable=unused-argument
+            """Mock callback."""
 
         self._ascii.processIncomingPacket(mock_data, mock_callback, unit)
 
@@ -685,8 +690,8 @@ def mock_callback(mock_data, *args, **kwargs): # pylint: disable=unused-argument
     # Binary tests
     # ----------------------------------------------------------------------- #
     def test_binary_framer_transaction_ready(self):
-        """ Test a binary frame transaction """
-        msg  = b'\x7b\x01\x03\x00\x00\x00\x05\x85\xC9\x7d'
+        """Test a binary frame transaction"""
+        msg = b'\x7b\x01\x03\x00\x00\x00\x05\x85\xC9\x7d'
         self.assertFalse(self._binary.isFrameReady())
         self.assertFalse(self._binary.checkFrame())
         self._binary.addToFrame(msg)
@@ -698,8 +703,8 @@ def test_binary_framer_transaction_ready(self):
         self.assertEqual(b'', self._binary.getFrame())
 
     def test_binary_framer_transaction_full(self):
-        """ Test a full binary frame transaction """
-        msg  = b'\x7b\x01\x03\x00\x00\x00\x05\x85\xC9\x7d'
+        """Test a full binary frame transaction"""
+        msg = b'\x7b\x01\x03\x00\x00\x00\x05\x85\xC9\x7d'
         pack = msg[2:-3]
         self._binary.addToFrame(msg)
         self.assertTrue(self._binary.checkFrame())
@@ -708,7 +713,7 @@ def test_binary_framer_transaction_full(self):
         self._binary.advanceFrame()
 
     def test_binary_framer_transaction_half(self):
-        """ Test a half completed binary frame transaction """
+        """Test a half completed binary frame transaction"""
         msg1 = b'\x7b\x01\x03\x00'
         msg2 = b'\x00\x00\x05\x85\xC9\x7d'
         pack = msg1[2:] + msg2[:-3]
@@ -723,28 +728,29 @@ def test_binary_framer_transaction_half(self):
         self._binary.advanceFrame()
 
     def test_binary_framer_populate(self):
-        """ Test a binary frame packet build """
+        """Test a binary frame packet build"""
         request = ModbusRequest()
         self._binary.populateResult(request)
         self.assertEqual(0x00, request.unit_id)
 
     def test_binary_framer_packet(self):
-        """ Test a binary frame packet build """
+        """Test a binary frame packet build"""
         old_encode = ModbusRequest.encode
         ModbusRequest.encode = lambda self: b''
         message = ModbusRequest()
-        message.unit_id        = 0xff
-        message.function_code  = 0x01
+        message.unit_id = 0xff
+        message.function_code = 0x01
         expected = b'\x7b\xff\x01\x81\x80\x7d'
         actual = self._binary.buildPacket(message)
         self.assertEqual(expected, actual)
         ModbusRequest.encode = old_encode
 
     def test_binary_process_incoming_packet(self):
-        """ Test binary process incoming packet. """
+        """Test binary process incoming packet."""
         mock_data = b'\x7b\x01\x03\x00\x00\x00\x05\x85\xC9\x7d'
         unit = 0x00
-        def mock_callback(mock_data): # pylint: disable=unused-argument
+
+        def mock_callback(mock_data):  # pylint: disable=unused-argument
             pass
 
         self._binary.processIncomingPacket(mock_data, mock_callback, unit)
diff --git a/test/test_utilities.py b/test/test_utilities.py
index c9c9900e9..5b2d264cd 100644
--- a/test/test_utilities.py
+++ b/test/test_utilities.py
@@ -1,43 +1,47 @@
 #!/usr/bin/env python3
-""" Test utilities. """
+"""Test utilities."""
 import unittest
 import struct
 from pymodbus.utilities import pack_bitstring, unpack_bitstring
 from pymodbus.utilities import checkCRC, checkLRC
 from pymodbus.utilities import dict_property, default
 
-_test_master = {4 : 'd'}
-class DictPropertyTester: # pylint: disable=too-few-public-methods
-    """ Dictionary property test. """
+_test_master = {4: 'd'}
+
+
+class DictPropertyTester:  # pylint: disable=too-few-public-methods
+    """Dictionary property test."""
+
     def __init__(self):
-        self.test   = {1 : 'a'}
-        self._test  = {2 : 'b'}
-        self.__test = {3 : 'c'} #NOSONAR pylint: disable=unused-private-member
+        """Initialize."""
+        self.test = {1: 'a'}
+        self._test = {2: 'b'}
+        self.__test = {3: 'c'}  # NOSONAR pylint: disable=unused-private-member
 
     l_1 = dict_property(lambda s: s.test, 1)
-    l_2 = dict_property(lambda s: s._test, 2) # pylint: disable=protected-access
-    l_3 = dict_property(lambda s: s.__test, 3) # pylint: disable=protected-access
+    l_2 = dict_property(lambda s: s._test, 2)  # pylint: disable=protected-access
+    l_3 = dict_property(lambda s: s.__test, 3)  # pylint: disable=protected-access
     s_1 = dict_property('test', 1)
     s_2 = dict_property('_test', 2)
     g_1 = dict_property(_test_master, 4)
 
 
 class SimpleUtilityTest(unittest.TestCase):
-    """ Unittest for the pymod.utilities module. """
+    """Unittest for the pymod.utilities module."""
 
     def setUp(self):
-        """ Initializes the test environment """
+        """Initialize the test environment"""
         self.data = struct.pack('>HHHH', 0x1234, 0x2345, 0x3456, 0x4567)
         self.string = b"test the computation"
         self.bits = [True, False, True, False, True, False, True, False]
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
         del self.bits
         del self.string
 
     def test_dict_property(self):
-        """ Test all string <=> bit packing functions """
+        """Test all string <=> bit packing functions"""
         result = DictPropertyTester()
         self.assertEqual(result.l_1, 'a')
         self.assertEqual(result.l_2, 'b')
@@ -57,32 +61,33 @@ def test_dict_property(self):
         self.assertEqual(result.g_1, 'x')
 
     def test_default_value(self):
-        """ Test all string <=> bit packing functions """
+        """Test all string <=> bit packing functions"""
         self.assertEqual(default(1), 0)
         self.assertEqual(default(1.1), 0.0)
-        self.assertEqual(default(1+1j), 0j)
+        self.assertEqual(default(1 + 1j), 0j)
         self.assertEqual(default('string'), '')
-        self.assertEqual(default([1,2,3]), [])
-        self.assertEqual(default({1:1}), {})
+        self.assertEqual(default([1, 2, 3]), [])
+        self.assertEqual(default({1: 1}), {})
         self.assertEqual(default(True), False)
 
     def test_bit_packing(self):
-        """ Test all string <=> bit packing functions """
+        """Test all string <=> bit packing functions"""
         self.assertEqual(unpack_bitstring(b'\x55'), self.bits)
         self.assertEqual(pack_bitstring(self.bits), b'\x55')
 
     def test_longitudinal_redundancycheck(self):
-        """ Test the longitudinal redundancy check code """
+        """Test the longitudinal redundancy check code"""
         self.assertTrue(checkLRC(self.data, 0x1c))
         self.assertTrue(checkLRC(self.string, 0x0c))
 
     def test_cyclic_redundancy_check(self):
-        """ Test the cyclic redundancy check code """
+        """Test the cyclic redundancy check code"""
         self.assertTrue(checkCRC(self.data, 0xe2db))
         self.assertTrue(checkCRC(self.string, 0x889e))
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/test_version.py b/test/test_version.py
index 532f38ab8..2ca99f1bd 100644
--- a/test/test_version.py
+++ b/test/test_version.py
@@ -1,25 +1,27 @@
 #!/usr/bin/env python3
-""" Test version. """
+"""Test version."""
 import unittest
 from pymodbus.version import Version
 
+
 class ModbusVersionTest(unittest.TestCase):
-    """ Unittest for the pymodbus._version code. """
+    """Unittest for the pymodbus._version code."""
 
     def setUp(self):
-        """ Initializes the test environment """
+        """Initialize the test environment"""
 
     def tearDown(self):
-        """ Cleans up the test environment """
+        """Clean up the test environment"""
 
     def test_version_class(self):
-        """ Test version class. """
-        version = Version('test', 1,2,3, "sometag")
+        """Test version class."""
+        version = Version('test', 1, 2, 3, "sometag")
         self.assertEqual(version.short(), '1.2.3.sometag')
         self.assertEqual(str(version), '[test, version 1.2.3.sometag]')
 
-#---------------------------------------------------------------------------#
-# Main
-#---------------------------------------------------------------------------#
+
+# ---------------------------------------------------------------------------#
+#  Main
+# ---------------------------------------------------------------------------#
 if __name__ == "__main__":
     unittest.main()
diff --git a/tox.ini b/tox.ini
index 7167d74e3..2598e4e46 100644
--- a/tox.ini
+++ b/tox.ini
@@ -73,10 +73,3 @@ commands =
     coverage combine coverage_reports
     coverage report --fail-under=85 --ignore-errors
 
-[flake8]
-exclude = .tox
-ignore = D211,D400,E731
-max-line-length = 120
-
-[pylint]
-