File: bundlePython.R

package info (click to toggle)
r-cran-rsconnect 1.3.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,044 kB
  • sloc: python: 185; sh: 13; makefile: 5
file content (118 lines) | stat: -rw-r--r-- 3,150 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# Create anonymous function that we can later call to get all needed python
# metdata for the manifest
pythonConfigurator <- function(python,
                               forceGenerate = FALSE) {

  if (is.null(python)) {
    return(NULL)
  }

  force(forceGenerate)

  function(appDir) {
    withCallingHandlers(
      inferPythonEnv(
        appDir,
        python = python,
        forceGenerate = forceGenerate
      ),
      error = function(err) {
        cli::cli_abort(
          "Failed to detect python environment",
          parent = err
        )
      }
    )
  }
}

# python is enabled on Connect and posit.cloud, but not on Shinyapps
getPythonForTarget <- function(path, accountDetails) {
  targetIsShinyapps <- isShinyappsServer(accountDetails$server)
  pythonEnabled <- getOption("rsconnect.python.enabled", !targetIsShinyapps)
  if (pythonEnabled) {
    getPython(path)
  } else {
    NULL
  }
}

getPython <- function(path = NULL) {
  if (!is.null(path)) {
    return(path.expand(path))
  }

  path <- Sys.getenv("RETICULATE_PYTHON")
  if (path != "") {
    return(path.expand(path))
  }

  path <- Sys.getenv("RETICULATE_PYTHON_FALLBACK")
  if (path != "") {
    return(path.expand(path))
  }

  NULL
}

inferPythonEnv <- function(workdir,
                           python = getPython(),
                           forceGenerate = FALSE) {
  # run the python introspection script
  env_py <- system.file("resources/environment.py", package = "rsconnect")
  args <- c(
    shQuote(env_py),
    if (forceGenerate) "-f",
    shQuote(workdir)
  )

  hasConda <- is_installed("reticulate") &&
    reticulate::py_available(initialize = FALSE) &&
    reticulate::py_config()$anaconda

  if (hasConda) {
    prefix <- getCondaEnvPrefix(python)
    conda <- getCondaExeForPrefix(prefix)
    args <- c("run", "-p", prefix, python, args)
    # conda run -p <prefix> python inst/resources/environment.py <flags> <dir>
    output <- system2(command = conda, args = args, stdout = TRUE, stderr = NULL, wait = TRUE)
  } else {
    output <- system2(command = python, args = args, stdout = TRUE, stderr = NULL, wait = TRUE)
  }

  environment <- jsonlite::fromJSON(output)
  if (is.null(environment$error)) {

    list(
      version = environment$python,
      package_manager = list(
        name = environment$package_manager,
        version = environment[[environment$package_manager]],
        package_file = environment$filename,
        contents = environment$contents
      )
    )
  } else {
    cli::cli_abort(environment$error)
  }
}

getCondaEnvPrefix <- function(python) {
  prefix <- dirname(dirname(python))
  if (!file.exists(file.path(prefix, "conda-meta"))) {
    stop(paste("Python from", python, "does not look like a conda environment: cannot find `conda-meta`"))
  }
  prefix
}

getCondaExeForPrefix <- function(prefix) {
  miniconda <- dirname(dirname(prefix))
  conda <- file.path(miniconda, "bin", "conda")
  if (isWindows()) {
    conda <- paste(conda, ".exe", sep = "")
  }
  if (!file.exists(conda)) {
    stop(paste("Conda env prefix", prefix, "does not have the `conda` command line interface."))
  }
  conda
}