# Buggy code
def _recv(self, size):
    """Reads data from the underlying descriptor

    :param size: The number of bytes to read
    :return: The bytes read
    """
    if not self.socket:
        raise ConnectionException(self.__str__())

    # socket.recv(size) waits until it gets some data from the host but
    # not necessarily the entire response that can be fragmented in
    # many packets.
    # To avoid the splitted responses to be recognized as invalid
    # messages and to be discarded, loops socket.recv until full data
    # is received or timeout is expired.
    # If timeout expires returns the read data, also if its length is
    # less than the expected size.
    self.socket.setblocking(0)

    timeout = self.timeout

    # If size isn't specified read 1 byte at a time.
    if size is None:
        recv_size = 1
    else:
        recv_size = size

    data = b""
    begin = time.time()
    while recv_size > 0:
        ready = select.select([self.socket], [], [], timeout)
        if ready[0]:
            data += self.socket.recv(recv_size)

        # If size isn't specified continue to read until timeout expires.
        if size:
            recv_size = size - len(data)

        # Timeout is reduced also if some data has been received in order
        # to avoid infinite loops when there isn't an expected response size
        # and the slave sends noisy data continuosly.
        timeout -= time.time() - begin
        if timeout <= 0:
            break

    return data


# Traceback (AttributeError)
client = ModbusSerialClient(port='notexist', method='rtu')
client.connect()
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "lib/python3.6/site-packages/pymodbus/client/sync.py", line 476, in connect
self.socket.interCharTimeout = self.inter_char_timeout
AttributeError: 'NoneType' object has no attribute 'interCharTimeout'

# Fixed code
def _recv(self, size):
    """Reads data from the underlying descriptor

    :param size: The number of bytes to read
    :return: The bytes read
    """
    if not self.socket:
        raise ConnectionException(self.__str__())

    # socket.recv(size) waits until it gets some data from the host but
    # not necessarily the entire response that can be fragmented in
    # many packets.
    # To avoid the splitted responses to be recognized as invalid
    # messages and to be discarded, loops socket.recv until full data
    # is received or timeout is expired.
    # If timeout expires returns the read data, also if its length is
    # less than the expected size.
    self.socket.setblocking(0)

    timeout = self.timeout

    # If size isn't specified read 1 byte at a time.
    if size is None:
        recv_size = 1
    else:
        recv_size = size

    data = b""
    time_ = time.time()
    end = time_ + timeout
    while recv_size > 0:
        ready = select.select([self.socket], [], [], end - time_)
        if ready[0]:
            data += self.socket.recv(recv_size)
        time_ = time.time()

        # If size isn't specified continue to read until timeout expires.
        if size:
            recv_size = size - len(data)

        # Timeout is reduced also if some data has been received in order
        # to avoid infinite loops when there isn't an expected response
        # size and the slave sends noisy data continuosly.
        if time_ > end:
            break

    return data