# Path: librouteros/exceptions.py
# class ProtocolError(LibRouterosError):
#     """Raised when e.g. encoding/decoding fails."""
# 
# class FatalError(ProtocolError):
#     """Exception raised when !fatal is received."""
# 
# Path: librouteros/connections.py
# class SocketTransport:
# 
#     def __init__(self, sock: socket):
#         self.sock = sock
# 
#     def write(self, data: bytes) -> None:
#         """
#         Write given bytes to socket. Loop as long as every byte in
#         string is written unless exception is raised.
#         """
#         self.sock.sendall(data)
# 
#     def read(self, length: int) -> bytes:
#         """
#         Read as many bytes from socket as specified in length.
#         Loop as long as every byte is read unless exception is raised.
#         """
#         data = bytearray()
#         while len(data) != length:
#             data += self.sock.recv((length - len(data)))
#             if not data:
#                 raise ConnectionClosed('Connection unexpectedly closed.')
#         return data
# 
#     def close(self) -> None:
#         self.sock.close()


import typing
from struct import pack, unpack #pylint: disable=no-name-in-module
from logging import getLogger, NullHandler
from librouteros.exceptions import (
    ProtocolError,
    FatalError,
)
from librouteros.connections import SocketTransport
        self.encoding = encoding

    @staticmethod
    def log(direction_string: str, *sentence: str) -> None:
        for word in sentence:
            LOGGER.debug(f'{direction_string} {word!r}')
        LOGGER.debug(f'{direction_string} EOS')

    def writeSentence(self, cmd: str, *words: str) -> None:
        """
        Write encoded sentence.

        :param cmd: Command word.
        :param words: Aditional words.
        """
        encoded = self.encodeSentence(cmd, *words)
        self.log('<---', cmd, *words)
        self.transport.write(encoded)

    def readSentence(self) -> typing.Tuple[str, typing.Tuple[str, ...]]:
        """
        Read every word untill empty word (NULL byte) is received.

        :return: Reply word, tuple with read words.
        """
        sentence = tuple(word for word in iter(self.readWord, ''))
        self.log('--->', *sentence)
        reply_word, words = sentence[0], sentence[1:]
        if reply_word == '!fatal':
            self.transport.close()

# Path: librouteros/exceptions.py
# class ProtocolError(LibRouterosError):
#     """Raised when e.g. encoding/decoding fails."""
# 
# class FatalError(ProtocolError):
#     """Exception raised when !fatal is received."""
# 
# Path: librouteros/connections.py
# class SocketTransport:
# 
#     def __init__(self, sock: socket):
#         self.sock = sock
# 
#     def write(self, data: bytes) -> None:
#         """
#         Write given bytes to socket. Loop as long as every byte in
#         string is written unless exception is raised.
#         """
#         self.sock.sendall(data)
# 
#     def read(self, length: int) -> bytes:
#         """
#         Read as many bytes from socket as specified in length.
#         Loop as long as every byte is read unless exception is raised.
#         """
#         data = bytearray()
#         while len(data) != length:
#             data += self.sock.recv((length - len(data)))
#             if not data:
#                 raise ConnectionClosed('Connection unexpectedly closed.')
#         return data
# 
#     def close(self) -> None:
#         self.sock.close()


# Path: librouteros/protocol.py
import typing
from struct import pack, unpack #pylint: disable=no-name-in-module
from logging import getLogger, NullHandler
from librouteros.exceptions import (
    ProtocolError,
    FatalError,
)
from librouteros.connections import SocketTransport

        self.encoding = encoding

    @staticmethod
    def log(direction_string: str, *sentence: str) -> None:
        for word in sentence:
            LOGGER.debug(f'{direction_string} {word!r}')
        LOGGER.debug(f'{direction_string} EOS')

    def writeSentence(self, cmd: str, *words: str) -> None:
        """
        Write encoded sentence.

        :param cmd: Command word.
        :param words: Aditional words.
        """
        encoded = self.encodeSentence(cmd, *words)
        self.log('<---', cmd, *words)
        self.transport.write(encoded)

    def readSentence(self) -> typing.Tuple[str, typing.Tuple[str, ...]]:
        """
        Read every word untill empty word (NULL byte) is received.

        :return: Reply word, tuple with read words.
        """
        sentence = tuple(word for word in iter(self.readWord, ''))
        self.log('--->', *sentence)
        reply_word, words = sentence[0], sentence[1:]
        if reply_word == '!fatal':
            self.transport.close()

            raise FatalError(words[0])