prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  How to test adapter.connection calls
  Some instruments call the adapter's `connection`property, like #697 which makes ProtocolAdapter fail. Instruments should not be adjusted to make the ProtocolAdapter work.
  
  The problem is, that you are not supposed to use normally the adapter's connection directly, because the `connection` depends on the specific adapter type. If an instrument calls the connection, the ProtocolAdapter fails. Instruments should not be adjusted to make the ProtocolAdapter work.
  
  Two solutions:
  
  - A generic mock connection seems good, because that would care for many use cases. Otherwise we had to add several methods (clear, close, timeout property, get_stb...) individually.
  - Or we could add timeout as a property to the `Adapter`, which will call its connection depending on the Adapter type (ProtocolAdapter stores it as a variable). Similarly the "read_stb" and `clear` etc.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `pymeasure/adapters/protocol.py`
  Content:
  ```
  1 #
  2 # This file is part of the PyMeasure package.
  3 #
  4 # Copyright (c) 2013-2022 PyMeasure Developers
  5 #
  6 # Permission is hereby granted, free of charge, to any person obtaining a copy
  7 # of this software and associated documentation files (the "Software"), to deal
  8 # in the Software without restriction, including without limitation the rights
  9 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 # copies of the Software, and to permit persons to whom the Software is
  11 # furnished to do so, subject to the following conditions:
  12 #
  13 # The above copyright notice and this permission notice shall be included in
  14 # all copies or substantial portions of the Software.
  15 #
  16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 # THE SOFTWARE.
  23 #
  24 
  25 import logging
  26 
  27 from .adapter import Adapter
  28 
  29 log = logging.getLogger(__name__)
  30 log.addHandler(logging.NullHandler())
  31 
  32 
  33 def to_bytes(command):
  34     """Change `command` to a bytes object"""
  35     if isinstance(command, (bytes, bytearray)):
  36         return command
  37     elif command is None:
  38         return b""
  39     elif isinstance(command, str):
  40         return command.encode("utf-8")
  41     elif isinstance(command, (list, tuple)):
  42         return bytes(command)
  43     elif isinstance(command, (int, float)):
  44         return str(command).encode("utf-8")
  45     raise TypeError(f"Invalid input of type {type(command).__name__}.")
  46 
  47 
  48 class ProtocolAdapter(Adapter):
  49     """ Adapter class for testing the command exchange protocol without instrument hardware.
  50 
  51     This adapter is primarily meant for use within :func:`pymeasure.test.expected_protocol()`.
  52 
  53     :param list comm_pairs: List of "reference" message pair tuples. The first element is
  54         what is sent to the instrument, the second one is the returned message.
  55         'None' indicates that a pair member (write or read) does not exist.
  56         The messages do **not** include the termination characters.
  57     """
  58 
  59     def __init__(self, comm_pairs=[], preprocess_reply=None, **kwargs):
  60         """Generate the adapter and initialize internal buffers."""
  61         super().__init__(preprocess_reply=preprocess_reply, **kwargs)
  62         assert isinstance(comm_pairs, (list, tuple)), (
  63             "Parameter comm_pairs has to be a list or tuple.")
  64         for pair in comm_pairs:
  65             if len(pair) != 2:
  66                 raise ValueError(f'Comm_pairs element {pair} does not have two elements!')
  67         self._read_buffer = b""
  68         self._write_buffer = b""
  69         self.comm_pairs = comm_pairs
  70         self._index = 0
  71 
  72     def _write(self, command, **kwargs):
  73         """Compare the command with the expected one and fill the read."""
  74         self._write_bytes(to_bytes(command))
  75         assert self._write_buffer == b"", (
  76             f"Written bytes '{self._write_buffer}' do not match expected "
  77             f"'{self.comm_pairs[self._index][0]}'.")
  78 
  79     def _write_bytes(self, content, **kwargs):
  80         """Write the bytes `content`. If a command is full, fill the read."""
  81         self._write_buffer += content
  82         try:
  83             p_write, p_read = self.comm_pairs[self._index]
  84         except IndexError:
  85             raise ValueError(f"No communication pair left to write {content}.")
  86         if self._write_buffer == to_bytes(p_write):
  87             assert self._read_buffer == b"", (
  88                 f"Unread response '{self._read_buffer}' present when writing. "
  89                 "Maybe a property's 'check_set_errors' is not accounted for, "
  90                 "a read() call is missing in a method, or the defined protocol is incorrect?"
  91             )
  92             # Clear the write buffer
  93             self._write_buffer = b""
  94             self._read_buffer = to_bytes(p_read)
  95             self._index += 1
  96         # If _write_buffer does _not_ agree with p_write, this is not cause for
  97         # concern, because you can in principle compose a message over several writes.
  98         # It's not clear how relevant this is in real-world use, but it's analogous
  99         # to the possibility to fetch a (binary) message over several reads.
  100 
  101     def _read(self, **kwargs):
  102         """Return an already present or freshly fetched read buffer as a string."""
  103         return self._read_bytes(-1).decode("utf-8")
  104 
  105     def _read_bytes(self, count, **kwargs):
  106         """Read `count` number of bytes from the buffer.
  107 
  108         :param int count: Number of bytes to read. If -1, return the buffer.
  109         """
  110         if self._read_buffer:
  111             if count == -1:
  112                 read = self._read_buffer
  113                 self._read_buffer = b""
  114             else:
  115                 read = self._read_buffer[:count]
  116                 self._read_buffer = self._read_buffer[count:]
  117             return read
  118         else:
  119             try:
  120                 p_write, p_read = self.comm_pairs[self._index]
  121             except IndexError:
  122                 raise ValueError("No communication pair left for reading.")
  123             assert p_write is None, (
  124                 f"Written {self._write_buffer} do not match expected {p_write} prior to read."
  125                 if self._write_buffer
  126                 else "Unexpected read without prior write.")
  127             self._index += 1
  128             if count == -1:
  129                 # _read_buffer is already empty, no action required.
  130                 return to_bytes(p_read)
  131             else:
  132                 self._read_buffer = to_bytes(p_read)[count:]
  133                 return to_bytes(p_read)[:count]
  134
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/pymeasure/adapters/protocol.py b/pymeasure/adapters/protocol.py
  --- a/pymeasure/adapters/protocol.py
  +++ b/pymeasure/adapters/protocol.py
  @@ -23,6 +23,7 @@
   #
   
   import logging
  +from unittest.mock import MagicMock
   
   from .adapter import Adapter
   
  @@ -50,15 +51,29 @@
   
       This adapter is primarily meant for use within :func:`pymeasure.test.expected_protocol()`.
   
  +    The :attr:`connection` attribute is a :class:`unittest.mock.MagicMock` such
  +    that every call returns. If you want to set a return value, you can use
  +    :code:`adapter.connection.some_method.return_value = 7`,
  +    such that a call to :code:`adapter.connection.some_method()` will return `7`.
  +    Similarly, you can verify that this call to the connection method happened
  +    with :code:`assert adapter.connection.some_method.called is True`.
  +    You can specify dictionaries with return values of attributes and methods.
  +
       :param list comm_pairs: List of "reference" message pair tuples. The first element is
           what is sent to the instrument, the second one is the returned message.
           'None' indicates that a pair member (write or read) does not exist.
           The messages do **not** include the termination characters.
  +    :param connection_attributes: Dictionary of connection attributes and their values.
  +    :param connection_methods: Dictionary of method names of the connection and their return values.
       """
   
  -    def __init__(self, comm_pairs=[], preprocess_reply=None, **kwargs):
  +    def __init__(self, comm_pairs=[], preprocess_reply=None,
  +                 connection_attributes={},
  +                 connection_methods={},
  +                 **kwargs):
           """Generate the adapter and initialize internal buffers."""
           super().__init__(preprocess_reply=preprocess_reply, **kwargs)
  +        # Setup communication
           assert isinstance(comm_pairs, (list, tuple)), (
               "Parameter comm_pairs has to be a list or tuple.")
           for pair in comm_pairs:
  @@ -68,6 +83,15 @@
           self._write_buffer = b""
           self.comm_pairs = comm_pairs
           self._index = 0
  +        # Setup attributes
  +        self._setup_connection(connection_attributes, connection_methods)
  +
  +    def _setup_connection(self, connection_attributes, connection_methods):
  +        self.connection = MagicMock()
  +        for key, value in connection_attributes.items():
  +            setattr(self.connection, key, value)
  +        for key, value in connection_methods.items():
  +            getattr(self.connection, key).return_value = value
   
       def _write(self, command, **kwargs):
           """Compare the command with the expected one and fill the read."""
  
verification_info: {"golden_diff": "diff --git a/pymeasure/adapters/protocol.py b/pymeasure/adapters/protocol.py\n--- a/pymeasure/adapters/protocol.py\n+++ b/pymeasure/adapters/protocol.py\n@@ -23,6 +23,7 @@\n #\n \n import logging\n+from unittest.mock import MagicMock\n \n from .adapter import Adapter\n \n@@ -50,15 +51,29 @@\n \n     This adapter is primarily meant for use within :func:`pymeasure.test.expected_protocol()`.\n \n+    The :attr:`connection` attribute is a :class:`unittest.mock.MagicMock` such\n+    that every call returns. If you want to set a return value, you can use\n+    :code:`adapter.connection.some_method.return_value = 7`,\n+    such that a call to :code:`adapter.connection.some_method()` will return `7`.\n+    Similarly, you can verify that this call to the connection method happened\n+    with :code:`assert adapter.connection.some_method.called is True`.\n+    You can specify dictionaries with return values of attributes and methods.\n+\n     :param list comm_pairs: List of \"reference\" message pair tuples. The first element is\n         what is sent to the instrument, the second one is the returned message.\n         'None' indicates that a pair member (write or read) does not exist.\n         The messages do **not** include the termination characters.\n+    :param connection_attributes: Dictionary of connection attributes and their values.\n+    :param connection_methods: Dictionary of method names of the connection and their return values.\n     \"\"\"\n \n-    def __init__(self, comm_pairs=[], preprocess_reply=None, **kwargs):\n+    def __init__(self, comm_pairs=[], preprocess_reply=None,\n+                 connection_attributes={},\n+                 connection_methods={},\n+                 **kwargs):\n         \"\"\"Generate the adapter and initialize internal buffers.\"\"\"\n         super().__init__(preprocess_reply=preprocess_reply, **kwargs)\n+        # Setup communication\n         assert isinstance(comm_pairs, (list, tuple)), (\n             \"Parameter comm_pairs has to be a list or tuple.\")\n         for pair in comm_pairs:\n@@ -68,6 +83,15 @@\n         self._write_buffer = b\"\"\n         self.comm_pairs = comm_pairs\n         self._index = 0\n+        # Setup attributes\n+        self._setup_connection(connection_attributes, connection_methods)\n+\n+    def _setup_connection(self, connection_attributes, connection_methods):\n+        self.connection = MagicMock()\n+        for key, value in connection_attributes.items():\n+            setattr(self.connection, key, value)\n+        for key, value in connection_methods.items():\n+            getattr(self.connection, key).return_value = value\n \n     def _write(self, command, **kwargs):\n         \"\"\"Compare the command with the expected one and fill the read.\"\"\"\n", "issue": "How to test adapter.connection calls\nSome instruments call the adapter's `connection`property, like #697 which makes ProtocolAdapter fail. Instruments should not be adjusted to make the ProtocolAdapter work.\r\n\r\nThe problem is, that you are not supposed to use normally the adapter's connection directly, because the `connection` depends on the specific adapter type. If an instrument calls the connection, the ProtocolAdapter fails. Instruments should not be adjusted to make the ProtocolAdapter work.\r\n\r\nTwo solutions:\r\n\r\n- A generic mock connection seems good, because that would care for many use cases. Otherwise we had to add several methods (clear, close, timeout property, get_stb...) individually.\r\n- Or we could add timeout as a property to the `Adapter`, which will call its connection depending on the Adapter type (ProtocolAdapter stores it as a variable). Similarly the \"read_stb\" and `clear` etc.\n", "before_files": [{"content": "#\n# This file is part of the PyMeasure package.\n#\n# Copyright (c) 2013-2022 PyMeasure Developers\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n#\n\nimport logging\n\nfrom .adapter import Adapter\n\nlog = logging.getLogger(__name__)\nlog.addHandler(logging.NullHandler())\n\n\ndef to_bytes(command):\n    \"\"\"Change `command` to a bytes object\"\"\"\n    if isinstance(command, (bytes, bytearray)):\n        return command\n    elif command is None:\n        return b\"\"\n    elif isinstance(command, str):\n        return command.encode(\"utf-8\")\n    elif isinstance(command, (list, tuple)):\n        return bytes(command)\n    elif isinstance(command, (int, float)):\n        return str(command).encode(\"utf-8\")\n    raise TypeError(f\"Invalid input of type {type(command).__name__}.\")\n\n\nclass ProtocolAdapter(Adapter):\n    \"\"\" Adapter class for testing the command exchange protocol without instrument hardware.\n\n    This adapter is primarily meant for use within :func:`pymeasure.test.expected_protocol()`.\n\n    :param list comm_pairs: List of \"reference\" message pair tuples. The first element is\n        what is sent to the instrument, the second one is the returned message.\n        'None' indicates that a pair member (write or read) does not exist.\n        The messages do **not** include the termination characters.\n    \"\"\"\n\n    def __init__(self, comm_pairs=[], preprocess_reply=None, **kwargs):\n        \"\"\"Generate the adapter and initialize internal buffers.\"\"\"\n        super().__init__(preprocess_reply=preprocess_reply, **kwargs)\n        assert isinstance(comm_pairs, (list, tuple)), (\n            \"Parameter comm_pairs has to be a list or tuple.\")\n        for pair in comm_pairs:\n            if len(pair) != 2:\n                raise ValueError(f'Comm_pairs element {pair} does not have two elements!')\n        self._read_buffer = b\"\"\n        self._write_buffer = b\"\"\n        self.comm_pairs = comm_pairs\n        self._index = 0\n\n    def _write(self, command, **kwargs):\n        \"\"\"Compare the command with the expected one and fill the read.\"\"\"\n        self._write_bytes(to_bytes(command))\n        assert self._write_buffer == b\"\", (\n            f\"Written bytes '{self._write_buffer}' do not match expected \"\n            f\"'{self.comm_pairs[self._index][0]}'.\")\n\n    def _write_bytes(self, content, **kwargs):\n        \"\"\"Write the bytes `content`. If a command is full, fill the read.\"\"\"\n        self._write_buffer += content\n        try:\n            p_write, p_read = self.comm_pairs[self._index]\n        except IndexError:\n            raise ValueError(f\"No communication pair left to write {content}.\")\n        if self._write_buffer == to_bytes(p_write):\n            assert self._read_buffer == b\"\", (\n                f\"Unread response '{self._read_buffer}' present when writing. \"\n                \"Maybe a property's 'check_set_errors' is not accounted for, \"\n                \"a read() call is missing in a method, or the defined protocol is incorrect?\"\n            )\n            # Clear the write buffer\n            self._write_buffer = b\"\"\n            self._read_buffer = to_bytes(p_read)\n            self._index += 1\n        # If _write_buffer does _not_ agree with p_write, this is not cause for\n        # concern, because you can in principle compose a message over several writes.\n        # It's not clear how relevant this is in real-world use, but it's analogous\n        # to the possibility to fetch a (binary) message over several reads.\n\n    def _read(self, **kwargs):\n        \"\"\"Return an already present or freshly fetched read buffer as a string.\"\"\"\n        return self._read_bytes(-1).decode(\"utf-8\")\n\n    def _read_bytes(self, count, **kwargs):\n        \"\"\"Read `count` number of bytes from the buffer.\n\n        :param int count: Number of bytes to read. If -1, return the buffer.\n        \"\"\"\n        if self._read_buffer:\n            if count == -1:\n                read = self._read_buffer\n                self._read_buffer = b\"\"\n            else:\n                read = self._read_buffer[:count]\n                self._read_buffer = self._read_buffer[count:]\n            return read\n        else:\n            try:\n                p_write, p_read = self.comm_pairs[self._index]\n            except IndexError:\n                raise ValueError(\"No communication pair left for reading.\")\n            assert p_write is None, (\n                f\"Written {self._write_buffer} do not match expected {p_write} prior to read.\"\n                if self._write_buffer\n                else \"Unexpected read without prior write.\")\n            self._index += 1\n            if count == -1:\n                # _read_buffer is already empty, no action required.\n                return to_bytes(p_read)\n            else:\n                self._read_buffer = to_bytes(p_read)[count:]\n                return to_bytes(p_read)[:count]\n", "path": "pymeasure/adapters/protocol.py"}], "after_files": [{"content": "#\n# This file is part of the PyMeasure package.\n#\n# Copyright (c) 2013-2022 PyMeasure Developers\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n#\n\nimport logging\nfrom unittest.mock import MagicMock\n\nfrom .adapter import Adapter\n\nlog = logging.getLogger(__name__)\nlog.addHandler(logging.NullHandler())\n\n\ndef to_bytes(command):\n    \"\"\"Change `command` to a bytes object\"\"\"\n    if isinstance(command, (bytes, bytearray)):\n        return command\n    elif command is None:\n        return b\"\"\n    elif isinstance(command, str):\n        return command.encode(\"utf-8\")\n    elif isinstance(command, (list, tuple)):\n        return bytes(command)\n    elif isinstance(command, (int, float)):\n        return str(command).encode(\"utf-8\")\n    raise TypeError(f\"Invalid input of type {type(command).__name__}.\")\n\n\nclass ProtocolAdapter(Adapter):\n    \"\"\" Adapter class for testing the command exchange protocol without instrument hardware.\n\n    This adapter is primarily meant for use within :func:`pymeasure.test.expected_protocol()`.\n\n    The :attr:`connection` attribute is a :class:`unittest.mock.MagicMock` such\n    that every call returns. If you want to set a return value, you can use\n    :code:`adapter.connection.some_method.return_value = 7`,\n    such that a call to :code:`adapter.connection.some_method()` will return `7`.\n    Similarly, you can verify that this call to the connection method happened\n    with :code:`assert adapter.connection.some_method.called is True`.\n    You can specify dictionaries with return values of attributes and methods.\n\n    :param list comm_pairs: List of \"reference\" message pair tuples. The first element is\n        what is sent to the instrument, the second one is the returned message.\n        'None' indicates that a pair member (write or read) does not exist.\n        The messages do **not** include the termination characters.\n    :param connection_attributes: Dictionary of connection attributes and their values.\n    :param connection_methods: Dictionary of method names of the connection and their return values.\n    \"\"\"\n\n    def __init__(self, comm_pairs=[], preprocess_reply=None,\n                 connection_attributes={},\n                 connection_methods={},\n                 **kwargs):\n        \"\"\"Generate the adapter and initialize internal buffers.\"\"\"\n        super().__init__(preprocess_reply=preprocess_reply, **kwargs)\n        # Setup communication\n        assert isinstance(comm_pairs, (list, tuple)), (\n            \"Parameter comm_pairs has to be a list or tuple.\")\n        for pair in comm_pairs:\n            if len(pair) != 2:\n                raise ValueError(f'Comm_pairs element {pair} does not have two elements!')\n        self._read_buffer = b\"\"\n        self._write_buffer = b\"\"\n        self.comm_pairs = comm_pairs\n        self._index = 0\n        # Setup attributes\n        self._setup_connection(connection_attributes, connection_methods)\n\n    def _setup_connection(self, connection_attributes, connection_methods):\n        self.connection = MagicMock()\n        for key, value in connection_attributes.items():\n            setattr(self.connection, key, value)\n        for key, value in connection_methods.items():\n            getattr(self.connection, key).return_value = value\n\n    def _write(self, command, **kwargs):\n        \"\"\"Compare the command with the expected one and fill the read.\"\"\"\n        self._write_bytes(to_bytes(command))\n        assert self._write_buffer == b\"\", (\n            f\"Written bytes '{self._write_buffer}' do not match expected \"\n            f\"'{self.comm_pairs[self._index][0]}'.\")\n\n    def _write_bytes(self, content, **kwargs):\n        \"\"\"Write the bytes `content`. If a command is full, fill the read.\"\"\"\n        self._write_buffer += content\n        try:\n            p_write, p_read = self.comm_pairs[self._index]\n        except IndexError:\n            raise ValueError(f\"No communication pair left to write {content}.\")\n        if self._write_buffer == to_bytes(p_write):\n            assert self._read_buffer == b\"\", (\n                f\"Unread response '{self._read_buffer}' present when writing. \"\n                \"Maybe a property's 'check_set_errors' is not accounted for, \"\n                \"a read() call is missing in a method, or the defined protocol is incorrect?\"\n            )\n            # Clear the write buffer\n            self._write_buffer = b\"\"\n            self._read_buffer = to_bytes(p_read)\n            self._index += 1\n        # If _write_buffer does _not_ agree with p_write, this is not cause for\n        # concern, because you can in principle compose a message over several writes.\n        # It's not clear how relevant this is in real-world use, but it's analogous\n        # to the possibility to fetch a (binary) message over several reads.\n\n    def _read(self, **kwargs):\n        \"\"\"Return an already present or freshly fetched read buffer as a string.\"\"\"\n        return self._read_bytes(-1).decode(\"utf-8\")\n\n    def _read_bytes(self, count, **kwargs):\n        \"\"\"Read `count` number of bytes from the buffer.\n\n        :param int count: Number of bytes to read. If -1, return the buffer.\n        \"\"\"\n        if self._read_buffer:\n            if count == -1:\n                read = self._read_buffer\n                self._read_buffer = b\"\"\n            else:\n                read = self._read_buffer[:count]\n                self._read_buffer = self._read_buffer[count:]\n            return read\n        else:\n            try:\n                p_write, p_read = self.comm_pairs[self._index]\n            except IndexError:\n                raise ValueError(\"No communication pair left for reading.\")\n            assert p_write is None, (\n                f\"Written {self._write_buffer} do not match expected {p_write} prior to read.\"\n                if self._write_buffer\n                else \"Unexpected read without prior write.\")\n            self._index += 1\n            if count == -1:\n                # _read_buffer is already empty, no action required.\n                return to_bytes(p_read)\n            else:\n                self._read_buffer = to_bytes(p_read)[count:]\n                return to_bytes(p_read)[:count]\n", "path": "pymeasure/adapters/protocol.py"}]}