Skip to content

Commit 5a76e8e

Browse files
authored
Merge pull request #948 from plotly/R-test-cwd
cwd for running dashr tests - auto and override
2 parents ba17890 + 8e287c3 commit 5a76e8e

File tree

3 files changed

+38
-11
lines changed

3 files changed

+38
-11
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
44

55
## Unreleased
66
### Added
7+
- [#948](https://github.com/plotly/dash/pull/948) Support setting working directory for R apps run using the `dashr` fixture, primarily useful for tests with assets. `dashr.start_server` supports a `cwd` argument to set an explicit working directory, and has smarter defaults when it's omitted: if `app` is a path to an R script, uses the directory of that path; if `app` is a string, uses the directory the test file itself is in.
78
- [#944](https://github.com/plotly/dash/pull/944)
89
- Relevant `dash.testing` methods can now be called with either an element or a CSS selector: `select_dcc_dropdown`, `multiple_click`, `clear_input`, `zoom_in_graph_by_ratio`, `click_at_coord_fractions`.
910
- Three new `dash.testing` methods: `clear_local_storage`, `clear_session_storage`, and `clear_storage` (to clear both together)

dash/testing/application_runners.py

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import threading
88
import subprocess
99
import logging
10+
import inspect
1011

1112
import runpy
1213
import future.utils as utils
@@ -30,7 +31,7 @@ def import_app(app_file, application_name="app"):
3031
3132
:Example:
3233
33-
>>> app = import_app('my_app.app')
34+
>>> app = import_app("my_app.app")
3435
3536
Will import the application in module `app` of the package `my_app`.
3637
@@ -248,28 +249,52 @@ def __init__(self, keep_open=False, stop_timeout=3):
248249
self.proc = None
249250

250251
# pylint: disable=arguments-differ
251-
def start(self, app, start_timeout=2):
252-
"""Start the server with waitress-serve in process flavor."""
252+
def start(self, app, start_timeout=2, cwd=None):
253+
"""Start the server with subprocess and Rscript."""
253254

254255
# app is a R string chunk
255-
if not (os.path.isfile(app) and os.path.exists(app)):
256+
if (os.path.isfile(app) and os.path.exists(app)):
257+
# app is already a file in a dir - use that as cwd
258+
if not cwd:
259+
cwd = os.path.dirname(app)
260+
logger.info("RRunner inferred cwd from app path: %s", cwd)
261+
else:
256262
path = (
257263
"/tmp/app_{}.R".format(uuid.uuid4().hex)
258264
if not self.is_windows
259265
else os.path.join(
260266
(os.getenv("TEMP"), "app_{}.R".format(uuid.uuid4().hex))
261267
)
262268
)
263-
logger.info("RRuner start => app is R code chunk")
264-
logger.info("make a temporay R file for execution=> %s", path)
265-
logger.debug("the content of dashR app")
269+
logger.info("RRunner start => app is R code chunk")
270+
logger.info("make a temporary R file for execution => %s", path)
271+
logger.debug("content of the dashR app")
266272
logger.debug("%s", app)
267273

268274
with open(path, "w") as fp:
269275
fp.write(app)
270276

271277
app = path
272278

279+
# try to find the path to the calling script to use as cwd
280+
if not cwd:
281+
for entry in inspect.stack():
282+
if "/dash/testing/" not in entry[1].replace("\\", "/"):
283+
cwd = os.path.dirname(os.path.realpath(entry[1]))
284+
break
285+
if cwd:
286+
logger.info(
287+
"RRunner inferred cwd from the Python call stack: %s",
288+
cwd
289+
)
290+
else:
291+
logger.warning(
292+
"RRunner found no cwd in the Python call stack. "
293+
"You may wish to specify an explicit working directory "
294+
"using something like: "
295+
"dashr.run_server(app, cwd=os.path.dirname(__file__))"
296+
)
297+
273298
logger.info("Run dashR app with Rscript => %s", app)
274299
args = shlex.split(
275300
"Rscript {}".format(os.path.realpath(app)),
@@ -279,7 +304,7 @@ def start(self, app, start_timeout=2):
279304

280305
try:
281306
self.proc = subprocess.Popen(
282-
args, stdout=subprocess.PIPE, stderr=subprocess.PIPE
307+
args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd
283308
)
284309
# wait until server is able to answer http request
285310
wait.until(lambda: self.accessible(self.url), timeout=start_timeout)

dash/testing/composite.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ def __init__(self, server, **kwargs):
2121
super(DashRComposite, self).__init__(**kwargs)
2222
self.server = server
2323

24-
def start_server(self, app):
24+
def start_server(self, app, cwd=None):
2525

26-
# start server with dashR app, the dash arguments are hardcoded
27-
self.server(app)
26+
# start server with dashR app. The app sets its own run_server args
27+
# on the R side, but we support overriding the automatic cwd
28+
self.server(app, cwd=cwd)
2829

2930
# set the default server_url, it implicitly call wait_for_page
3031
self.server_url = self.server.url

0 commit comments

Comments
 (0)