Auto switch to nearest available port.

This commit is contained in:
Zhangrp 2022-12-06 21:35:09 +08:00
parent 83aa6ff92c
commit 3e8de73b61
3 changed files with 24 additions and 16 deletions

View File

@ -75,14 +75,14 @@ def render(
def serve( def serve(
docs: Union[Iterable[Doc], Doc], docs: Union[Iterable[Doc], Doc],
style: str = "dep", style: str = "dep",
page: bool = True, page: bool = True,
minify: bool = False, minify: bool = False,
options: Dict[str, Any] = {}, options: Dict[str, Any] = {},
manual: bool = False, manual: bool = False,
port: int = 5000, port: int = 5000,
host: str = "0.0.0.0", host: str = "0.0.0.0",
) -> None: ) -> None:
"""Serve displaCy visualisation. """Serve displaCy visualisation.
@ -100,22 +100,28 @@ def serve(
""" """
from wsgiref import simple_server from wsgiref import simple_server
if is_port_in_use(port): # automatically switch to the next available port if the default / given port is taken
port += 1 available_port = port
while is_port_in_use(port) and port < 65535: while is_port_in_use(available_port) and available_port <= 65535:
port += 1 available_port += 1
if is_in_jupyter(): if is_in_jupyter():
warnings.warn(Warnings.W011) warnings.warn(Warnings.W011)
render(docs, style=style, page=page, minify=minify, options=options, manual=manual) render(docs, style=style, page=page, minify=minify, options=options, manual=manual)
httpd = simple_server.make_server(host, port, app) if port > 65535:
raise ValueError(Errors.E1048.format(host=host))
if available_port != port:
warnings.warn(Warnings.W124.format(host=host, port=port, available_port=available_port))
httpd = simple_server.make_server(host, available_port, app)
print(f"\nUsing the '{style}' visualizer") print(f"\nUsing the '{style}' visualizer")
print(f"Serving on http://{host}:{port} ...\n") print(f"Serving on http://{host}:{available_port} ...\n")
try: try:
httpd.serve_forever() httpd.serve_forever()
except KeyboardInterrupt: except KeyboardInterrupt:
print(f"Shutting down server on port {port}.") print(f"Shutting down server on port {available_port}.")
finally: finally:
httpd.server_close() httpd.server_close()

View File

@ -214,6 +214,7 @@ class Warnings(metaclass=ErrorsWithCodes):
"is a Cython extension type.") "is a Cython extension type.")
W123 = ("Argument `enable` with value {enable} does not contain all values specified in the config option " W123 = ("Argument `enable` with value {enable} does not contain all values specified in the config option "
"`enabled` ({enabled}). Be aware that this might affect other components in your pipeline.") "`enabled` ({enabled}). Be aware that this might affect other components in your pipeline.")
W124 = ("{host}:{port} is already in use, using the nearest available port {available_port} as an alternative.")
class Errors(metaclass=ErrorsWithCodes): class Errors(metaclass=ErrorsWithCodes):
@ -957,6 +958,7 @@ class Errors(metaclass=ErrorsWithCodes):
E1046 = ("{cls_name} is an abstract class and cannot be instantiated. If you are looking for spaCy's default " E1046 = ("{cls_name} is an abstract class and cannot be instantiated. If you are looking for spaCy's default "
"knowledge base, use `InMemoryLookupKB`.") "knowledge base, use `InMemoryLookupKB`.")
E1047 = ("`find_threshold()` only supports components with a `scorer` attribute.") E1047 = ("`find_threshold()` only supports components with a `scorer` attribute.")
E1048 = ("No port available for displacy on host {host}. Please specify a port by `displacy.serve(doc, port)`.")
# Deprecated model shortcuts, only used in errors and warnings # Deprecated model shortcuts, only used in errors and warnings

View File

@ -1740,4 +1740,4 @@ def all_equal(iterable):
def is_port_in_use(port): def is_port_in_use(port):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
return s.connect_ex(('localhost', port)) == 0 return s.connect_ex(('localhost', port)) == 0