Update portend-3.0.0

This commit is contained in:
JonnyWong16 2021-10-14 21:12:55 -07:00
parent f3f4f9edf6
commit edd2f21ce1
No known key found for this signature in database
GPG key ID: B1F1F9807184697A

View file

@ -1,11 +1,7 @@
# -*- coding: utf-8 -*-
""" """
A simple library for managing the availability of ports. A simple library for managing the availability of ports.
""" """
from __future__ import print_function, division
import time import time
import socket import socket
import argparse import argparse
@ -13,17 +9,23 @@ import sys
import itertools import itertools
import contextlib import contextlib
import platform import platform
try:
from collections import abc from collections import abc
except ImportError: import urllib.parse
import collections as abc
from tempora import timing from tempora import timing
def client_host(server_host): def client_host(server_host):
"""Return the host on which a client can connect to the given listener.""" """
Return the host on which a client can connect to the given listener.
>>> client_host('192.168.0.1')
'192.168.0.1'
>>> client_host('0.0.0.0')
'127.0.0.1'
>>> client_host('::')
'::1'
"""
if server_host == '0.0.0.0': if server_host == '0.0.0.0':
# 0.0.0.0 is INADDR_ANY, which should answer on localhost. # 0.0.0.0 is INADDR_ANY, which should answer on localhost.
return '127.0.0.1' return '127.0.0.1'
@ -64,7 +66,7 @@ class Checker(object):
if port is None and isinstance(host, abc.Sequence): if port is None and isinstance(host, abc.Sequence):
host, port = host[:2] host, port = host[:2]
if platform.system() == 'Windows': if platform.system() == 'Windows':
host = client_host(host) host = client_host(host) # pragma: nocover
info = socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM) info = socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM)
list(itertools.starmap(self._connect, info)) list(itertools.starmap(self._connect, info))
@ -80,7 +82,7 @@ class Checker(object):
return return
# the connect succeeded, so the port isn't free # the connect succeeded, so the port isn't free
port, host = sa[:2] host, port = sa[:2]
tmpl = "Port {port} is in use on {host}." tmpl = "Port {port} is in use on {host}."
raise PortNotFree(tmpl.format(**locals())) raise PortNotFree(tmpl.format(**locals()))
@ -103,6 +105,11 @@ def free(host, port, timeout=float('Inf')):
If timeout is None or , the routine will run indefinitely. If timeout is None or , the routine will run indefinitely.
>>> free('localhost', find_available_local_port()) >>> free('localhost', find_available_local_port())
>>> free(None, None)
Traceback (most recent call last):
...
ValueError: Host values of '' or None are not allowed.
""" """
if not host: if not host:
raise ValueError("Host values of '' or None are not allowed.") raise ValueError("Host values of '' or None are not allowed.")
@ -121,9 +128,6 @@ def free(host, port, timeout=float('Inf')):
time.sleep(0.1) time.sleep(0.1)
wait_for_free_port = free
def occupied(host, port, timeout=float('Inf')): def occupied(host, port, timeout=float('Inf')):
""" """
Wait for the specified port to become occupied (accepting requests). Wait for the specified port to become occupied (accepting requests).
@ -137,6 +141,11 @@ def occupied(host, port, timeout=float('Inf')):
Traceback (most recent call last): Traceback (most recent call last):
... ...
Timeout: Port ... not bound on localhost. Timeout: Port ... not bound on localhost.
>>> occupied(None, None)
Traceback (most recent call last):
...
ValueError: Host values of '' or None are not allowed.
""" """
if not host: if not host:
raise ValueError("Host values of '' or None are not allowed.") raise ValueError("Host values of '' or None are not allowed.")
@ -155,9 +164,6 @@ def occupied(host, port, timeout=float('Inf')):
return return
wait_for_occupied_port = occupied
def find_available_local_port(): def find_available_local_port():
""" """
Find a free port on localhost. Find a free port on localhost.
@ -188,20 +194,33 @@ class HostPort(str):
>>> len(hp) >>> len(hp)
15 15
>>> hp = HostPort('[::1]:32768')
>>> hp.host
'::1'
>>> hp.port
32768
""" """
@property @property
def host(self): def host(self):
host, sep, port = self.partition(':') return urllib.parse.urlparse(f'//{self}').hostname
return host
@property @property
def port(self): def port(self):
host, sep, port = self.partition(':') return urllib.parse.urlparse(f'//{self}').port
return int(port)
@classmethod
def from_addr(cls, addr):
listen_host, port = addr[:2]
plain_host = client_host(listen_host)
host = f'[{plain_host}]' if ':' in plain_host else plain_host
return cls(':'.join([host, str(port)]))
def _main(): def _main(args=None):
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
def global_lookup(key): def global_lookup(key):
@ -210,7 +229,7 @@ def _main():
parser.add_argument('target', metavar='host:port', type=HostPort) parser.add_argument('target', metavar='host:port', type=HostPort)
parser.add_argument('func', metavar='state', type=global_lookup) parser.add_argument('func', metavar='state', type=global_lookup)
parser.add_argument('-t', '--timeout', default=None, type=float) parser.add_argument('-t', '--timeout', default=None, type=float)
args = parser.parse_args() args = parser.parse_args(args)
try: try:
args.func(args.target.host, args.target.port, timeout=args.timeout) args.func(args.target.host, args.target.port, timeout=args.timeout)
except Timeout as timeout: except Timeout as timeout:
@ -218,5 +237,4 @@ def _main():
raise SystemExit(1) raise SystemExit(1)
if __name__ == '__main__': __name__ == '__main__' and _main()
_main()