Skip to content

Commit dc9f18d

Browse files
Add ability to run tests in parallel by using process to define port
1 parent 1f902ba commit dc9f18d

1 file changed

Lines changed: 23 additions & 4 deletions

File tree

dash/testing/application_runners.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import sys
22
import os
3+
import re
34
import time
45
import uuid
56
import shlex
@@ -28,6 +29,17 @@
2829
logger = logging.getLogger(__name__)
2930

3031

32+
def _worker_port_base():
33+
"""Return a port base offset for the current pytest-xdist worker.
34+
35+
Each worker (gw0, gw1, ...) gets a unique 100-port window so parallel
36+
test runs don't collide. Outside of xdist the offset is 0.
37+
"""
38+
worker = os.environ.get("PYTEST_XDIST_WORKER", "gw0")
39+
match = re.match(r"gw(\d+)", worker)
40+
return int(match.group(1)) * 100 if match else 0
41+
42+
3143
def import_app(app_file, application_name="app"):
3244
"""Import a dash application from a module. The import path is in dot
3345
notation to the module. The variable named app will be returned.
@@ -59,12 +71,12 @@ def import_app(app_file, application_name="app"):
5971
class BaseDashRunner:
6072
"""Base context manager class for running applications."""
6173

62-
_next_port = 58050
74+
_next_port = 58050 + _worker_port_base()
6375

6476
def __init__(self, keep_open, stop_timeout, scheme="http", host="localhost"):
6577
self.scheme = scheme
6678
self.host = host
67-
self.port = 8050
79+
self.port = BaseDashRunner._next_port
6880
self.started = None
6981
self.keep_open = keep_open
7082
self.stop_timeout = stop_timeout
@@ -220,7 +232,11 @@ def __init__(self, keep_open=False, stop_timeout=3):
220232

221233
# pylint: disable=arguments-differ
222234
def start(self, app, start_timeout=3, **kwargs):
223-
self.port = kwargs.get("port", 8050)
235+
if "port" not in kwargs:
236+
kwargs["port"] = self.port = BaseDashRunner._next_port
237+
BaseDashRunner._next_port += 1
238+
else:
239+
self.port = kwargs["port"]
224240

225241
def target():
226242
app.scripts.config.serve_locally = True
@@ -279,7 +295,7 @@ def start(
279295
app_module=None,
280296
application_name="app",
281297
raw_command=None,
282-
port=8050,
298+
port=None,
283299
start_timeout=3,
284300
):
285301
"""Start the server with waitress-serve in process flavor."""
@@ -288,6 +304,9 @@ def start(
288304
"the process runner needs to start with at least one valid command"
289305
)
290306
return
307+
if port is None:
308+
port = BaseDashRunner._next_port
309+
BaseDashRunner._next_port += 1
291310
self.port = port
292311
args = shlex.split(
293312
raw_command

0 commit comments

Comments
 (0)