code: def read(self, endpoint, size_or_buffer, timeout = None):
          r
          backend = self._ctx.backend
  
          fn_map = {
                      util.ENDPOINT_TYPE_BULK:backend.bulk_read,
                      util.ENDPOINT_TYPE_INTR:backend.intr_read,
                      util.ENDPOINT_TYPE_ISO:backend.iso_read
                  }
  
          intf, ep = self._ctx.setup_request(self, endpoint)
          fn = fn_map[util.endpoint_type(ep.bmAttributes)]
  
          if isinstance(size_or_buffer, array.array):
              buff = size_or_buffer
          else: # here we consider it is a integer
              buff = util.create_buffer(size_or_buffer)
  
          ret = fn(
                  self._ctx.handle,
                  ep.bEndpointAddress,
                  intf.bInterfaceNumber,
                  buff,
                  self.__get_timeout(timeout))
  
          if isinstance(size_or_buffer, array.array):
              return ret
          elif ret != len(buff) * buff.itemsize:
              return buff[:ret]
          else:
              return buff
docs: r"""Read data from the endpoint.
  
          This method is used to receive data from the device. The endpoint
          parameter corresponds to the bEndpointAddress member whose endpoint
          you want to communicate with. The size_or_buffer parameter either
          tells how many bytes you want to read or supplies the buffer to
          receive the data (it *must* be an object of the type array).
  
          The timeout is specified in miliseconds.
  
          If the size_or_buffer parameter is the number of bytes to read, the
          method returns an array object with the data read. If the
          size_or_buffer parameter is an array object, it returns the number
          of bytes actually read.