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 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
python_has_modules <- function(python, modules) {
# write code to tempfile
file <- tempfile("reticulate-python-", fileext = ".py")
code <- paste("import", modules)
writeLines(code, con = file)
on.exit(unlink(file), add = TRUE)
# invoke Python
status <- system2(python, shQuote(file), stdout = FALSE, stderr = FALSE)
status == 0L
}
python_has_module <- function(python, module) {
code <- paste("import", module)
args <- c("-E", "-c", shQuote(code))
status <- system2(python, args, stdout = FALSE, stderr = FALSE)
status == 0L
}
python_version <- function(python) {
code <- "import platform; print(platform.python_version())"
args <- c("-E", "-c", shQuote(code))
output <- system2(python, args, stdout = TRUE, stderr = FALSE)
sanitized <- gsub("[^0-9.-]", "", output)
numeric_version(sanitized)
}
python_module_version <- function(python, module) {
fmt <- "import %1$s; print(%1$s.__version__)"
code <- sprintf(fmt, module)
args <- c("-E", "-c", shQuote(code))
output <- system2(python, args, stdout = TRUE, stderr = FALSE)
numeric_version(output)
}
# given the path to a python binary, or an environment path,
# try to find the path to the associated python binary, and
# figure out if it's a virtualenv, conda environment, or none
python_info <- function(path) {
path <- path.expand(path)
parent <- dirname(path)
# NOTE: we check for both 'python' and 'python3' because certain python
# installations might install one version of the binary but not the other.
#
# Some installations might not place Python within a 'Scripts' or 'bin'
# sub-directory, so look in the root directory too.
prefixes <- list(NULL, if (is_windows()) "Scripts" else "bin")
suffixes <- if (is_windows())
"python.exe"
else if (startsWith(basename(path), "python3"))
"python3" # don't resolve 'python' for 'python3'
else
c("python", "python3")
# placeholder for a discovered system python
systemPython <- NULL
while (path != parent) {
# check for virtual environment files
files <- c(
"pyvenv.cfg", # created by venv
file.path(prefixes[[2L]], "activate_this.py") # created by virtualenv
)
paths <- file.path(path, files)
virtualenv <- any(file.exists(paths))
# extra check that we aren't in a conda environment
condapath <- file.path(path, "condabin/conda")
if (file.exists(condapath))
virtualenv <- FALSE
if (virtualenv)
return(python_info_virtualenv(path))
# check for conda environment files
condaenv <- file.exists(file.path(path, "conda-meta"))
if (condaenv)
return(python_info_condaenv(path))
# check for python binary (implies a system install)
# we don't return immediately here because we might find
# as we traverse upwards that some of the expected virtualenv
# or condaenv files exist, so we just save the path and use
# it later if appropriate
if (is.null(systemPython)) {
for (prefix in prefixes) {
for (suffix in suffixes) {
bin <- paste(c(path, prefix, suffix), collapse = "/")
if (file.exists(bin)) {
systemPython <- bin
break
}
}
}
}
# recurse
parent <- path
path <- dirname(path)
}
# if we found a system python, use that as the fallback
if (!is.null(systemPython))
return(python_info_system(dirname(systemPython), systemPython))
stopf("could not find a Python environment for %s", path)
}
python_info_virtualenv <- function(path) {
# form path to python binary
suffix <- if (is_windows()) "Scripts/python.exe" else "bin/python"
python <- file.path(path, suffix)
# return details
out <- list(
python = python,
type = "virtualenv",
root = path
)
if (file.exists(cfg <- file.path(out$root, "pyvenv.cfg"))) {
starter <- grep("^home = ", readLines(cfg), value = TRUE)
if(length(starter))
out$starter <- str_drop_prefix(starter, "home = ")
}
out
}
python_info_condaenv <- function(path) {
# form path to python binary
suffix <- if (is_windows()) "python.exe" else "bin/python"
python <- file.path(path, suffix)
# find path to conda associated with this env
conda <- get_python_conda_info(python)$conda
list(
python = python,
type = "conda",
root = path,
conda = conda
)
}
python_info_system <- function(path, python) {
list(
python = python,
type = "system",
root = path
)
}
|