| """Abstract Transport class.""" |
| |
| import sys |
| |
| PY34 = sys.version_info >= (3, 4) |
| |
| __all__ = ['BaseTransport', 'ReadTransport', 'WriteTransport', |
| 'Transport', 'DatagramTransport', 'SubprocessTransport', |
| ] |
| |
| |
| class BaseTransport: |
| """Base class for transports.""" |
| |
| def __init__(self, extra=None): |
| if extra is None: |
| extra = {} |
| self._extra = extra |
| |
| def get_extra_info(self, name, default=None): |
| """Get optional transport information.""" |
| return self._extra.get(name, default) |
| |
| def close(self): |
| """Close the transport. |
| |
| Buffered data will be flushed asynchronously. No more data |
| will be received. After all buffered data is flushed, the |
| protocol's connection_lost() method will (eventually) called |
| with None as its argument. |
| """ |
| raise NotImplementedError |
| |
| |
| class ReadTransport(BaseTransport): |
| """Interface for read-only transports.""" |
| |
| def pause_reading(self): |
| """Pause the receiving end. |
| |
| No data will be passed to the protocol's data_received() |
| method until resume_reading() is called. |
| """ |
| raise NotImplementedError |
| |
| def resume_reading(self): |
| """Resume the receiving end. |
| |
| Data received will once again be passed to the protocol's |
| data_received() method. |
| """ |
| raise NotImplementedError |
| |
| |
| class WriteTransport(BaseTransport): |
| """Interface for write-only transports.""" |
| |
| def set_write_buffer_limits(self, high=None, low=None): |
| """Set the high- and low-water limits for write flow control. |
| |
| These two values control when to call the protocol's |
| pause_writing() and resume_writing() methods. If specified, |
| the low-water limit must be less than or equal to the |
| high-water limit. Neither value can be negative. |
| |
| The defaults are implementation-specific. If only the |
| high-water limit is given, the low-water limit defaults to a |
| implementation-specific value less than or equal to the |
| high-water limit. Setting high to zero forces low to zero as |
| well, and causes pause_writing() to be called whenever the |
| buffer becomes non-empty. Setting low to zero causes |
| resume_writing() to be called only once the buffer is empty. |
| Use of zero for either limit is generally sub-optimal as it |
| reduces opportunities for doing I/O and computation |
| concurrently. |
| """ |
| raise NotImplementedError |
| |
| def get_write_buffer_size(self): |
| """Return the current size of the write buffer.""" |
| raise NotImplementedError |
| |
| def write(self, data): |
| """Write some data bytes to the transport. |
| |
| This does not block; it buffers the data and arranges for it |
| to be sent out asynchronously. |
| """ |
| raise NotImplementedError |
| |
| def writelines(self, list_of_data): |
| """Write a list (or any iterable) of data bytes to the transport. |
| |
| The default implementation concatenates the arguments and |
| calls write() on the result. |
| """ |
| if not PY34: |
| # In Python 3.3, bytes.join() doesn't handle memoryview. |
| list_of_data = ( |
| bytes(data) if isinstance(data, memoryview) else data |
| for data in list_of_data) |
| self.write(b''.join(list_of_data)) |
| |
| def write_eof(self): |
| """Close the write end after flushing buffered data. |
| |
| (This is like typing ^D into a UNIX program reading from stdin.) |
| |
| Data may still be received. |
| """ |
| raise NotImplementedError |
| |
| def can_write_eof(self): |
| """Return True if this transport supports write_eof(), False if not.""" |
| raise NotImplementedError |
| |
| def abort(self): |
| """Close the transport immediately. |
| |
| Buffered data will be lost. No more data will be received. |
| The protocol's connection_lost() method will (eventually) be |
| called with None as its argument. |
| """ |
| raise NotImplementedError |
| |
| |
| class Transport(ReadTransport, WriteTransport): |
| """Interface representing a bidirectional transport. |
| |
| There may be several implementations, but typically, the user does |
| not implement new transports; rather, the platform provides some |
| useful transports that are implemented using the platform's best |
| practices. |
| |
| The user never instantiates a transport directly; they call a |
| utility function, passing it a protocol factory and other |
| information necessary to create the transport and protocol. (E.g. |
| EventLoop.create_connection() or EventLoop.create_server().) |
| |
| The utility function will asynchronously create a transport and a |
| protocol and hook them up by calling the protocol's |
| connection_made() method, passing it the transport. |
| |
| The implementation here raises NotImplemented for every method |
| except writelines(), which calls write() in a loop. |
| """ |
| |
| |
| class DatagramTransport(BaseTransport): |
| """Interface for datagram (UDP) transports.""" |
| |
| def sendto(self, data, addr=None): |
| """Send data to the transport. |
| |
| This does not block; it buffers the data and arranges for it |
| to be sent out asynchronously. |
| addr is target socket address. |
| If addr is None use target address pointed on transport creation. |
| """ |
| raise NotImplementedError |
| |
| def abort(self): |
| """Close the transport immediately. |
| |
| Buffered data will be lost. No more data will be received. |
| The protocol's connection_lost() method will (eventually) be |
| called with None as its argument. |
| """ |
| raise NotImplementedError |
| |
| |
| class SubprocessTransport(BaseTransport): |
| |
| def get_pid(self): |
| """Get subprocess id.""" |
| raise NotImplementedError |
| |
| def get_returncode(self): |
| """Get subprocess returncode. |
| |
| See also |
| http://docs.python.org/3/library/subprocess#subprocess.Popen.returncode |
| """ |
| raise NotImplementedError |
| |
| def get_pipe_transport(self, fd): |
| """Get transport for pipe with number fd.""" |
| raise NotImplementedError |
| |
| def send_signal(self, signal): |
| """Send signal to subprocess. |
| |
| See also: |
| docs.python.org/3/library/subprocess#subprocess.Popen.send_signal |
| """ |
| raise NotImplementedError |
| |
| def terminate(self): |
| """Stop the subprocess. |
| |
| Alias for close() method. |
| |
| On Posix OSs the method sends SIGTERM to the subprocess. |
| On Windows the Win32 API function TerminateProcess() |
| is called to stop the subprocess. |
| |
| See also: |
| http://docs.python.org/3/library/subprocess#subprocess.Popen.terminate |
| """ |
| raise NotImplementedError |
| |
| def kill(self): |
| """Kill the subprocess. |
| |
| On Posix OSs the function sends SIGKILL to the subprocess. |
| On Windows kill() is an alias for terminate(). |
| |
| See also: |
| http://docs.python.org/3/library/subprocess#subprocess.Popen.kill |
| """ |
| raise NotImplementedError |