class: center, middle, inverse, title-slide # Package renv : présentation et retour d’expérience ## Figer ses versions de packages R
(et leurs dépendances et dépendances de dépendances)
### Elise Maigné ### 2023-12-21 --- class: center, middle # renv c'est quoi ? <img src="https://rstudio.github.io/renv/reference/figures/logo.svg", width="300" height="300"> --- ### Package renv - Un package R créé par Kevin Ushey > "new effort to bring project-local R dependency management to your projects". -- - renv ~ packrat 2.0 (aussi par Kevin Ushey) > "The goal is for renv to be a robust, stable replacement for the Packrat package, with fewer surprises and better default behaviors." -- - Figer et/ou partager les versions des packages de R utilisés **pour un projet**. -- .center[![ok](images/index.png)] .center[![reprod](images/reproductibilite_transparent.png)] --- # Principes .center[![schéma](images/schema0.png)] --- class: center, middle # Comment ça marche ? <img src="https://rstudio.github.io/renv/reference/figures/logo.svg", width="300" height="300"> --- # Initialisation Dans un dossier spécifique (la racine d'un projet) : ```r install.packages("renv") renv::init() ``` **OU** en mode projet Rstudio (.Rproj), sur un nouveau projet File > New project > New directory > "Activate renv with this project". (aussi dans les options du projet, onglet **Environments**) Et voilà ! --- # Fonctionnement `renv::init()` crée : .pull-left[ - ###un fichier **.Rprofile** - un fichier **renv.lock** - un dossier **renv** contenant : - un fichier **.gitignore** - un fichier **activate.R** - un fichier **settings.dcf** - un dossier **stagging** - un dossier **library** ] .pull-right[ active renv au démarrage du projet/lancement de R depuis ce dossier ] --- # Fonctionnement <style type="text/css"> .tiny .remark-code { /*Change made here*/ font-size: 70% !important; } </style> `renv::init()` crée : .pull-left[ - un fichier **.Rprofile** - ###un fichier **renv.lock** - un dossier **renv** contenant : - un fichier **.gitignore** - un fichier **activate.R** - un fichier **settings.dcf** - un dossier **stagging** - un dossier **library** ] .pull-right[ </br></br> stocke la version de R utilisée et les versions des dépendances **dont on a besoin dans le code** ] --- # Fonctionnement - exemple renv.lock .tiny[ ```r { "R": { "Version": "4.0.3", "Repositories": [ { "Name": "CRAN", "URL": "https://cran.rstudio.com" } ] }, "Packages": { "BH": { "Package": "BH", "Version": "1.75.0-0", "Source": "Repository", "Repository": "CRAN", "Hash": "e4c04affc2cac20c8fec18385cd14691" }, "R6": { "Package": "R6", "Version": "2.5.0", "Source": "Repository", "Repository": "CRAN", "Hash": "b203113193e70978a696b2809525649d" }, ... ``` ] --- # Fonctionnement `renv::init()` crée : .pull-left[ - un fichier **.Rprofile** - un fichier **renv.lock** - un dossier **renv** contenant : - ###un fichier **.gitignore** - un fichier **activate.R** - un fichier **settings.dcf** - un dossier **stagging** - un dossier **library** ] .pull-right[ </br></br></br></br> Si on travaille aussi avec git, les gros fichiers ne seront pas commités (les packages) ] --- # Fonctionnement `renv::init()` crée : .pull-left[ - un fichier **.Rprofile** - un fichier **renv.lock** - un dossier **renv** contenant : - un fichier **.gitignore** - ###un fichier **activate.R** - ###un fichier **settings.dcf** - un dossier **stagging** - un dossier **library** ] .pull-right[ </br></br></br></br></br> Script d'initialisation du renv </br> Les paramètres du renv pour le projet ] --- # Fonctionnement `renv::init()` crée : .pull-left[ - un fichier **.Rprofile** - un fichier **renv.lock** - un dossier **renv** contenant : - un fichier **.gitignore** - un fichier **activate.R** - un fichier **settings.dcf** - ###un dossier **stagging** - ###un dossier **library** ] .pull-right[ </br></br></br></br></br></br></br> Pour l'installation des "staged packages" </br> </br> Pour l'installation des autres packages ] --- # Fonctionnement Ce qui nous concerne c'est la gestion des libraries. Quand on est dans un projet géré avec renv, on peut voir que le `.libPaths()` change : **Sans renv :** ```r > .libPaths() [1] "/home/emaigne/R/x86_64-pc-linux-gnu-library/4.0" [2] "/opt/R/4.0.3/lib/R/library" ``` **Avec renv :** ```r > .libPaths() [1] "/home/emaigne/Documents/mon_dossier/renv/library/R-4.0/x86_64-pc-linux-gnu" [2] "/tmp/RtmpHmJq4n/renv-system-library" ``` --- # Fonctionnement Les packages sont installés dans un sous dossier de mon dossier de projet. -- **Et bien non !!** ![emplacements](images/emplacement_packages.png) -- Ce sont des liens symboliques vers un dossier de cache qui contient les différentes versions des packages. ![emplacement_brio](images/brio.png) --- # Fonctionnement .pull-left[ ### Sans renv : <figure> <img src="images/shared-library.svg", width="300" height="150"> <p style='font-size: 10px;'>© Kevin Ushley, <a>https://kevinushey-2020-rstudio-conf.netlify.app/slides.html</a></p> Une seule version par package. ] -- .pull-right[ ### Avec renv : <img src="images/package-cache.svg", width="300" height="150"> <p style='font-size: 10px;'>© Kevin Ushley, <a>https://kevinushey-2020-rstudio-conf.netlify.app/slides.html</a></p> Le cache permet d'avoir plusieurs versions du même package. Le cache peut être désactivé pour un projet ► Les packages iront dans le `library` spécifique. ] --- # Schéma récapitulatif .center[![schéma](images/schema1.png)] --- class: center, middle # Comment l'utiliser ? <img src="https://rstudio.github.io/renv/reference/figures/logo.svg", width="300" height="300"> --- # Commandes à connaitre .pull-left[ - ####**`renv::init()`** - `renv::status()` - `renv::dependencies()` - `renv::snapshot()` - `renv::restore()` - `renv::install()` ] .pull-right[ Pour initialiser l'utilisation de renv dans le projet. ] --- # Commandes à connaitre .pull-left[ - `renv::init()` - ####**`renv::status()`** - `renv::dependencies()` - `renv::snapshot()` - `renv::restore()` - `renv::install()` ] .pull-right[ Pour savoir où on en est par rapport au fichier renv.lock. Est-ce qu'il y a des packages non présents dans renv.lock ? Des packages dans renv.lock non utilisés dans le code R ? ] -- Exemple : ```r renv::status() The following package(s) are installed but not recorded in the lockfile: Rcpp [1.0.6] whisker [0.4] knitr [1.31] Use `renv::snapshot()` to add these packages to your lockfile. ``` --- # Commandes à connaitre .pull-left[ - `renv::init()` - `renv::status()` - ####**`renv::dependencies()`** - `renv::snapshot()` - `renv::restore()` - `renv::install()` ] .pull-right[ </br> Quels sont les packages utilisés dans le code ? Uniquement packages appelés dans les scripts R (.R ou .Rmd ou .Rnw ou DESCRIPTION) d'une des façons suivantes : ```r library(package) require(package) requireNamespace("package") package::method() ``` ] -- .font80pct[ ```r > renv::dependencies() Finding R package dependencies ... Done! Source 1 /home/emaigne/Documents/slides/renv/presentation.Rmd rmarkdown 2 /home/emaigne/Documents/slides/renv/presentation.Rmd xaringan 3 /home/emaigne/Documents/slides/renv/presentation.Rmd xaringanthemer 4 /home/emaigne/Documents/slides/package_renv/renv.lock renv ``` ] --- # Commandes à connaitre .pull-left[ - `renv::init()` - `renv::status()` - `renv::dependencies()` - ####**`renv::snapshot()`** - `renv::restore()` - `renv::install()` ] .pull-right[ </br></br> Pour sauver l'état des packages utilisés dans le fichier renv.lock ] -- Exemple : ```r > renv::snapshot() The following package(s) will be updated in the lockfile: # CRAN =============================== - BH [* -> 1.75.0-0] - R6 [* -> 2.5.0] - Rcpp [* -> 1.0.6] - base64enc [* -> 0.1-3] Do you want to proceed? [y/N]: ``` --- # Commandes à connaitre .pull-left[ - `renv::init()` - `renv::status()` - `renv::dependencies()` - `renv::snapshot()` - ####**`renv::restore()`** - `renv::install()` ] .pull-right[ </br></br></br></br> Pour revenir à l'état du renv.lock. i.e. désinstalle les packages en trop, réinstalle les packages manquants. (ça ne désinstalle pas vraiment, ça supprime l'entrée dans `library`) ] -- Exemple : ```r > renv::restore() The following package(s) will be updated: # CRAN =============================== - stringi [* -> 1.5.3] Do you want to proceed? [y/N]: y Installing stringi [1.5.3] ... OK [linked cache in 0.2 milliseconds] ``` --- # Commandes à connaitre .pull-left[ - `renv::init()` - `renv::status()` - `renv::dependencies()` - `renv::snapshot()` - `renv::restore()` - ####**`renv::install()`** ] .pull-right[ </br></br></br></br></br> Pour installer un package en utilisant renv (CRAN, version spécifique, github, commit spécifique, Bioconductor, ...). S'il peut utiliser le cache il le fait ! ] Exemple : ```r renv::install("digest") # latest renv::install("digest@0.6.18") # specific version renv::install("eddelbuettel/digest") # github latest dev version renv::install("bioc::Biobase") # (note: requires the BiocManager package) ``` --- # Commandes à connaitre .pull-left[ - `renv::init()` - `renv::status()` - `renv::dependencies()` - `renv::snapshot()` - `renv::restore()` - `renv::install()` ] .pull-right[ ] <hr> Pour une utilisation plus fine du package, voir : https://kevinushey-2020-rstudio-conf.netlify.app/slides.html --- class: center, middle # Retour d'expérience <img src="https://rstudio.github.io/renv/reference/figures/logo.svg", width="300" height="300"> --- # Retour d'expérience - La version de R Le fichier `renv.lock` contient la version de R : ```r { "R": { "Version": "4.0.3", "Repositories": [ { ... ``` -- La version de R n'est pas "imposée par renv", si la mauvaise est chargée il met juste un warning au démarrage. -- Si plusieurs version de R doivent être installées, regarder par ex. du côté de [`rig`](https://github.com/r-lib/rig) ```bash rig rstudio 4.0.3 monprojet.Rproj ``` --- # Retour d'expérience - Utilisation avec git **renv prend tout son sens !!** On peut partager les memes versions de packages avec ses collaborateurs. -- #### Pour partager en cours de développement (**comportement par défaut**) : - le fichier `renv.lock` (versions des packages) - le fichier `.Rprofile` (pour que renv s'active tout seul) - le dossier `renv/` avec dedans (les paramètres) : - `.gitignore` - `settings.dcf` - `activate.R` On peut alors utiliser `renv::restore()` pour récupérer les bonnes versions des packages (sur la bonne version de R). -- #### Partage à minima : - le fichier renv.lock Une autre personne peut, chez elle faire un `renv::init()` pour installer les packages correspondants. --- # Retour d'expérience - Divers - **renv** c'est bien, notamment pour partager/archiver ses codes. -- - initialement je pensais que c'était lourd (je pensais le réserver pour des projets type container) et puis j'ai découvert l'existence du cache. -- - au démarrage, R nous dit si renv est utilisé (ou pas) : ```r Tapez 'demo()' pour des démonstrations, 'help()' pour l'aide en ligne ou 'help.start()' pour obtenir l'aide au format HTML. Tapez 'q()' pour quitter R. * Project '~/Documents/mon_dossier' loaded. [renv 0.12.3] ``` -- - renv marche même sans RStudio, et sans "projet" RStudio. C'est le .Rprofile et les fichiers de renv qui vont activer renv au niveau du dossier. --- # Retour d'expérience - Les fonctions SUPER utiles - `renv::status()` est très pratique, je vous conseille d'en abuser. Permet de comparer le fichier renv.lock et le dossier library. -- - `renv::install()` permet d'installer des packages de partout. CRAN, Bioconductor, git, .... Aller voir l'aide : ?renv::install ```r # install the latest version of 'digest' renv::install("digest") # install an old version of 'digest' (using archives) renv::install("digest@0.6.18") # install 'digest' from GitHub (latest dev. version) renv::install("eddelbuettel/digest") # install a package from GitHub, using specific commit renv::install("eddelbuettel/digest@df55b00bff33e945246eff2586717452e635032f") # install a package from Bioconductor # (note: requires the BiocManager package) renv::install("bioc::Biobase") ``` --- # Retour d'expérience - Les fonctions SUPER utiles - `renv::dependencies()` permet de pointer quel package est utilisé où. Très utile pour du nettoyage, test de nouveau package, ... Conseil : coder `package::fonction()` partout facilite pas mal le travail ! ```r > mydeps <- renv::dependencies() Finding R package dependencies ... Done! > head(mydeps) Source Package Require Version Dev 1 /home/emaigne/Documents/2020/2020_HiCDOC/HiCDOC/DESCRIPTION methods FALSE 2 /home/emaigne/Documents/2020/2020_HiCDOC/HiCDOC/DESCRIPTION zlibbioc FALSE 3 /home/emaigne/Documents/2020/2020_HiCDOC/HiCDOC/DESCRIPTION ggplot2 FALSE 4 /home/emaigne/Documents/2020/2020_HiCDOC/HiCDOC/DESCRIPTION Rcpp >= 0.12.8 FALSE 5 /home/emaigne/Documents/2020/2020_HiCDOC/HiCDOC/DESCRIPTION stats FALSE 6 /home/emaigne/Documents/2020/2020_HiCDOC/HiCDOC/DESCRIPTION S4Vectors FALSE ``` --- # Schéma récapitulatif .center[![schéma](images/schema2.png)] --- class: center, middle # des questions ? --- # Comparaison avec un environnement python Tableau emprunté ici : https://6chaoran.wordpress.com/2020/07/20/introduction-of-renv-package/ | task | R with renv | Python with conda | Python with pip | |:---- |:----------- |:----------------- |:--------------- | | create the environment | renv::init() | conda create | virtualenv | | save the environment | renv::snapshot() | conda env export > environment.yml | pip freeze > requirements.txt | | load the environment | renv::restore() | conda env create -f environment.yml | pip install -r requirements.txt | # Utilisation avec conda Voir ici : http://russ-hyde.rbind.io/post/2021-02-23-renv-in-conda/ On peut installer r-base et r-renv avec conda puis c'est renv qui s'occupe de gérer l'environnement R, et non plus conda, ce qui évite des problèmes de non disponibilité des packages R dans conda. --- # Références - Renv documentation : https://rstudio.github.io/renv/articles/renv.html - Renv github : https://github.com/rstudio/renv/ - Présentation de Kevin Ushey : https://kevinushey-2020-rstudio-conf.netlify.app/slides.html - http://russ-hyde.rbind.io/post/2021-02-23-renv-in-conda/ - https://6chaoran.wordpress.com/2020/07/20/introduction-of-renv-package/