Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not automatically activate slendr Python virtual environment upon loading the package #118

Merged
merged 13 commits into from
Jan 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,14 @@ Imports:
ijtiff,
shinyWidgets,
shiny,
rgdal,
ape
Suggests:
testthat (>= 3.0.0),
knitr,
rmarkdown,
admixr,
units,
rgdal,
magick,
cowplot,
forcats,
Expand Down
12 changes: 6 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
.PHONY: build vignettes docs
.PHONY: build docs website

version := $(shell less DESCRIPTION | grep 'Version' | sed 's/Version: \(.*\)$$/\1/')
pkg := build/slendr_$(version).tar.gz
logo := man/figures/logo.png

docs:
rm -rf docs/reference
R -e 'devtools::install(upgrade = "never")'
R -e 'devtools::document()'
R -e 'pkgdown::build_reference()'
R -e 'pkgdown::build_reference_index()'
Expand All @@ -17,13 +17,13 @@ docs:
#git restore docs/reference/world.html
#git restore docs/reference/expand_range-1.png

website: $(logo)
rm -rf docs/
website: $(logo) README.md
R -e 'devtools::install(upgrade = "never")'
R -e 'knitr::knit("README.Rmd", output = "README.md")'
R -e 'devtools::document()'
R -e 'pkgdown::build_reference()'
R -e 'pkgdown::build_reference_index()'
R -e 'pkgdown::build_news()'
R -e 'pkgdown::build_site()'
git restore docs/CNAME
# discard useless updates of temporary paths, random seed values, etc.
#git restore docs/pkgdown.yml
#git restore docs/reference/join.html
Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export(distance)
export(expand_range)
export(explore_model)
export(gene_flow)
export(init_env)
export(join)
export(move)
export(msprime)
Expand Down
12 changes: 12 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# slendr (development version)

- **<u>Minor breaking change!</u> Python environments of _slendr_ are no longer automatically activated upon calling `library(slendr)`! Using the coalescent _msprime_ back end and _slendr_'s tree-sequence functions now requires making an explicit call to a new function `init_env()` after `library(slendr)` is executed.** (PR [#102](https://github.com/bodkan/slendr/pull/118))

Motivation for the change: A small proportion of users have been experiencing issues with broken conda environments and various other issues with Python virtual environments in general. It's hard to guess how frequent this has been, but experience from workshops and courses suggests perhaps 1 in 20 of users experiencing Python issues which hindered their ability to use _slendr_ .(Fun fact: the first user-submitted GitHub issue upon releasing the first version of the _slendr_ R package was... a Python virtual environment issue).

Explanation: Activating Python environments automatically upon calling `library(slendr)` has been a popular feature because it hid away most of the complexities of the R-Python interface that powers _slendr_'s tree-sequence functionality. This was particularly convenient for many _slendr_ users, particularly those who have no experience with Python at all.

Unfortunately, in cases where a Python virtual environments with tskit/msprime/pyslim on a user's system ended up corrupted (or if anything else at the Python level got broken), the automatic Python environment activation performed by the `library(slendr)` call failed and _slendr_ was not even loaded. Sadly, this completely pulled the rug from under _slendr_ and there was nothing that could be done about it from its perspective (the issue happened at a low-level layer of embedded-Python before _slendr_ could've been loaded into R). Solving these issues was not difficult for experienced users, but many _slendr_ users have no experience with Python at all, they have never used conda, they don't understand the concept of "Python virtual environments" or how the R-Python interface works. And nor should they! After all, _slendr_ is an R package.

