def __init__(self, fd): """'fd' is either a file object (e.g., obtained with 'open') or a file number (e.g., obtained with socket's fileno()). """ if hasattr(fd, 'fileno'): self._fd = fd self._fileno = fd.fileno() elif isinstance(fd, int): self._fd, self._fileno = None, self._fd else: raise ValueError('invalid file descriptor') self._pycos = Pycos.scheduler() if self._pycos: self._notifier = self._pycos._notifier if hasattr(fd, '_fileno'): # assume it is AsyncSocket self._notifier.unregister(fd) else: self._notifier = None self._timeout = None self._read_task = None self._read_fn = None self._write_task = None self._write_fn = None self._buflist = [] flags = fcntl.fcntl(self._fileno, fcntl.F_GETFL) fcntl.fcntl(self._fileno, fcntl.F_SETFL, flags | os.O_NONBLOCK)
def __init__(self, fd): """'fd' is either a file object (e.g., obtained with 'open') or a file number (e.g., obtained with socket's fileno()). """ if hasattr(fd, 'fileno'): self._fd = fd self._fileno = fd.fileno() elif isinstance(fd, int): self._fd, self._fileno = None, self._fd else: raise ValueError('invalid file descriptor') self._pycos = Pycos.scheduler() if self._pycos: self._notifier = self._pycos._notifier if hasattr(fd, '_fileno'): # assume it is AsyncSocket self._notifier.unregister(fd) else: self._notifier = None self._timeout = None self._read_task = None self._read_fn = None self._write_task = None self._write_fn = None self._buflist = [] self._event = None flags = fcntl.fcntl(self._fileno, fcntl.F_GETFL) fcntl.fcntl(self._fileno, fcntl.F_SETFL, flags | os.O_NONBLOCK)
def write(self, buf, full=False, timeout=None): """Write data in 'buf' to file. If 'full' is True, the function waits till all data in buf is written; otherwise, it waits until one write completes. It returns length of data written. If no data has been written before timeout, then IOError('timedout') will be thrown. If timeout is given and full is True and timeout expires before all the data could be written, it returns length of data written before timeout if any data has been written. Must be used with 'yield' as 'n = yield fd.write(buf)' to write (some) data in buf. """ def _write(view, written): try: n = os.write(self._fileno, view) except (OSError, IOError) as exc: if exc.errno in (errno.EAGAIN, errno.EINTR): n = 0 else: self._notifier.clear(self, _AsyncPoller._Write) if full: view.release() self._write_task.throw(*sys.exc_info()) self._write_task = self._write_fn = None return written += n if n == len(view) or not full: self._notifier.clear(self, _AsyncPoller._Write) if full: view.release() self._write_task._proceed_(written) self._write_task = self._write_fn = None else: view = view[n:] self._write_fn = partial_func(_write, view, written) if not self._pycos: self._pycos = Pycos.scheduler() self._notifier = self._pycos._notifier if hasattr(self._fd, '_fileno'): self._notifier.unregister(self._fd) if full: view = memoryview(buf) else: view = buf self._timeout = timeout self._write_task = Pycos.cur_task(self._pycos) self._write_task._await_() self._write_fn = partial_func(_write, view, 0) self._notifier.add(self, _AsyncPoller._Write)
def write(self, buf, full=False, timeout=None): """Write data in 'buf' to file. If 'full' is True, the function waits till all data in buf is written; otherwise, it waits until one write completes. It returns length of data written. If no data has been written before timeout, then IOError('timedout') will be thrown. If timeout is given and full is True and timeout expires before all the data could be written, it returns length of data written before timeout if any data has been written. Must be used with 'yield' as 'n = yield fd.write(buf)' to write (some) data in buf. """ def _write(view, written): try: n = os.write(self._fileno, view) except (OSError, IOError) as exc: if exc.errno in (errno.EAGAIN, errno.EINTR): n = 0 else: self._notifier.clear(self, _AsyncPoller._Write) self._write_task.throw(*sys.exc_info()) self._write_task = self._write_fn = None return written += n if n == len(view) or not full: self._notifier.clear(self, _AsyncPoller._Write) self._write_task._proceed_(written) self._write_task = self._write_fn = None else: view = view[n:] self._write_fn = partial_func(_write, view, written) if not self._pycos: self._pycos = Pycos.scheduler() self._notifier = self._pycos._notifier if hasattr(self._fd, '_fileno'): self._notifier.unregister(self._fd) if full: view = buffer(buf) else: view = buf self._timeout = timeout self._write_task = Pycos.cur_task(self._pycos) self._write_task._await_() self._write_fn = partial_func(_write, view, 0) self._notifier.add(self, _AsyncPoller._Write)
def read(self, size=0, full=False, timeout=None): """Read at most 'size' bytes from file; if 'size' <= 0, all data up to EOF is read and returned. If 'full' is True, exactly 'size' bytes are returned (unless EOF or timeout occur before). If EOF is encountered before any more data is available, empty buffer is returned. If no data has been read before timeout, then IOError('timedout') will be thrown. If timeout is given and full is True and timeout expires before all the data could be read, it returns partial data read before timeout if any data has been read. Must be used in a task with 'yield' as 'data = yield fd.read(1024)' """ def _read(size, full): if size > 0: count = size else: count = 16384 try: buf = os.read(self._fileno, count) except (OSError, IOError) as exc: if exc.errno in (errno.EAGAIN, errno.EWOULDBLOCK): return else: raise except Exception: self._notifier.clear(self, _AsyncPoller._Read) self._read_task.throw(*sys.exc_info()) self._read_task = self._read_fn = None return if buf: if size > 0: size -= len(buf) # assert size >= 0 if size == 0: full = False self._buflist.append(buf) if full: self._read_fn = partial_func(_read, size, full) return if self._buflist: buf, self._buflist = ''.join(self._buflist), [] self._notifier.clear(self, _AsyncPoller._Read) self._read_task._proceed_(buf) self._read_task = self._read_fn = None if not self._pycos: self._pycos = Pycos.scheduler() self._notifier = self._pycos._notifier if hasattr(self._fd, '_fileno'): self._notifier.unregister(self._fd) if not size or size < 0: size = 0 full = True elif self._buflist: buf, self._buflist = ''.join(self._buflist), [] if len(buf) > size: buf, self._buflist = buf[:size], [buf[size:]] if (not full) or (len(buf) == size): return buf self._buflist = [buf] size -= len(buf) self._timeout = timeout self._read_task = Pycos.cur_task(self._pycos) self._read_task._await_() self._read_fn = partial_func(_read, size, full) self._notifier.add(self, _AsyncPoller._Read)
def write(self, buf, full=False, timeout=None): """Write data in 'buf' to file. If 'full' is True, the function waits till all data in buf is written; otherwise, it waits until one write completes. It returns length of data written. If no data has been written before timeout, then IOError('timedout') will be thrown. If timeout is given and full is True and timeout expires before all the data could be written, it returns length of data written before timeout if any data has been written. Must be used with 'yield' as 'n = yield fd.write(buf)' to write (some) data in buf. """ def _write(written, rc, n): if rc or n == 0: if self._timeout: self._notifier._del_timeout(self) if rc != winerror.ERROR_OPERATION_ABORTED: if written: self._write_task._proceed_(written) else: self._write_task.throw(IOError(rc, 'WriteFile', str(rc))) self._overlap.object = self._write_task = self._write_result = None return written += n self._overlap.Offset += n self._write_result = self._write_result[n:] if not full or len(self._write_result) == 0: self._overlap.object = self._write_result = None if self._timeout: self._notifier._del_timeout(self) self._write_task._proceed_(written) self._write_task = None return self._overlap.object = partial_func(_write, written) try: rc, _ = win32file.WriteFile(self._handle, self._write_result, self._overlap) except pywintypes.error as exc: rc = exc.winerror if rc and rc != winerror.ERROR_IO_PENDING: self._overlap.object = self._write_result = None if self._timeout: self._notifier._del_timeout(self) if written: self._write_task._proceed_(written) else: self._write_task.throw(IOError(rc, 'WriteFile', str(rc))) self._write_task = None return self._write_result = buffer(buf) self._overlap.object = partial_func(_write, 0) if not self._pycos: self._pycos = Pycos.scheduler() self._notifier = self._pycos._notifier self._notifier.register(self._handle) self._write_task = Pycos.cur_task(self._pycos) self._write_task._await_() try: rc, _ = win32file.WriteFile(self._handle, self._write_result, self._overlap) except pywintypes.error as exc: if exc.winerror == winerror.ERROR_BROKEN_PIPE: self._write_task._proceed_(0) self._write_result = self._write_task = self._overlap.object = None return else: rc = exc.winerror if rc and rc != winerror.ERROR_IO_PENDING: self._overlap.object = self._write_result = self._write_task = None self._write_task._proceed_(None) raise IOError(rc, 'WriteFile', str(rc)) if timeout: self._timeout = timeout self._notifier._add_timeout(self)
def read(self, size=0, full=False, timeout=None): """Read at most 'size' bytes from file; if 'size' <= 0, all data up to EOF is read and returned. If 'full' is True, exactly 'size' bytes are returned (unless EOF or timeout occur before). If EOF is encountered before any more data is available, empty buffer is returned. If no data has been read before timeout, then IOError('timedout') will be thrown. If timeout is given and full is True and timeout expires before all the data could be read, it returns partial data read before timeout if any data has been read. Must be used in a task with 'yield' as 'data = yield fd.read(1024)' """ def _read(size, full, rc, n): if rc or n == 0: if self._timeout: self._notifier._del_timeout(self) self._overlap.object = self._read_result = None if rc != winerror.ERROR_OPERATION_ABORTED: if (self._buflist or rc == winerror.ERROR_HANDLE_EOF or rc == winerror.ERROR_BROKEN_PIPE): buf, self._buflist = ''.join(self._buflist), [] self._read_task._proceed_(buf) return self._read_task.throw(IOError(rc, 'ReadFile', str(rc))) self._overlap.object = self._read_task = self._read_result = None return buf = self._read_result[:n] if size > 0: size -= len(buf) assert size >= 0 if size == 0: full = False self._buflist.append(buf) self._overlap.Offset += n if full: self._overlap.object = partial_func(_read, size, full) try: rc, _ = win32file.ReadFile(self._handle, self._read_result, self._overlap) except pywintypes.error as exc: rc = exc.winerror if rc and rc != winerror.ERROR_IO_PENDING: buf, self._buflist = ''.join(self._buflist), [] self._overlap.object = self._read_result = None if self._timeout: self._notifier._del_timeout(self) self._read_task._proceed_(buf) self._read_task = None return if self._buflist: buf, self._buflist = ''.join(self._buflist), [] if self._timeout: self._notifier._del_timeout(self) self._overlap.object = self._read_result = None self._read_task._proceed_(buf) self._read_task = None if not self._pycos: self._pycos = Pycos.scheduler() self._notifier = self._pycos._notifier self._notifier.register(self._handle) if not size or size < 0: count = 16384 full = True else: if self._buflist: buf, self._buflist = ''.join(self._buflist), [] if len(buf) > size: buf, self._buflist = buf[:size], [buf[size:]] if (not full) or (len(buf) == size): return buf self._buflist = [buf] size -= len(buf) count = size self._read_result = win32file.AllocateReadBuffer(count) self._overlap.object = partial_func(_read, size, full) self._read_task = Pycos.cur_task(self._pycos) self._read_task._await_() try: rc, _ = win32file.ReadFile(self._handle, self._read_result, self._overlap) except pywintypes.error as exc: if exc.winerror == winerror.ERROR_BROKEN_PIPE: buf, self._buflist = ''.join(self._buflist), [] self._read_task._proceed_(buf) self._read_result = self._read_task = self._overlap.object = None return else: rc = exc.winerror if rc and rc != winerror.ERROR_IO_PENDING: self._overlap.object = self._read_result = self._read_task = None self._read_task.throw(IOError(rc, 'ReadFile', str(rc))) if timeout: self._timeout = timeout self._notifier._add_timeout(self)
def __init__(self, path_handle, mode='r', share=None): """If 'path_handle' is a string, opens that file for asynchronous I/O; if it is a handle (pipe client / server, for example), sets up for asynchronous I/O. 'mode' is as per 'open' Python function, although limited to basic/common modes. """ self._overlap = pywintypes.OVERLAPPED() if isinstance(path_handle, str): self._path = path_handle if mode.startswith('r'): access = win32file.GENERIC_READ if share is None: share = win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE create = win32file.OPEN_EXISTING if '+' in mode: access |= win32file.GENERIC_WRITE elif mode.startswith('w'): access = win32file.GENERIC_WRITE if share is None: share = win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE create = win32file.CREATE_ALWAYS if '+' in mode: access |= win32file.GENERIC_READ elif mode.startswith('a'): access = win32file.GENERIC_WRITE if share is None: share = win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE create = win32file.OPEN_ALWAYS if '+' in mode: access |= win32file.GENERIC_READ # TODO: if reading, offset should be 0? sb = os.stat(path_handle) self._overlap.Offset = sb.st_size else: self._overlap = None raise ValueError('invalid mode "%s"' % mode) flags = win32file.FILE_FLAG_OVERLAPPED try: self._handle = win32file.CreateFile(path_handle, access, share, None, create, flags, None) except Exception: self._overlap = None raise if mode.startswith('r'): flags = os.O_RDONLY elif mode.startswith('a'): flags = os.O_APPEND else: flags = 0 self._fileno = msvcrt.open_osfhandle(self._handle, flags) else: self._handle = path_handle # pipe mode should be either 'r' or 'w' flags = os.O_RDONLY if mode.startswith('r') else 0 self._fileno = msvcrt.open_osfhandle(self._handle, flags) self._buflist = [] self._read_result = None self._write_result = None self._timeout = None self._timeout_id = None self._pycos = Pycos.scheduler() if self._pycos: self._notifier = self._pycos._notifier self._notifier.register(self._handle) else: self._notifier = None self._event = None
def read(self, size=0, full=False, timeout=None): """Read at most 'size' bytes from file; if 'size' <= 0, all data up to EOF is read and returned. If 'full' is True, exactly 'size' bytes are returned (unless EOF or timeout occur before). If EOF is encountered before any more data is available, empty buffer is returned. If no data has been read before timeout, then IOError('timedout') will be thrown. If timeout is given and full is True and timeout expires before all the data could be read, it returns partial data read before timeout if any data has been read. Must be used in a task with 'yield' as 'data = yield fd.read(1024)' """ def _read(size, full): if size > 0: count = size else: count = 16384 try: buf = os.read(self._fileno, count) except (OSError, IOError) as exc: if exc.errno in (errno.EAGAIN, errno.EWOULDBLOCK): return else: raise except: self._notifier.clear(self, _AsyncPoller._Read) self._read_task.throw(*sys.exc_info()) self._read_task = self._read_fn = None return if buf: if size > 0: size -= len(buf) # assert size >= 0 if size == 0: full = False self._buflist.append(buf) if full: self._read_fn = partial_func(_read, size, full) return if self._buflist: buf, self._buflist = ''.join(self._buflist), [] self._notifier.clear(self, _AsyncPoller._Read) self._read_task._proceed_(buf) self._read_task = self._read_fn = None if not self._pycos: self._pycos = Pycos.scheduler() self._notifier = self._pycos._notifier if hasattr(self._fd, '_fileno'): self._notifier.unregister(self._fd) if not size or size < 0: size = 0 full = True elif self._buflist: buf, self._buflist = ''.join(self._buflist), [] if len(buf) > size: buf, self._buflist = buf[:size], [buf[size:]] if (not full) or (len(buf) == size): return buf self._buflist = [buf] size -= len(buf) self._timeout = timeout self._read_task = Pycos.cur_task(self._pycos) self._read_task._await_() self._read_fn = partial_func(_read, size, full) self._notifier.add(self, _AsyncPoller._Read)
def __init__(self, path_handle, mode='r', share=None): """If 'path_handle' is a string, opens that file for asynchronous I/O; if it is a handle (pipe client / server, for example), sets up for asynchronous I/O. 'mode' is as per 'open' Python function, although limited to basic/common modes. """ self._overlap = pywintypes.OVERLAPPED() if isinstance(path_handle, str): self._path = path_handle if mode.startswith('r'): access = win32file.GENERIC_READ if share is None: share = win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE create = win32file.OPEN_EXISTING if '+' in mode: access |= win32file.GENERIC_WRITE elif mode.startswith('w'): access = win32file.GENERIC_WRITE if share is None: share = win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE create = win32file.CREATE_ALWAYS if '+' in mode: access |= win32file.GENERIC_READ elif mode.startswith('a'): access = win32file.GENERIC_WRITE if share is None: share = win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE create = win32file.OPEN_ALWAYS if '+' in mode: access |= win32file.GENERIC_READ # TODO: if reading, offset should be 0? sb = os.stat(path_handle) self._overlap.Offset = sb.st_size else: self._overlap = None raise ValueError('invalid mode "%s"' % mode) flags = win32file.FILE_FLAG_OVERLAPPED try: self._handle = win32file.CreateFile(path_handle, access, share, None, create, flags, None) except: self._overlap = None raise if mode.startswith('r'): flags = os.O_RDONLY elif mode.startswith('a'): flags = os.O_APPEND else: flags = 0 self._fileno = msvcrt.open_osfhandle(self._handle, flags) else: self._handle = path_handle # pipe mode should be either 'r' or 'w' flags = os.O_RDONLY if mode.startswith('r') else 0 self._fileno = msvcrt.open_osfhandle(self._handle, flags) self._buflist = [] self._read_result = None self._write_result = None self._timeout = None self._timeout_id = None self._pycos = Pycos.scheduler() if self._pycos: self._notifier = self._pycos._notifier self._notifier.register(self._handle) else: self._notifier = None