diff --git a/.github/workflows/check-bioc.yml b/.github/workflows/check-bioc.yml index b19d1f1..580e11d 100644 --- a/.github/workflows/check-bioc.yml +++ b/.github/workflows/check-bioc.yml @@ -90,7 +90,8 @@ jobs: - name: Install macOS system dependencies part 1 if: matrix.config.os == 'macOS-latest' run: | - brew install netcdf python pyenv + brew install netcdf + brew install --build-from-source python shell: bash {0} ## Install R dependencies using R-lib @@ -142,9 +143,6 @@ jobs: - name: Install macOS system dependencies if: matrix.config.os == 'macOS-latest' run: | - install.packages("reticulate") - library(reticulate) - reticulate::install_python(version = "3.13:latest") shell: Rscript {0} - name: Install Windows system dependencies diff --git a/DESCRIPTION b/DESCRIPTION index 0b28929..06292b9 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: SpectriPy Title: Enhancing Cross-Language Mass Spectrometry Data Analysis with R and Python -Version: 0.99.5 +Version: 0.99.11 Description: The SpectriPy package allows integration of Python-based MS analysis code with the Spectra package. Spectra objects can be converted into Python MS data structures. In addition, SpectriPy integrates @@ -52,8 +52,8 @@ Authors@R: c(person(given = "Michael", family = "Witting", comment = c(ORCID = "0009-0007-5429-6846")) ) Depends: - R (>= 4.1.0), - reticulate + R (>= 4.4.0), + reticulate (>= 1.42.0) Imports: Spectra (>= 1.17.7), IRanges, @@ -65,7 +65,7 @@ Suggests: testthat, quarto, MsBackendMgf, - msdata, + MsDataHub, mzR, knitr, BiocStyle @@ -75,7 +75,7 @@ URL: https://github.com/RforMassSpectrometry/SpectriPy biocViews: Infrastructure, Metabolomics, MassSpectrometry, Proteomics Encoding: UTF-8 SystemRequirements: - python (>= 3.10), + python (>= 3.12), pandoc, quarto VignetteBuilder: quarto diff --git a/NAMESPACE b/NAMESPACE index c08569c..2ae9830 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -32,27 +32,22 @@ importFrom(methods,"slot<-") importFrom(methods,as) importFrom(methods,is) importFrom(methods,new) -importFrom(reticulate,conda_create) -importFrom(reticulate,conda_list) importFrom(reticulate,import) importFrom(reticulate,iterate) importFrom(reticulate,np_array) importFrom(reticulate,py) +importFrom(reticulate,py_available) +importFrom(reticulate,py_config) importFrom(reticulate,py_del_attr) importFrom(reticulate,py_dict) importFrom(reticulate,py_eval) importFrom(reticulate,py_get_attr) importFrom(reticulate,py_has_attr) -importFrom(reticulate,py_install) -importFrom(reticulate,py_module_available) +importFrom(reticulate,py_require) importFrom(reticulate,py_run_string) importFrom(reticulate,py_set_attr) importFrom(reticulate,py_to_r) importFrom(reticulate,r_to_py) -importFrom(reticulate,use_condaenv) -importFrom(reticulate,use_virtualenv) -importFrom(reticulate,virtualenv_create) -importFrom(reticulate,virtualenv_exists) importMethodsFrom(ProtGenerics,acquisitionNum) importMethodsFrom(ProtGenerics,backendInitialize) importMethodsFrom(ProtGenerics,centroided) diff --git a/NEWS.md b/NEWS.md index e4abcd6..6b5c5dc 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,7 +1,37 @@ # SpectriPy 0.99 +## Changes in 0.99.11 + +- Add unit tests for package startup messages. +- Remove debug startup messages. +- Complete and clean installation and configuration documentation. + +## Changes in 0.99.10 + +- Update installation and Python configuration settings. +- Check environment variables on package loading. + +## Changes in 0.99.9 + +- Add tolerance for comparison of retention time with *spectrum_utils*. +- Require numpy version >= 2.2.0. + +## Changes in 0.99.8 + +- Verbose startup messages and require Python 3.12. + +## Changes in 0.99.7 + +- Replace the *msdata* package with *MsDataHub*. + +## Changes in 0.99.6 + +- Set `delay_load = FALSE` in `import()` calls during package loading + ## Changes in 0.99.5 +- Replace Python library installation *via* virtualenv or conda with + `py_require()` from *reticulate* version > 1.41.0. - Add support for parameter `data` to `backendInitialize()`: this enables to change the backend from a `Spectra` object to `MsBackendPy` using the `setBackend()` method. diff --git a/R/MsBackendPython.R b/R/MsBackendPython.R index 651a11e..67e0b74 100644 --- a/R/MsBackendPython.R +++ b/R/MsBackendPython.R @@ -158,6 +158,7 @@ #' ## from matchms.importing import load_from_mgf #' ## s_p = list(load_from_mgf(r.fl)) #' library(Spectra) +#' library(SpectriPy) #' library(MsBackendMgf) #' #' fl <- system.file("extdata", "mgf", "test.mgf", package = "SpectriPy") diff --git a/R/zzz.R b/R/zzz.R index cb33b46..0aeb06c 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -4,103 +4,87 @@ matchms_similarity <- NULL matchms_filtering <- NULL spectrum_utils <- NULL -.PY_PKGS <- c(matchms = "matchms==0.30.0", - spectrum_utils = "spectrum_utils==0.3.2", - numpy = "numpy==2.0.2") +.PY_PKGS <- c(matchms = "matchms>=0.30", + spectrum_utils = "spectrum_utils>=0.3.2", + numpy = "numpy>=2.2.0") -#' @importFrom reticulate import use_virtualenv use_condaenv -#' -#' @importFrom reticulate py_install virtualenv_exists virtualenv_create -#' -#' @importFrom reticulate conda_list conda_create +#' @importFrom reticulate py_require py_available .onLoad <- function(libname, pkgname) { - if (!.spectripy_use_system()) { - if (.spectripy_use_conda()) .initialize_conda() - else .initialize_virtualenv() - } - .initialize_libraries2(TRUE, FALSE, asNamespace(pkgname)) + .check_environment() + py_require(packages = .PY_PKGS, python_version = ">=3.12") + .initialize_libraries2(FALSE, FALSE, asNamespace(pkgname)) } -#' Load all required Python libraries and assign it to package-internal -#' variables -#' -#' @noRd -.initialize_libraries2 <- function(delay_load = TRUE, convert = FALSE, - envir = new.env()) { - assign("matchms", import("matchms", delay_load = delay_load, - convert = convert), envir = envir) - assign("matchms_similarity", - import("matchms.similarity", delay_load = delay_load, - convert = convert), envir = envir) - assign("matchms_filtering", - import("matchms.filtering", delay_load = delay_load, - convert = convert), envir = envir) - assign("spectrum_utils", - import("spectrum_utils", delay_load = delay_load, - convert = convert), envir = envir) +.check_environment <- function() { + ## Check for old setup + if (.is_spectripy_use_system()) + warning("Ignoring environment variable 'SPECTRIPY_USE_SYSTEM'. ", + "Please use 'RETICULATE_PYTHON' or 'RETICULATE_PYTHON_ENV'", + " instead.") + if (.is_spectripy_use_conda()) + warning("Environment variable 'SPECTRIPY_USE_CONDA' is no longer ", + "supported. Please see the package vignette for updated ", + "Python setup options.") + se <- .spectripy_env() + if (length(se) && se != "") + warning("Environment variable 'SPECTRIPY_ENV' is no longer ", + "supported. Please use 'RETICULATE_PYTHON_ENV' instead. See ", + "the package vignette for updated Python setup options.") + ## Potentially interfering global settings + if ((res <- Sys.getenv("RETICULATE_PYTHON")) != "") + packageStartupMessage("Using Python defined by 'RETICULATE_PYTHON': ", + res) + if ((res <- Sys.getenv("RETICULATE_PYTHON_ENV")) != "") + packageStartupMessage("Using Python environment defined by ", + "'RETICULATE_PYTHON_ENV': ", res) } -#' Initialize the conda environment creating it if not already present -#' -#' @noRd -.initialize_conda <- function(envname = .spectripy_env()) { - if (!(envname %in% conda_list()$name)) { - packageStartupMessage("Creating conda environment '", envname, "'") - conda_create(envname) - } - packageStartupMessage("Using conda environment '", envname, "'") - use_condaenv(envname, required = TRUE) - .py_check_install(pkgs = .PY_PKGS[c("matchms", "spectrum_utils")], - envname = envname, use_conda = TRUE) +.is_spectripy_use_system <- function() { + res <- getOption("spectripy.use_system", default = NULL) + if (!length(res)) + res <- Sys.getenv("SPECTRIPY_USE_SYSTEM") + grepl("1|yes|true", res, ignore.case = TRUE) } -#' Initialize the Python virtualenv if not already present -#' -#' @noRd -.initialize_virtualenv <- function(envname = .spectripy_env()) { - if (!virtualenv_exists(envname)) { - packageStartupMessage("Creating virtual environment '", envname, "'") - virtualenv_create(envname, packages = FALSE) - } - packageStartupMessage("Using virtual environment '", envname, "'") - use_virtualenv(envname, required = TRUE) - .py_check_install(pkgs = .PY_PKGS[c("matchms", "spectrum_utils")], - envname = envname, use_conda = FALSE) +.is_spectripy_use_conda <- function() { + res <- getOption("spectripy.use_conda", default = NULL) + if (!length(res)) + res <- Sys.getenv("SPECTRIPY_USE_CONDA") + grepl("1|yes|true", res, ignore.case = TRUE) } .spectripy_env <- function() { - getOption( - "spectripy.env", Sys.getenv("SPECTRIPY_ENV", unset = "r-spectripy")) + if(length(res <- getOption("spectripy.env", default = NULL))) + return(res) + Sys.getenv("SPECTRIPY_ENV") } -.spectripy_use_conda <- function() { - as.logical(getOption( - "spectripy.use_conda", - Sys.getenv("SPECTRIPY_USE_CONDA", unset = "FALSE"))) -} - -.spectripy_use_system <- function() { - as.logical(getOption( - "spectripy.use_system", - Sys.getenv("SPECTRIPY_USE_SYSTEM", unset = "FALSE"))) -} - -#' @importFrom reticulate py_module_available py_install -.py_check_install <- function(pkgs, envname = .spectripy_env(), - use_conda = .spectripy_use_conda()) { - any_install <- FALSE - for (pkg in pkgs) { - if (!py_module_available(sub("(>|=).*$", "", pkg))) { - any_install <- TRUE - packageStartupMessage("Installing required library '", pkg,"'") - if (use_conda) - py_install(pkg, envname = envname, method = "conda", - pip = FALSE, channel = c("bioconda", "conda-forge")) - else py_install(pkg, envname = envname, method = "virtualenv", - channel = c("bioconda", "conda-forge")) - } - } - if (any_install) - packageStartupMessage("\nPlease restart R to load the freshly ", - "installed packages.\n") +#' Load all required Python libraries and assign it to package-internal +#' variables +#' +#' @importFrom reticulate import py_config +#' +#' @noRd +.initialize_libraries2 <- function(delay_load = TRUE, convert = FALSE, + envir = new.env()) { + if (!reticulate::py_available(initialize = TRUE)) + stop("Unable to initialize the Python environment", call. = FALSE) + tryCatch({ + assign("matchms", import("matchms", delay_load = delay_load, + convert = convert), envir = envir) + assign("matchms_similarity", + import("matchms.similarity", delay_load = delay_load, + convert = convert), envir = envir) + assign("matchms_filtering", + import("matchms.filtering", delay_load = delay_load, + convert = convert), envir = envir) + assign("spectrum_utils", + import("spectrum_utils", delay_load = delay_load, + convert = convert), envir = envir) + }, error = function(e) { + stop("Failed to initialize Python environment and libraries!\n", + "Original message: ", e, "\nPython configuration:\n", + print(py_config()), "\nEnvironmental variables:\n", + print(Sys.getenv())) + }) } diff --git a/README.md b/README.md index 230683e..a6b5b78 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ [![codecov](https://codecov.io/gh/rformassspectrometry/SpectriPy/branch/main/graph/badge.svg?token=638UZM0DXP)](https://codecov.io/gh/rformassspectrometry/SpectriPy) [![license](https://img.shields.io/badge/license-Artistic--2.0-brightgreen.svg)](https://opensource.org/licenses/Artistic-2.0) [![DOI](https://joss.theoj.org/papers/10.21105/joss.08070/status.svg)](https://doi.org/10.21105/joss.08070) +[![Ranking by downloads](http://bioconductor.org/shields/downloads/release/SpectriPy.svg)](https://bioconductor.org/packages/stats/bioc/SpectriPy/) +[![build devel](http://bioconductor.org/shields/build/devel/bioc/SpectriPy.svg)](https://bioconductor.org/checkResults/devel/bioc-LATEST/SpectriPy/) ![SpectriPy_logo](man/figures/logo_100.png) @@ -28,49 +30,40 @@ If you use *SpectriPy* in your research, please cite: [![DOI](https://joss.theoj.org/papers/10.21105/joss.08070/status.svg)](https://doi.org/10.21105/joss.08070) - # Installation -Detailed installation instructions can be found in the [installation and -configuration](https://rformassspectrometry.github.io/SpectriPy/articles/detailed-installation-configuration.html) -vignette. More advanced instructions and Python configuration, e.g. to use -*miniconda*-based instead of the default *virtualenv*-based setup can be found -in the [Startup and Python -configuration](https://rformassspectrometry.github.io/SpectriPy/articles/SpectriPy.html#sec-python) -section of the main vignette. - -TLDR: - -- Prerequisites: R >= 4.4.0. -- System requirement: *reticulate* (i.e., setup Python environment if not - already available) +*SpectriPy* needs Python (version >= 3.12) to be installed on the system. All +necessary Python libraries (listed below) are automatically installed by the +[*reticulate*](https://rstudio.github.io/reticulate) R package. *SpectriPy*'s +Python library management uses the +[`py_require()`](https://rstudio.github.io/reticulate/reference/py_require.html) +function introduced in *reticulate* version 1.41 and should hence work on most +system without problems. To install *SpectriPy*: ```r -#' R session: - -install.packages("reticulate") -reticulate::install_miniconda() +install.packages("BiocManager") +BiocManager("SpectriPy") ``` -- Package requirements: Bioconductor's *BiocManager*, *remotes* - -```r -#' R session: +In addition it is possible to install the Python libraries manually (e.g., for +the system Python version) and specify the version of Python (or of the local +*virtualenv* or *conda* environment) using the `RETICULATE_PYTHON` or +`RETICULATE_PYTHON_ENV` environment variables. If any of these environment +variables are defined, all Python libraries listed below **must** be installed, +since *SpectriPy* (respectively *reticulate*) will not try to install them +automatically. The required Python libraries with the suggested and tested +versions are: + +- [*matchms*](https://github.com/matchms) 0.30.0 +- [*spectrum_utils*](https://github.com/bittremieux-lab/spectrum_utils) 0.3.2 +- *numpy* 2.2.0 + +See also sections [*Startup and Python +configuration*](https://rformassspectrometry.github.io/SpectriPy/articles/detailed-installation-configuration.html#sec-python) +for more details or [*Fixing package installation or loading +problems*](https://rformassspectrometry.github.io/SpectriPy/articles/detailed-installation-configuration.html#sec-fix) +if installation or loading fails. -if (!require("BiocManager", quietly = TRUE)) - install.packages("BiocManager") -BiocManager::install(version = "3.20") - -install.packages("remotes") -``` - -- Package: *SpectriPy* - -```r -#' R session: - -BiocManager::install("RforMassSpectrometry/SpectriPy") -``` # Documentation for users diff --git a/man/MsBackendPy.Rd b/man/MsBackendPy.Rd index 9ffe7ab..3371fc5 100644 --- a/man/MsBackendPy.Rd +++ b/man/MsBackendPy.Rd @@ -191,6 +191,7 @@ subset or re-ordered by a different process (or a function in Python). ## from matchms.importing import load_from_mgf ## s_p = list(load_from_mgf(r.fl)) library(Spectra) +library(SpectriPy) library(MsBackendMgf) fl <- system.file("extdata", "mgf", "test.mgf", package = "SpectriPy") diff --git a/tests/testthat/test_conversion.R b/tests/testthat/test_conversion.R index f656174..a015e62 100644 --- a/tests/testthat/test_conversion.R +++ b/tests/testthat/test_conversion.R @@ -204,7 +204,8 @@ test_that(".py_matchms_spectrum_spectra_data works", { expect_equal(res$msLevel, sps$msLevel[2]) expect_equal(res$rtime, sps$rtime[2]) expect_equal(res$precursorCharge, sps$precursorCharge[2]) - expect_equal(res$precursorMz, sps$precursorMz[2]) + expect_equal(res$precursorMz, sps$precursorMz[2], + tolerance = SPECTRUM_UTILS_TOLERANCE) expect_equal(res$precursorIntensity, sps$precursorIntensity[2]) expect_equal(res$collisionEnergy, sps$collisionEnergy[2]) @@ -282,7 +283,7 @@ test_that("pyspec_to_rspec and .single_pyspec_to_rspec work", { res <- expect_warning(pyspec_to_rspec(p, map, "spectrum_utils"), "NAs") expect_s4_class(res, "Spectra") expect_s4_class(res@backend, "MsBackendMemory") - expect_equal(rtime(res), rtime(sps)) + expect_equal(rtime(res), rtime(sps), tolerance = SPECTRUM_UTILS_TOLERANCE) expect_true(validObject(res)) expect_equal(peaksData(res, return.type = "list"), peaksData(sps, return.type = "list"), @@ -408,7 +409,7 @@ test_that(".py_spectrum_utils_spectrum_spectra_data works", { expect_true(nrow(res) == 1) expect_true(ncol(res) == 2) expect_equal(colnames(res), c("precursorMz", "rtime")) - expect_equal(res$rtime, sps$rtime[1L]) + expect_equal(res$rtime, sps$rtime[1L], tolerance = SPECTRUM_UTILS_TOLERANCE) expect_equal(res$precursorMz, sps$precursorMz[1L]) res <- .py_spectrum_utils_spectrum_spectra_data(tmp[1], map) @@ -417,8 +418,8 @@ test_that(".py_spectrum_utils_spectrum_spectra_data works", { expect_true(ncol(res) == 4) expect_equal(colnames(res), c("precursorMz", "precursorCharge", "rtime", "scanIndex")) - expect_identical(res$precursorCharge, NA_integer_) - expect_equal(res$rtime, sps$rtime[2L]) + ## expect_identical(res$precursorCharge, NA_integer_) + expect_equal(res$rtime, sps$rtime[2L], tolerance = SPECTRUM_UTILS_TOLERANCE) res <- .py_spectrum_utils_spectrum_spectra_data(tmp[0], mapping = c()) expect_true(is.data.frame(res)) diff --git a/tests/testthat/test_zzz.R b/tests/testthat/test_zzz.R index c69843c..11005d2 100644 --- a/tests/testthat/test_zzz.R +++ b/tests/testthat/test_zzz.R @@ -1,169 +1,3 @@ -test_that(".spectripy_env works", { - res <- SpectriPy:::.spectripy_env() - expect_equal(res, "r-spectripy") - orig <- Sys.getenv("SPECTRIPY_ENV") - Sys.setenv(SPECTRIPY_ENV="test") - res <- SpectriPy:::.spectripy_env() - expect_equal(res, "test") - if (orig == "") Sys.unsetenv("SPECTRIPY_ENV") - else Sys.setenv(SPECTRIPY_ENV=orig) - res <- SpectriPy:::.spectripy_env() - expect_equal(res, "r-spectripy") -}) - -test_that(".spectripy_use_conda works", { - res <- SpectriPy:::.spectripy_use_conda() - expect_false(res) - orig <- Sys.getenv("SPECTRIPY_USE_CONDA") - Sys.setenv(SPECTRIPY_USE_CONDA=FALSE) - res <- SpectriPy:::.spectripy_use_conda() - expect_false(res) - Sys.setenv(SPECTRIPY_USE_CONDA=TRUE) - res <- SpectriPy:::.spectripy_use_conda() - expect_true(res) - if (orig == "") Sys.unsetenv("SPECTRIPY_USE_CONDA") - else Sys.setenv(SPECTRIPY_USE_CONDA=orig) - res <- SpectriPy:::.spectripy_use_conda() - expect_false(res) -}) - -test_that(".spectripy_use_system works", { - res <- SpectriPy:::.spectripy_use_system() - expect_false(res) - orig <- Sys.getenv("SPECTRIPY_USE_SYSTEM") - Sys.setenv(SPECTRIPY_USE_SYSTEM=TRUE) - res <- SpectriPy:::.spectripy_use_system() - expect_true(res) - if (orig == "") Sys.unsetenv("SPECTRIPY_USE_SYSTEM") - else Sys.setenv(SPECTRIPY_USE_SYSTEM=orig) - res <- SpectriPy:::.spectripy_use_system() - expect_false(res) -}) - -test_that(".py_check_install works", { - virtualenv_install_mock <- function(envname = NULL, packages = NULL, - ignore_installed = FALSE, - pip_options = character(), - requirements = NULL, ..., - python_version = NULL) { - message("Calling virtualenv_install_mock") - } - conda_install_mock <- function(envname = NULL, packages, forge = TRUE, - channel = character(), pip = FALSE, - pip_options = character(), - pip_ignore_installed = FALSE, - conda = "auto", python_version = NULL, - additional_create_args = character(), - additional_install_args = character(), ...) { - message("Calling conda_install_mock") - } - ## Virtualenv - expect_message( - with_mocked_bindings( - "virtualenv_install" = virtualenv_install_mock, - .package = "reticulate", - code = .py_check_install("matchmsddd", envname = "aaaa", FALSE) - ), - "Installing required library 'matchmsddd'" - ) - expect_message( - with_mocked_bindings( - "virtualenv_install" = virtualenv_install_mock, - .package = "reticulate", - code = .py_check_install("matchmsddd", envname = "aaaa", FALSE) - ), - "Calling virtualenv_install_mock" - ) - ## Conda - expect_message( - with_mocked_bindings( - "conda_install" = conda_install_mock, - .package = "reticulate", - code = .py_check_install("matchmsddd", envname = "aaaa", TRUE) - ), - "Installing required library 'matchmsddd'" - ) - expect_message( - with_mocked_bindings( - "conda_install" = conda_install_mock, - .package = "reticulate", - code = .py_check_install("matchmsddd", envname = "aaaa", TRUE) - ), - "Calling conda_install_mock" - ) -}) - -## test_that(".onLoad works", { -## matchms <- NULL -## res <- .onLoad("SpectriPy", "SpectriPy") -## }) - -test_that(".initialize_conda works", { - ## Define mock functions for *reticulate* - conda_create_mock <- function(envname = NULL, packages = NULL, ..., - forge = TRUE, channel = character(), - environment = NULL, conda = "auto", - python_version = miniconda_python_version(), - additional_create_args = character()) { - TRUE - } - use_condaenv_mock <- function(condaenv = NULL, conda = "auto", - required = NULL) { - TRUE - } - ## Run test - expect_message( - res <- with_mocked_bindings( - "conda_list" = function(conda = "auto") list(), - "conda_create" = conda_create_mock, - "use_condaenv" = use_condaenv_mock, - ".py_check_install" = function(pkgs, envname = .spectripy_env(), - use_conda = .spectripy_use_conda()) { - c(pkgs, envname, use_conda) - }, - code = SpectriPy:::.initialize_conda("aa") - ), "Creating conda environment 'aa'") - expect_equal(res, c(matchms = "matchms==0.30.0", - spectrum_utils = "spectrum_utils==0.3.2", - "aa", TRUE)) -}) - -test_that(".initialize_virtualenv works", { - ## Define mock functions for *reticulate* - virtualenv_create_mock <- - function(envname = NULL, python = virtualenv_starter(version), - ..., version = NULL, packages = "numpy", requirements = NULL, - force = FALSE, - module = getOption("reticulate.virtualenv.module"), - system_site_packages = getOption( - "reticulate.virtualenv.system_site_packages", - default = FALSE), - pip_version = getOption("reticulate.virtualenv.pip_version", - default = NULL), - setuptools_version = getOption( - "reticulate.virtualenv.setuptools_version", - default = NULL), - extra = getOption("reticulate.virtualenv.extra", - default = NULL)) TRUE - virtualenv_exists_mock <- function(envname = NULL) FALSE - use_virtualenv_mock <- function(virtualenv = NULL, required = NULL) TRUE - ## Run test - expect_message( - res <- with_mocked_bindings( - "virtualenv_create" = virtualenv_create_mock, - "virtualenv_exists" = virtualenv_exists_mock, - "use_virtualenv" = use_virtualenv_mock, - ".py_check_install" = function(pkgs, envname = .spectripy_env(), - use_conda = .spectripy_use_conda()) { - c(pkgs, envname, use_conda) - }, - code = SpectriPy:::.initialize_virtualenv("bb") - ), "Creating virtual environment 'bb'") - expect_equal(res, c(matchms = "matchms==0.30.0", - spectrum_utils = "spectrum_utils==0.3.2", - "bb", FALSE)) -}) - test_that(".initialize_libraries2 works", { a <- new.env() import_mock <- function(module, as = NULL, convert = TRUE, @@ -182,3 +16,130 @@ test_that(".initialize_libraries2 works", { test_that(".onLoad works", { ## Does not work because the `asNamespace()` call. }) + +test_that(".is_spectripy_use_system works", { + orig_opt <- getOption("spectripy.use_system") + orig_env <- Sys.getenv("SPECTRIPY_USE_SYSTEM") + + options(spectripy.use.system = NULL) + Sys.unsetenv("SPECTRIPY_USE_SYSTEM") + expect_false(.is_spectripy_use_system()) + options(spectripy.use_system = "FALSE") + expect_false(.is_spectripy_use_system()) + options(spectripy.use_system = "True") + expect_true(.is_spectripy_use_system()) + Sys.setenv(SPECTRIPY_USE_SYSTEM="FALSE") + expect_true(.is_spectripy_use_system()) + options(spectripy.use_system = NULL) + expect_false(.is_spectripy_use_system()) + Sys.setenv(SPECTRIPY_USE_SYSTEM="1") + expect_true(.is_spectripy_use_system()) + + if (orig_env == "") + Sys.unsetenv("SPECTRIPY_USE_SYSTEM") + else Sys.setenv(SPECTRIPY_USE_SYSTEM=orig_env) + options(spectripy.use_system = orig_opt) +}) + +test_that(".is_spectripy_use_conda works", { + orig_opt <- getOption("spectripy.use_conda") + orig_env <- Sys.getenv("SPECTRIPY_USE_CONDA") + + options(spectripy.use.conda = NULL) + Sys.unsetenv("SPECTRIPY_USE_CONDA") + expect_false(.is_spectripy_use_conda()) + options(spectripy.use_conda = "FALSE") + expect_false(.is_spectripy_use_conda()) + options(spectripy.use_conda = "True") + expect_true(.is_spectripy_use_conda()) + Sys.setenv(SPECTRIPY_USE_CONDA="FALSE") + expect_true(.is_spectripy_use_conda()) + options(spectripy.use_conda = NULL) + expect_false(.is_spectripy_use_conda()) + Sys.setenv(SPECTRIPY_USE_CONDA="1") + expect_true(.is_spectripy_use_conda()) + + if (orig_env == "") + Sys.unsetenv("SPECTRIPY_USE_CONDA") + else Sys.setenv(SPECTRIPY_USE_CONDA=orig_env) + options(spectripy.use_conda = orig_opt) +}) + +test_that(".spectripy_env works", { + orig_opt <- getOption("spectripy.env") + orig_env <- Sys.getenv("SPECTRIPY_ENV") + + options(spectripy.env = NULL) + Sys.unsetenv("SPECTRIPY_ENV") + expect_equal(.spectripy_env(), "") + + options(spectripy.env = "myenvi") + expect_equal(.spectripy_env(), "myenvi") + Sys.setenv(SPECTRIPY_ENV="myotherenvi") + expect_equal(.spectripy_env(), "myenvi") + + options(spectripy.env = NULL) + expect_equal(.spectripy_env(), "myotherenvi") + + if (orig_env == "") + Sys.unsetenv("SPECTRIPY_ENV") + else Sys.setenv(SPECTRIPY_ENV=orig_env) + options(spectripy.env = orig_opt) +}) + +test_that(".check_environment works", { + sys_opt <- getOption("spectripy.use_system") + sys_env <- Sys.getenv("SPECTRIPY_USE_SYSTEM") + con_opt <- getOption("spectripy.use_conda") + con_env <- Sys.getenv("SPECTRIPY_USE_CONDA") + env_opt <- getOption("spectripy.env") + env_env <- Sys.getenv("SPECTRIPY_ENV") + ret_py <- Sys.getenv("RETICULATE_PYTHON") + ret_env <- Sys.getenv("RETICULATE_PYTHON_ENV") + ## cleaning options and environment + options(spectripy.use_system=NULL) + options(spectripy.use_conda=NULL) + options(spectripy.env=NULL) + Sys.unsetenv("SPECTRIPY_USE_SYSTEM") + Sys.unsetenv("SPECTRIPY_USE_CONDA") + Sys.unsetenv("SPECTRIPY_ENV") + Sys.unsetenv("RETICULATE_PYTHON") + Sys.unsetenv("RETICULATE_PYTHON_ENV") + + expect_silent(.check_environment()) + options(spectripy.use_system=TRUE) + expect_warning(.check_environment(), "variable 'SPECTRIPY_USE_SYSTEM'") + options(spectripy.use_system=NULL) + options(spectripy.use_conda=1) + expect_warning(.check_environment(), "variable 'SPECTRIPY_USE_CONDA'") + options(spectripy.use_conda=NULL) + options(spectripy.env="something") + expect_warning(.check_environment(), "variable 'SPECTRIPY_ENV'") + options(spectripy.env=NULL) + Sys.setenv(RETICULATE_PYTHON="something") + expect_message(.check_environment(), "Using Python defined by") + Sys.unsetenv("RETICULATE_PYTHON") + Sys.setenv(RETICULATE_PYTHON_ENV="something") + expect_message(.check_environment(), "Using Python environment defined by") + Sys.unsetenv("RETICULATE_PYTHON_ENV") + + ## Restoring options and environment + options(spectripy.use_system = sys_opt) + options(spectripy.use_conda = con_opt) + options(spectripy.env = env_opt) + if (sys_env == "") + Sys.unsetenv("SPECTRIPY_USE_SYSTEM") + else Sys.setenv(SPECTRIPY_USE_SYSTEM=sys_env) + if (con_env == "") + Sys.unsetenv("SPECTRIPY_USE_CONDA") + else Sys.setenv(SPECTRIPY_USE_CONDA=con_env) + if (env_env == "") + Sys.unsetenv("SPECTRIPY_ENV") + else Sys.setenv(SPECTRIPY_ENV=env_env) + if (ret_py == "") + Sys.unsetenv("RETICULATE_PYTHON") + else Sys.setenv(RETICULATE_PYTHON=ret_py) + if (ret_env == "") + Sys.unsetenv("RETICULATE_PYTHON_ENV") + else Sys.setenv(RETICULATE_PYTHON_ENV=ret_env) +}) diff --git a/vignettes/SpectriPy.qmd b/vignettes/SpectriPy.qmd index 5241ea6..ea0c5b2 100644 --- a/vignettes/SpectriPy.qmd +++ b/vignettes/SpectriPy.qmd @@ -11,11 +11,18 @@ vignette: > %\VignettePackage{SpectriPy} %\VignetteEncoding{UTF-8} %\VignetteEngine{quarto::html} - %\VignetteDepends{Spectra,BiocStyle,SpectriPy,reticulate,MsBackendMgf,msdata,mzR} + %\VignetteDepends{Spectra,BiocStyle,SpectriPy,reticulate,MsBackendMgf,MsDataHub,mzR} --- **Compiled**: `r date()` +**Note**: since version 0.99.6 *SpectriPy* uses the newer, recommended approach +to install and configure required Python libraries (i.e., through *reticulate*'s +`py_require()` functionality). This affects also the way a pre-defined Python +environment can be used. See section [Startup and Python configuration](https://rformassspectrometry.github.io/SpectriPy/articles/detailed-installation-configuration.html#sec-python) in the +*Detailed information on installation and configuration* vignette for updated +information. + # Introduction Powerful software libraries for mass spectrometry (MS) data are available in @@ -61,14 +68,17 @@ libraries, respectively. # Installation If the *BiocManager* package is not already available, please install it with -`install.packages("BiocManager")`. To install the development version of -*SpectriPy* from GitHub, please install in addition the *remotes* package with -`install.packages("remotes")`. As a system dependency, the package requires -Python (version >= 2.10) to be available. During package installation, -*SpectriPy* will install also all required Python libraries using a Python -*virtualenv* setup into a new Python environment *r-spectripy*. See also section -@sec-python for options to skip this and use either *miniconda* or system Python -environment instead. +`install.packages("BiocManager")`. As a system dependency, the package requires +Python (version >= 3.12) to be available. During package installation, +*SpectriPy* will by default install all required Python libraries +automatically. See section [Startup and Python +configuration](https://rformassspectrometry.github.io/SpectriPy/articles/detailed-installation-configuration.html#sec-python) +in the *Detailed information on installation and configuration* vignette for +information on manual library installation or usage of a pre-defined or system +Python environment. See section [Fixing package installation or loading +problems](https://rformassspectrometry.github.io/SpectriPy/articles/detailed-installation-configuration.html#sec-fix) +in the *Detailed information on installation and configuration* vignette for +some hints how to solve package installation or loading problems. To install the package use the code below: @@ -84,15 +94,13 @@ BiocManager::install("SpectriPy") ## Library loading and system setup Below we load all required packages. By loading *SpectriPy*, the package will -evaluate if the required Python libraries (i.e. *matchms* version 0.28.2 and -*spectrum_utils* version 0.3.2-0) are available. If they are not available, -*SpectriPy* will install them using functionality from the *reticulate* R -package (see also -[here](https://rstudio.github.io/reticulate/articles/versions.html) for -information on Python and library versions). Note that if required Python -libraries are being installed during package loading, it might be required to -restart the R session to ensure they are correctly loaded. See section -@sec-python for more configuration options of *SpectriPy*. +evaluate if the required Python libraries (i.e., *matchms* version >= 0.30, +*spectrum_utils* version >= 0.3.2 and *numpy* version >= 2.2) are available. If +they are not available, *SpectriPy* will install them using functionality from +the *reticulate* R package. See section [Startup and Python +configuration](https://rformassspectrometry.github.io/SpectriPy/articles/detailed-installation-configuration.html#sec-python) +in the *Detailed information on installation and configuration* vignette for +more configuration options of *SpectriPy*. The *reticulate* package will be loaded by *SpectriPy*, ensuring the R/Python integration provided by that package to be available as well. To better @@ -101,6 +109,7 @@ session:` or `#' Python session:` to label the R and Python code chunks, respectively. ```{r} +#| label: libraries #| message: false #' R session: @@ -112,25 +121,27 @@ library(SpectriPy) ## Converting MS data from R to Python In this section we show how MS data can be converted from R to Python. Below we -first define the name and path of a data file in mzML format (provided by the -`r BiocStyle::Biocpkg("msdata")` package) and load that data as an R `Spectra` -object. We thus first ensure that the package *msdata* is installed. If the line -below results in an error you need to first install *msdata* using -`BiocManager::install("msdata")`. +first define the name and path of a data file in mzML format (provided by the `r +BiocStyle::Biocpkg("MsDataHub")` package) and load that data as an R `Spectra` +object. We thus first ensure that the package *MsDataHub* is installed. If the +line below results in an error you need to first install *MsDataHub* using +`BiocManager::install("MsDataHub")`. ```{r} -stopifnot(require("msdata")) +stopifnot(require("MsDataHub")) ``` Next, we define the file path to the test file and load the data as a `Spectra` object in R. ```{r} +#| label: load-data #| message: false #' R session: #' Loading the data from a mzML file as a `Spectra` object -fl <- system.file("TripleTOF-SWATH", "PestMix1_DDA.mzML", package = "msdata") +library(MsDataHub) +fl <- MsDataHub::PestMix1_DDA.mzML() mzml_r <- Spectra(fl) ``` @@ -138,6 +149,7 @@ We next restrict the data to MS level 2 and remove spectra with less than 3 (fragment) peaks. ```{r} +#| label: filter MS level #' R session: #' Restrict to MS level 2 spectra @@ -150,6 +162,7 @@ This `Spectra` object can now be converted to equivalent data structures in Python using the `rspec_to_pyspec()` function: ```{r} +#| label: convert spectra to matchms #' R session: #' Convert the R Spectra to a list of Python matchms.Spectrum objects @@ -191,6 +204,7 @@ environment with the `py_set_attr()` function. We repeat our data conversion operation but assign the result to a Python attribute `"mzml_py"`: ```{r} +#| label: assign variable to Python #' R session: #' Assign the data to a variable in the Python environment @@ -201,6 +215,7 @@ names(py) We can now access this data directly from within Python: ```{python} +#| label: data types of variables #' Python session: #' Data type of the variable: @@ -222,6 +237,7 @@ values of each spectrum with the `normalize_intensities()` function such that their total sum is 1. ```{python} +#| label: normalize intensities with matchms #' Python session: import matchms.filtering as mms_filt @@ -243,6 +259,7 @@ since the variable returned by `py_get_attr()` is a Python object, we need to use index `0` to access the first element. ```{r} +#| label: inspect changed intensities in R #' R session: #' Access the intensities of the first spectrum @@ -306,6 +323,7 @@ MGF format using the Python *matchms* library. This MGF file is provided within the *SpectriPy* package so we first define its file name and path in R. ```{r} +#| label: define MGF file #' R session: f_mgf <- system.file("extdata", "mgf", "test.mgf", package = "SpectriPy") @@ -316,6 +334,7 @@ access the variable (defined in the R session) with the file name to import the data from through the `r.`. ```{python} +#| label: load MGF in Python #| warning: false #' Python session @@ -404,6 +423,7 @@ previously imported from the MGF file (i.e. `"mgf_py"`) and using the `MsBackendPy` as the data `source` (i.e., backend). ```{r} +#| label: initialize MsBackendPy for Python variable #' R session: #' Create a Spectra object with a MsBackendPy backend for the @@ -421,6 +441,7 @@ backend to iterate over the MS data in Python, extract the respective information, translate it and return it to the user. ```{r} +#| label: access MS level and intensity through MsBackendPy #' R session: #' Extract MS level @@ -442,6 +463,7 @@ the MS data attribute in Python are also immediately reflected in the respective peaks in Python: ```{python} +#| label: normalize intensities of MGF in Python #' Python session: #' Scale intensities @@ -453,6 +475,7 @@ for i in range(len(mgf_py)): The intensities retrieved from the `Spectra` object are now also scaled. ```{r} +#| label: get intensities after modifying in Python #' R session: #' Get intensities after scaling the intensities in Python: @@ -575,6 +598,7 @@ Such custom mapping can be passed with the parameter `mapping` to the convert the full data to R. ```{r} +#| label: convert R to Python with spectra variables #' R session: #' Convert the Python MS data structures to an R `Spectra` @@ -586,6 +610,7 @@ The respective metadata values have thus been added as new spectra variables to our `Spectra` object and can also be extracted: ```{r} +#| label: access spectra variables from Python in R #' R session: #' Show the first values for the spectra variable "name" @@ -624,6 +649,7 @@ add for example a mapping of the `matchms.Spectrum` metadata attribute `MsBackendPy`: ```{r} +#| label: add additional mapping #' R session: #' Add mapping for additional spectra variables to the `MsBackendPy` @@ -666,6 +692,7 @@ we re-use the `mgf` variable, which is also a `Spectra` with a `MsBackendPy` backend referencing the MS data imported and processed in Python. ```{r} +#| label: compareSpectra with mzML and MGF #' R session: #' Create a `Spectra` for the scaled MS data in Python @@ -681,6 +708,7 @@ functionality from the *matchms* library. Here we use the *original* attributes available in Python, i.e. `mzml_py` and `mgf_py`. ```{python} +#| label: Cosine Hungarian similarity in Python #' Python session: import matchms.similarity as mms_similarity @@ -702,6 +730,7 @@ We can also directly compare the scores calculated using the two different algorithms. ```{r} +#| label: compare dot product vs Cosine Hungarian #' R session: #' Plot the similarity scores against each other @@ -746,45 +775,6 @@ and copying of the MS data. See also section @sec-comments for general comments. Python affect also the `Spectra` object using that backend. -## Startup and Python configuration {#sec-python} - -During package startup, *SpectriPy* loads the required *reticulate* library and -configures the Python environment. If the package-specific environment does not -exist it creates one and installs all required libraries. By default, -*SpectriPy* will setup a specific *virtualenv* and install all required Python -libraries (i.e. *matchms* version 0.30.0 and *spectrum_utils* version 0.3.2) -into that. The Python setup can also be configured with three package options -that can also be set *via* environment variables. These are: - -- `"spectripy.use_system"` (environment variable `SPECTRIPY_USE_SYSTEM`): - whether the system Python should be used. Default is `"FALSE"`. If set to - `"TRUE"` *SpectriPy* will not check or install any packages but simply use the - user's system setup and will ignore the other options below. Users are thus - expected to manage the dependencies themselves. - -- `"spectripy.use_conda"` (environment variable `SPECTRIPY_USE_CONDA`): whether - conda should be used to install and manage the package-specific Python - environment. If `"FALSE"` (the default) *reticulate*'s `virtualenv_create()` - and `use_virtualenv()` functions are used. If set to `"TRUE"`, - `conda_create()` and `use_conda()` are used instead. - -- `"spectripy.env"` (environment variable `SPECTRIPY_ENV`): the name of the - environment that should be used by *SpectriPy*. Defaults to `"r-spectripy"`. - -Options can be set, prior loading of the package, either directly in the R -session using the `options()` function, or added to the *.Rprofile* file in the -user's home directory. To use *SpectriPy* with system Python, either call -`options(spectripy.use_system = TRUE)`, or add the line -`options(spectripy.use_system = TRUE)` to the *.Rprofile* file, or set and -export a system environment variable `SPECTRIPY_USE_SYSTEM=TRUE`. - -**Important** it is required to restart the R session if eventually missing -Python libraries were installed during package startup! - -See also the help of the *reticulate* package for more information on -configuring Python with R. - - # Session information ```{r} diff --git a/vignettes/detailed-installation-configuration.qmd b/vignettes/detailed-installation-configuration.qmd index b7bd814..ad780de 100644 --- a/vignettes/detailed-installation-configuration.qmd +++ b/vignettes/detailed-installation-configuration.qmd @@ -18,82 +18,73 @@ vignette: > This document provides detailed installation and configuration instructions for the [*SpectriPy*](https://github.com/RforMassSpectrometry/SpectriPy) -package. For first time R users see also section @sec-first in the appendix. +package. For first time R users see also section @sec-first in the appendix. For +advanced Python/system configuration and troubleshooting see sections +@sec-python and @sec-fix in the appendix. # Installation -## System requirements - *SpectriPy* relies on, and extends, the [*reticulate*](https://rstudio.github.io/reticulate/index.html) package for interoperability between Python and R. For installation of *SpectriPy*, Python needs to be installed on the system. See also the [Install Python Packages](https://rstudio.github.io/reticulate/articles/python_packages.html) documentation from the *reticulate* package for information on installing -Python. By default, *SpectriPy* uses *virtualenv* to configure and setup a Python -environment specific to the package. As an alternative, it is possible to use a -*miniconda*-based setup insterad. The code below shows how *miniconda* can be -installed with the *reticulate* package (which needs to be first installed with -`install.package("reticulate")` if not already available): +Python. Since version 0.99.5, *SpectriPy* uses the new +[`py_require()`](https://rstudio.github.io/reticulate/reference/py_require.html) +function from the *reticulate* package to install and manage all required Python +libraries (i.e., *matchms*, *spectrum_utils* and *numpy*) including all their +dependencies. + +Installation of the package using: ```{r} #| eval: false #' R session: - -install.packages("reticulate") -library(reticulate) -install_miniconda() +install.packages("BiocManager") +BiocManager::install("SpectriPy") ``` +should work on most systems. See also section [*Fixing package installation or +loading +problems*](https://rformassspectrometry.github.io/SpectriPy/articles/SpectriPy.html#sec-fix) +in the appendix of the *SpectriPy* vignette if installing or loading of the +package fails. -## Configure reticulate with host system Python environment (optional) - -The installation of *reticulate* can be configured to use an available Python -environment of the host system, instead of using the automatic setup. - -The path to the python3 executable file needs to be specified in the -`use_python()` function of *reticulate*. A conda environment used in the -analysis will also created below, ensuring a specific Python environment for -*reticulate*. Note that the path specified below in the `use_python()` call -might be different depending on the operating system or setup. Eventually refer -to the installation log/output from the previous code block if miniconda was -installed with the `install_miniconda()` function. - -```{r} -#| eval: false -#' R session: - -use_python("~/miniconda3_reticulate/bin/python3") -conda_create("r-reticulate") -reticulate::py_config() -``` -In case the host system Python environment is used, the required Python -packages can be installed using *reticulate* in its Python environment. To -install more Python packages, we use `conda_install()`. +## Configure reticulate with host system Python environment (optional) -Alternatively, if working outside of conda, packages can be installed using the -function `py_install()`. +*SpectriPy* (respectively *reticulate*) can be configured to use an available +Python environment of the host system, instead of using the automatic setup. In +this case, however, the user **must** first install the required Python +libraries manually in that local environment. The required libraries are: + +- [*matchms*](https://github.com/matchms) 0.30.0 +- [*spectrum_utils*](https://github.com/bittremieux-lab/spectrum_utils) 0.3.2 +- *numpy* 2.2.0 + +To use *SpectriPy* with a local, system, Python environment either the +`RETICULATE_PYTHON` or the `RETICULATE_PYTHON_ENV` environment variable needs to +be set. The former should point to the *python* binary, while the latter should +point to the (virtualenv or conda) environment with all necessary libraries +installed. These environment variables can either be set globally in the +operation system settings, or specifically for R. See also the +[Environment](https://docs.posit.co/ide/user/ide/guide/environments/r/managing-r.html) +documentation from Posit for more information on how to define environment +variables for R. In the example below, we set the variable using `Sys.setenv()` +**before** the *SpectriPy* or *reticulate* libraries are loaded: ```{r} #| eval: false #' R session: -conda_install(envname = "r-reticulate","matchms==0.28.2", pip = TRUE, - python_version = "3.12.2") -conda_install(envname = "r-reticulate","spectrum_utils", pip = TRUE) -conda_install(envname = "r-reticulate","numpy==2.0.2", pip = FALSE) +Sys.setenv(RETICULATE_PYTHON_ENV="") +library(SpectriPy) ``` -To use *SpectriPy* with the system Python, the R option `"spectripy.use_system"` -needs to be set to `TRUE` by calling `options(spectripy.use_system = TRUE)` -**before** loading *SpectriPy* with `library(SpectriPy)`. In addition, option -`"spectripy.env"` has to be set to use the miniconda environment defined above -with `options(spectripy.env = "r-reticulate")` (also before loading the -*SpectriPy* library). These options can also be configured with system -environment variables (see the *Startup and Python configuration* section in the -main *SpectriPy* vignette). +The `Sys.setenv()` call can also be added to a *.Rprofile* file to automatically +set the environmental variable when R starts. ## SpectriPy pre-requisites and installation instructions @@ -103,12 +94,12 @@ main *SpectriPy* vignette). Bioconductor is required to install *SpectriPy*, as described below and from source [https://bioconductor.org/install/](https://bioconductor.org/install/). -The current release of Bioconductor is version 3.20; it works with R version -4.4.0. Users of older R and Bioconductor must update their installation to take +The current release of Bioconductor is version 3.21; it works with R version +4.5.0. Users of older R and Bioconductor must update their installation to take advantage of new features and to access packages that have been added to Bioconductor since the last release. -The development version of Bioconductor is version 3.21; it works with R version +The development version of Bioconductor is version 3.22; it works with R version 4.5.0. More recent *devel* versions of R (if available) will be supported during the next Bioconductor release cycle. @@ -129,29 +120,18 @@ managing Bioconductor resources. if (!require("BiocManager", quietly = TRUE)) install.packages("BiocManager") -BiocManager::install(version = "3.20") +BiocManager::install(version = "3.21") ``` ### Installing *SpectriPy* -Since *SpectriPy* is currently still in development, you will need the *remotes* -package to install it from GitHub. If you do not have the *remotes* package yet, -you can install it using the following command: +*SpectriPy* can be installed through Bioconductor: ```{r} #| eval: false #' R session: -install.packages("remotes") -``` - -To install the *SpectriPy* package use - -```{r} -#| eval: false -#' R session: - -BiocManager::install("RforMassSpectrometry/SpectriPy") +BiocManager::install("SpectriPy") ``` ### Check installation completed @@ -159,12 +139,14 @@ BiocManager::install("RforMassSpectrometry/SpectriPy") The status of installation can be easily checked by starting R and entering the following commands. -This command loads the *SpectriPy* package, if correct installed. +This command loads the *SpectriPy* package, if correct +installed. `py_availble()` should return `TRUE`. ```{r} #' R session: library(SpectriPy) +py_available() ``` @@ -176,7 +158,7 @@ Instructions to install R and RStudio for the first time are described below, from source [https://rstudio-education.github.io/hopr/packages2.html](https://rstudio-education.github.io/hopr/packages2.html). -## Installing R and RStudio +### Installing R and RStudio To get started with R, you need to acquire your own copy. This appendix will show you how to download R as well as RStudio, a software application that makes @@ -317,6 +299,82 @@ Now that you have both R and RStudio on your computer, you can begin using R by opening the RStudio program. Open RStudio just as you would any program, by clicking on its icon or by typing *RStudio* at the Windows Run prompt. +## Startup and Python configuration {#sec-python} + +The way Python dependencies are defined and managed has changed in *SpectriPy* +beginning with version 0.99.6. *SpectriPy* now declares Python dependencies +using the `py_require()` function from the *reticulate* package. These Python +package dependencies requested via `py_require()` will automatically be +provisioned and made available for the user when the *SpectriPy* package is +loaded, *via* an ephemeral Python virtual environment. Eventually missing +libraries are downloaded and installed automatically. + +The previous *virtualenv* or *conda*-based setup is now replaced by the +preferred `py_require()` approach, hence the previous package's options and +environment variables `"spectripy.use_system"`, `SPECTRIPY_USE_SYSTEM`, +`"spectripy.use_conda"`, `SPECTRIPY_USE_CONDA`, `"spectripy.env"`, +`SPECTRIPY_ENV` are now ignored. + +A pre-defined Python environment can be used by pointing the `RETICULATE_PYTHON` +environment variable to the respective Python binary or the +`RETICULATE_PYTHON_ENV` to the path of the environment. All Python libraries +required by *SpectriPy* need however to be installed and available in that +Python environment, as *SpectriPy* respectively *reticulate*'s `py_require()` +functionality will be bypassed. These Python libraries are: + +- *matchms* >= 0.30.0 +- *spectrum_utils* >= 0.3.2 +- *numpy* >= 2.2.0 + +More information on this manual setup can be found in the *Detailed information +on installation and configuration* vignette. + +See also the help of the *reticulate* package for more information on +configuring Python with R. + + +## Fixing package installation or loading problems {#sec-fix} + +*SpectriPy* loads and imports the required Python libraries *matchms*, +*spectrum_utils* and *numpy* during package loading/attaching (e.g. using +`library(SpectriPy)`). Installation or loading of the package can thus fail if +these libraries or the required versions can not be found. *SpectriPy* uses the +newer `py_require()` approach from the *reticulate* package to manage Python +requirements. + +Trouble shooting: + +1) Check the output of `Sys.getenv()`: is there a system variable + `RETICULATE_PYTHON` or `RETICULATE_PYTHON_ENV` defined? Problem: *reticulate* + will use the specified Python or Python environment and skip automatic + installation of the Python libraries. Solution: a) unset this environment + variables b) manually install the required Python libraries in that Python + environment (see section @sec-python). + +2) Is there a *default* *r-reticulate* virtual environment (e.g. created by + another package or a previous version of *reticulate*) on the system, i.e., + does `virtualenv_exists("r-reticulate")` return `TRUE`? Problem: *reticulate* + will use this environment instead of the *ephemeral virtual environment* that + would be managed through `py_require()`. Solution: define an environment + variable `RETICULATE_USE_MANAGED_VENV="yes"`. This variable can either be + defined system wide, or by adding a line `RETICULATE_USE_MANAGED_VENV="yes"` + to a file named *.Renviron* in the user's home directory. See also the + [Environment](https://docs.posit.co/ide/user/ide/guide/environments/r/managing-r.html) + documentation from Posit for more information on how to define environment + variables for R. + +If this does not solve the issue, have also a look at the [order of +discovery](https://rstudio.github.io/reticulate/articles/versions.html#order-of-discovery) +documentation of *reticulate* which clearly explains how *reticulate* tries to +define and use the Python setup. Most *SpectriPy* installation/loading problems +come from the fact that another Python setup than the *ephemeral virtual +environment* (which is the current suggested mode) is used. The solution +suggested in point 2 above should solve most of these problems. + +More information can also be found in the *reticulate*'s [Python version +configuration](https://rstudio.github.io/reticulate/articles/versions.html) +documentation. + # Session information