Splitting the Python virtual environment activation step into its own `init_env()` function means that `library(slendr)` now always succeeds (regardless of potential underlying Python issues on a user's sytem), making it much easier to diagnose and fix Python problems from R once the package is loaded.

So, to recap: `library(slendr)` no longer activates _slendr_'s isolated Python virtual environment. In order to simulate tree sequences and analyse them using its interface to _tskit_, it is necessary to call `init_env()`. This function performs the same Python-activation steps that `library(slendr)` used to call automagically in earlier _slendr_ versions. No other change to your scripts is necessary.

- When a named list is provided as a `sample_sets =` argument to a oneway statistic function, the names are used in a `set` column of the resulting data frame even if only single samples were used. ([#2a6781](https://github.com/bodkan/slendr/commit/2a6781))

- It is now possible to label groups of samples in _slendr_'s _tskit_ interface functions which should make data frames with statistics results more readable. As an example, running `ts_f3(ts, A = c("p1_1", "p1_2", "p1_3"), B = c("p2_1", "p2_3"), C = c("p3_1", "p3_2", "p3_"))` resulted in a following data-frame output:
Expand Down
6 changes: 6 additions & 0 deletions R/compilation.R
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ setting `direction = 'backward'.`", call. = FALSE)
#' @examples
#' \dontshow{check_dependencies(python = TRUE) # make sure dependencies are present
#' }
#' init_env()
#'
#' # load an example model with an already simulated tree sequence
#' path <- system.file("extdata/models/introgression", package = "slendr")
#' model <- read_model(path)
Expand Down Expand Up @@ -347,6 +349,8 @@ read_model <- function(path) {
#' @examples
#' \dontshow{check_dependencies(python = TRUE, slim = TRUE) # make sure dependencies are present
#' }
#' init_env()
#'
#' # load an example model
#' model <- read_model(path = system.file("extdata/models/introgression", package = "slendr"))
#'
Expand Down Expand Up @@ -557,6 +561,8 @@ slim <- function(
#' @examples
#' \dontshow{check_dependencies(python = TRUE) # make sure dependencies are present
#' }
#' init_env()
#'
#' # load an example model
#' model <- read_model(path = system.file("extdata/models/introgression", package = "slendr"))
#'
Expand Down
81 changes: 57 additions & 24 deletions R/interface.R
Original file line number Diff line number Diff line change
Expand Up @@ -1127,6 +1127,8 @@ area <- function(x) {
#' @examples
#' \dontshow{check_dependencies(python = TRUE) # make sure dependencies are present
#' }
#' init_env()
#'
#' # load an example model with an already simulated tree sequence
#' path <- system.file("extdata/models/introgression", package = "slendr")
#' model <- read_model(path)
Expand Down Expand Up @@ -1238,6 +1240,44 @@ schedule_sampling <- function(model, times, ..., locations = NULL, strict = FALS
schedule
}

#' Activate slendr's own dedicated Python environment
#'
#' This function attempts to activate a dedicated slendr Miniconda Python
#' environment previously set up via \code{setup_env}.
#'
#' @param quiet Should informative messages be printed to the console? Default
#' is \code{FALSE}.
#'
#' @return No return value, called for side effects
#'
#' @export
init_env <- function(quiet = FALSE) {
if (!is_slendr_env_present())
stop("Could not activate slendr's Python environment because it is not\npresent ",
"on your system ('", PYTHON_ENV, "').\n\n",
"To set up a dedicated Python environment you first need to run setup_env().", call. = FALSE)
else {
reticulate::use_condaenv(PYTHON_ENV, required = TRUE)
if (!reticulate::py_module_available("msprime") ||
!reticulate::py_module_available("tskit") ||
!reticulate::py_module_available("pyslim")) {
stop("Python environment ", PYTHON_ENV, " has been found but it",
" does not appear to have msprime, tskit and pyslim modules all",
" installed. Perhaps the environment got corrupted somehow?",
" Running `clear_env()` and `setup_env()` to reset the slendr's Python",
" environment is recommended.", call. = FALSE)
} else {
# pylib <<- reticulate::import_from_path(
# "pylib",
# path = system.file("python", package = "slendr"),
# delay_load = TRUE
# )
if (!quiet)
message("The interface to all required Python modules has been activated.")
}
}
}

#' Setup a dedicated Python virtual environment for slendr
#'
#' This function will automatically download a Python miniconda distribution
Expand All @@ -1260,41 +1300,29 @@ schedule_sampling <- function(model, times, ..., locations = NULL, strict = FALS
#' @export
setup_env <- function(quiet = FALSE, agree = FALSE, pip = NULL) {
if (is_slendr_env_present()) {
reticulate::use_condaenv(PYTHON_ENV, required = TRUE)
if (!reticulate::py_module_available("msprime") ||
!reticulate::py_module_available("tskit") ||
!reticulate::py_module_available("pyslim")) {
stop("Python environment ", PYTHON_ENV, " has been found but it",
" does not appear to have msprime, tskit and pyslim modules all",
" installed. Perhaps the environment got corrupted somehow?",
" Running `clear_env()` and `setup_env()` to reset the slendr's Python",
" environment is recommended.")
} else if (!quiet)
message("The interface to all required Python modules has been activated.")
message("A required slendr Python environment is already present. You can activate\n",
"it by calling init_env().")
} else {
if (agree)
answer <- 2
else
answer <- utils::menu(
c("No", "Yes"),
title = paste0(
"No pre-configured Python environment for slendr has been found.\n\n",
"Do you wish to install a completely isolated Miniconda Python distribution\n",
"just for slendr and create an isolated environment with all required Python\n",
"modules automatically?\n",
"\nNo need to worry, everything will be installed into a completely\n",
"separate location into an isolated environment in an R library directory.\n",
"This won't affect your other Python installations at all, whatever those\n",
"might be (standard Python installations or conda setups). You can always\n",
"wipe out the automatically created environment by running `clear_env()`.\n\n",
"This function will install a completely isolated Miniconda Python distribution\n",
"just for slendr and create an environment with all required Python modules.\n",
"\nEverything will be installed into a completely separate location into an\n",
"isolated environment in an R library directory. This won't affect your other\n",
"Python installations at all. You can always wipe out the automatically created\n",
"environment by running clear_env().\n\n",
"Do you wish to proceed with the automated Python environment setup?")
)
if (answer == 2) {
message("============================================================")
message("=======================================================================")
message("Installing slendr's Python environment. Please wait until")
message("the installation procedure finishes. Do NOT interrupt the")
message("process while the installation is still running.")
message("============================================================\n")
message("======================================================================\n")
Sys.sleep(10)

if (!dir.exists(reticulate::miniconda_path()))
Expand All @@ -1318,9 +1346,13 @@ setup_env <- function(quiet = FALSE, agree = FALSE, pip = NULL) {

reticulate::conda_install(envname = PYTHON_ENV, packages = deps, pip = pip)

if (!quiet)
if (!quiet) {
message("======================================================================")
message("Python environment for slendr has been successfuly created, and ",
"the R\ninterface to msprime, tskit, and pyslim modules has been activated.")
"the R\ninterface to msprime, tskit, and pyslim modules has been activated.\n")
message("In future sessions, activate this environment by calling init_env().")
message("=======================================================================")
}
} else
warning("Your Python environment is not set up correctly which means that the tree\n",
"sequence functionality of slendr will not work.", call. = FALSE)
Expand Down Expand Up @@ -1371,6 +1403,7 @@ clear_env <- function(force = FALSE) {
#' @examples
#' \dontshow{check_dependencies(python = TRUE) # make sure dependencies are present
#' }
#' init_env()
#' check_env()
#' @export
check_env <- function(verbose = TRUE) {
Expand Down
Loading