Skip to content

python discovery for reticulate can cause inspection errors #1207

@aronatkins

Description

@aronatkins

related also to this issue and maybe this is just more details on this specific issue.

When you try to deploy an app that has ragnar as a dependency AND you have used ragnar in a way that generated the ephemeral python environment as described in the original issue, you get the following error during deployment to Connect.

ℹ Capturing R dependencies from renv.lock
✔ Found 72 dependencies
Error in pythonConfig():
! Failed to detect python environment
Caused by error in system2():
! error in running command
Backtrace:

  1. ├─rsconnect::deployApp(...)
  2. │ └─rsconnect:::bundleApp(...)
  3. │ └─rsconnect:::createAppManifest(...)
  4. │ └─rsconnect (local) pythonConfig(appDir)
  5. │ ├─base::withCallingHandlers(...)
  6. │ └─rsconnect:::inferPythonEnv(appDir, python = python, forceGenerate = forceGenerate)
  7. │ └─base::system2(...)
  8. └─rsconnect (local) <fn>(<cmdError>)
  9. └─cli::cli_abort("Failed to detect python environment", parent = err)
  10. └─rlang::abort(...)
    

Execution halted

This happens because python is retrieved by the getPython function when the option of "rsconnect.python.enabled is set to TRUE.

    pythonEnabled <- getOption("rsconnect.python.enabled", !targetIsShinyapps)
    if (pythonEnabled) {
        getPython(path)

The function rsconnect::inferPythonEnv uses the value of python = getPython(), which will return NULL in this case, since it is just using the call Sys.getenv("RETICULATE_PYTHON"). The method used by reticulate described in the original issues above does not set any environment variables. Additionally, conda is not used in this case either.

The way inferPythonEnv works, is shown below:

rsconnect:::inferPythonEnv
function (workdir, python = getPython(), forceGenerate = FALSE) 
{
    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)
        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)
    }

So when python is NULL and conda is not used, the system2(command = python, .... will fail with the error I pasted above.

It is interesting, since in logical case where conda exists, the python is extracted from the reticulate::py_config()$anaconda variable.

So perhaps the inferPythonEnv function should instead be using the reticulate::py_config()$python location when reticulate is installed, like this?

    hasVirtualEnv <- is_installed("reticulate") && reticulate::py_available(initialize = FALSE) && 
        !reticulate::py_config()$anaconda
  
   if(hasVirtualEnv) python <- reticulate::py_config()$python

Since reticulate is already a suggested package, and in this case, you are already checking for reticulate being installed, perhaps this logical case would properly find the python reticulate is using in a cleaner way?
Tagging @t-kalinowski, @aronatkins and @nealrichardson since I discussed this issue with them.

Originally posted by @SokolovAnatoliy in #1143

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions