Start the server with subprocess and Rscript.
(self, app, start_timeout=2, cwd=None)
| 370 | |
| 371 | # pylint: disable=arguments-differ |
| 372 | def start(self, app, start_timeout=2, cwd=None): # type: ignore[reportIncompatibleMethodOverride] |
| 373 | """Start the server with subprocess and Rscript.""" |
| 374 | |
| 375 | if os.path.isfile(app) and os.path.exists(app): |
| 376 | # app is already a file in a dir - use that as cwd |
| 377 | if not cwd: |
| 378 | cwd = os.path.dirname(app) |
| 379 | logger.info("RRunner inferred cwd from app path: %s", cwd) |
| 380 | else: |
| 381 | # app is a string chunk, we make a temporary folder to store app.R |
| 382 | # and its relevant assets |
| 383 | tmp_dir = "/tmp" if not self.is_windows else os.getenv("TEMP") |
| 384 | tmp_dir = str(tmp_dir) # to satisfy type checking |
| 385 | hex_id = uuid.uuid4().hex |
| 386 | self._tmp_app_path = os.path.join(tmp_dir, hex_id) |
| 387 | try: |
| 388 | os.mkdir(self.tmp_app_path) # type: ignore[reportArgumentType] |
| 389 | except OSError: |
| 390 | logger.exception("cannot make temporary folder %s", self.tmp_app_path) |
| 391 | path = os.path.join(self.tmp_app_path, "app.R") # type: ignore[reportCallIssue] |
| 392 | |
| 393 | logger.info("RRunner start => app is R code chunk") |
| 394 | logger.info("make a temporary R file for execution => %s", path) |
| 395 | logger.debug("content of the dashR app") |
| 396 | logger.debug("%s", app) |
| 397 | |
| 398 | with open(path, "w", encoding="utf-8") as fp: |
| 399 | fp.write(app) |
| 400 | |
| 401 | app = path |
| 402 | |
| 403 | # try to find the path to the calling script to use as cwd |
| 404 | if not cwd: |
| 405 | for entry in inspect.stack(): |
| 406 | if "/dash/testing/" not in entry[1].replace("\\", "/"): |
| 407 | cwd = os.path.dirname(os.path.realpath(entry[1])) |
| 408 | logger.warning("get cwd from inspect => %s", cwd) |
| 409 | break |
| 410 | if cwd: |
| 411 | logger.info("RRunner inferred cwd from the Python call stack: %s", cwd) |
| 412 | |
| 413 | # try copying all valid sub folders (i.e. assets) in cwd to tmp |
| 414 | # note that the R assets folder name can be any valid folder name |
| 415 | assets = [ |
| 416 | os.path.join(cwd, _) |
| 417 | for _ in os.listdir(cwd) |
| 418 | if not _.startswith("__") and os.path.isdir(os.path.join(cwd, _)) |
| 419 | ] |
| 420 | |
| 421 | for asset in assets: |
| 422 | target = os.path.join(self.tmp_app_path, os.path.basename(asset)) # type: ignore[reportCallIssue] |
| 423 | if os.path.exists(target): |
| 424 | logger.debug("delete existing target %s", target) |
| 425 | shutil.rmtree(target) |
| 426 | logger.debug("copying %s => %s", asset, self.tmp_app_path) |
| 427 | shutil.copytree(asset, target) |
| 428 | logger.debug("copied with %s", os.listdir(target)) |
| 429 |
no test coverage detected