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é ### 2021-05-20 --- 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)] --- 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></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() ``` ] --- # 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`) ] --- # 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, ...). Installation de manière intelligente. ] 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 - Changement de version de R renv ne gère pas la version de R (bien que ce soit dans renv.lock). -- Sur un projet à plusieurs certains étaient en R3, d'autres en R4. En cours de route on a essayé d'uniformiser .small[ 1. tout le monde installe la version 4 2. utilisation de renv ] -- La majorité des problèmes rencontrés venaient du fait du partage de libraries par défaut de R, une fois passé à la version 4. Les packages étaient potentiellement déjà installés, mais compilés avec une mauvaise version de R ► renv ne savait pas les installer, installation manuelle de tous les packages et dépendences. -- .center[![ok](images/cry.png)] --- # 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 - le fichier .Rprofile - le dossier renv/ avec dedans: - .gitignore - settings.dcf - activate.R A l'aide du .Rprofile, renv s'active tout seul chez les autres membres du projet. Ils peuvent alors utiliser `renv::restore()` pour récupérer les bonnes versions des packages. -- #### 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 - **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::status()` est très pratique, je vous conseille d'en abuser. -- - Si vous n'êtes pas passé à R>=4, y passer (proprement) avant de se mettre à utiliser renv. -- - 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. --- # 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/