diff --git a/server/cli/launch.py b/server/cli/launch.py index 14e70000..8d2cf178 100644 --- a/server/cli/launch.py +++ b/server/cli/launch.py @@ -11,7 +11,7 @@ import click from server.app.app import Server from server.app.util.errors import ScanpyFileError from server.app.util.utils import custom_format_warning -from server.utils.utils import find_available_port +from server.utils.utils import find_available_port, is_port_available # anything bigger than this will generate a special message @@ -141,7 +141,14 @@ security risk by including the --scripts flag. Make sure you trust the scripts t file_parts = splitext(basename(data)) title = file_parts[0] - if not port: + if port: + if debug: + raise click.ClickException("--port and --debug may not be used together (try --verbose for error logging).") + if not is_port_available(host, int(port)): + raise click.ClickException( + f"The port selected {port} is in use, please specify an open port using the --port flag." + ) + else: port = find_available_port(host) # Setup app @@ -199,7 +206,7 @@ security risk by including the --scripts flag. Make sure you trust the scripts t sys.stdout = f try: - server.app.run(host=host, debug=debug, port=port, threaded=True) + server.app.run(host=host, debug=debug, port=port, threaded=True, use_debugger=False) except OSError as e: if e.errno == errno.EADDRINUSE: raise click.ClickException("Port is in use, please specify an open port using the --port flag.") from e diff --git a/server/test/test_api.py b/server/test/test_api.py index 24791879..7f396431 100644 --- a/server/test/test_api.py +++ b/server/test/test_api.py @@ -19,7 +19,7 @@ class EndPoints(unittest.TestCase): @classmethod def setUpClass(cls): - cls.ps = Popen(["cellxgene", "launch", "example-dataset/pbmc3k.h5ad", "--debug", "--port", "5005"]) + cls.ps = Popen(["cellxgene", "launch", "example-dataset/pbmc3k.h5ad", "--verbose", "--port", "5005"]) session = requests.Session() for i in range(90): try: diff --git a/server/test/test_nan_rest.py b/server/test/test_nan_rest.py index 23b3db50..a9ba4dd7 100644 --- a/server/test/test_nan_rest.py +++ b/server/test/test_nan_rest.py @@ -8,7 +8,7 @@ import decode_fbs import requests -LOCAL_URL = "http://127.0.0.1:5005/" +LOCAL_URL = "http://127.0.0.1:5006/" VERSION = "v0.2" URL_BASE = f"{LOCAL_URL}api/{VERSION}/" @@ -21,7 +21,7 @@ class WithNaNs(unittest.TestCase): @classmethod def setUpClass(cls): cls.ps = Popen( - ["cellxgene", "launch", "server/test/test_datasets/nan.h5ad", "--debug", "--port", "5005"] + ["cellxgene", "launch", "server/test/test_datasets/nan.h5ad", "--verbose", "--port", "5006"] ) session = requests.Session() for i in range(90): diff --git a/server/utils/utils.py b/server/utils/utils.py index 37a984e4..239f45bd 100644 --- a/server/utils/utils.py +++ b/server/utils/utils.py @@ -10,10 +10,17 @@ def find_available_port(host, port=5005): # Takes approx 2 seconds to do a scan of 5000 ports on my laptop num_ports_to_try = 5000 for port_to_try in range(port, port + num_ports_to_try): - with contextlib.closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s: - try: - s.bind((host, port_to_try)) - return port_to_try - except socket.error: - pass + if is_port_available(host, port_to_try): + return port_to_try raise socket.error(errno.EADDRINUSE, f"No port in range {port} - {port + num_ports_to_try - 1} available.") + + +def is_port_available(host, port): + is_available = False + with contextlib.closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s: + try: + s.bind((host, port)) + is_available = True + except socket.error: + pass + return is_available