Skip to main content

package-dependencies

Complete guide to managing R package dependencies, including Imports vs Suggests, namespace imports, and handling dependencies in code, tests, examples, and vignettes

Informations de source

Dépôt
choxos/RPkgAgent
Dernière activité de la source
15 février 2026 à 21:57
Langue détectée de SKILL.md
anglais
Étoiles
0
Forks
0

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
Package Dependencies
description
Complete guide to managing R package dependencies, including Imports vs Suggests, namespace imports, and handling dependencies in code, tests, examples, and vignettes
# Package Dependencies ## Overview Managing dependencies correctly is critical for R packages. This skill covers the different dependency types, how to declare and use them, and common patterns for conditional dependencies. ## CRITICAL Concept: Listing vs Importing **Most important rule**: Listing a package in `Imports:` does NOT make its functions available! ```r # DESCRIPTION: Imports: dplyr # This does NOT work: my_function <- function(data) { filter(data, value > 0) # ERROR: object 'filter' not found } # You must ALSO either: # Option 1: Use explicit namespace (RECOMMENDED for most cases): my_function <- function(data) { dplyr::filter(data, value > 0) } # Option 2: Import to namespace via roxygen2: #' @importFrom dplyr filter my_function <- function(data) { filter(data, value > 0) } ``` **Listing in DESCRIPTION ensures the package is installed.** **Importing to NAMESPACE makes functions available in your code.** ## Dependency Types ### Imports Packages required for your package to work. ```dcf # DESCRIPTION: Imports: dplyr (>= 1.0.0), rlang (>= 1.0.0), tidyr ``` **Guarantees:** - Installed when your package is installed - Loaded when your package is loaded (but not attached) - Functions available via `pkg::fun()` **Use for:** - Packages your code depends on - Packages used in most functions - Critical dependencies **Usage pattern:** ```r # Default: Use pkg::fun() my_function <- function(x) { dplyr::mutate(x, new_col = value * 2) } # Or import specific functions: #' @importFrom dplyr mutate select filter my_function <- function(x) { x %>% filter(value > 0) %>% mutate(doubled = value * 2) } ``` ### Suggests Optional packages for enhanced functionality, tests, or documentation. ```dcf # DESCRIPTION: Suggests: ggplot2, testthat (>= 3.0.0), knitr, rmarkdown, covr ``` **No guarantees:** - May or may not be installed - Must check availability before use - Cannot use `pkg::fun()` without checking **Use for:** - Packages for optional features - Testing frameworks (testthat, covr) - Vignette builders (knitr, rmarkdown) - Packages for examples only - Heavy dependencies users may not need **Usage pattern:** ```r # MUST check availability: my_plot <- function(data) { if (!requireNamespace("ggplot2", quietly = TRUE)) { stop("Package 'ggplot2' required but not installed.\n", "Install with: install.packages('ggplot2')", call. = FALSE) } ggplot2::ggplot(data, ggplot2::aes(x, y)) + ggplot2::geom_point() } # Better: Use rlang::check_installed() my_plot <- function(data) { rlang::check_installed("ggplot2", reason = "to create plots") ggplot2::ggplot(data, ggplot2::aes(x, y)) + ggplot2::geom_point() } ``` ### Depends Makes another package's functions available in user's workspace (rarely recommended). ```dcf # DESCRIPTION: Depends: R (>= 4.1.0), methods ``` **Effects:** - Package is attached when yours is attached - Functions available in user's search path - Modifies user's environment **Modern usage:** - `R (>= version)` - minimum R version (ALWAYS use this) - `methods` - if defining S4 classes - Almost never use for other packages **Why avoid:** ```r # If you use Depends: dplyr: library(mypackage) # Also attaches dplyr # Now user's environment has all dplyr functions: filter # Available (might conflict with stats::filter) ``` **Better approach:** ```r # Use Imports + explicit namespace: Imports: dplyr # In code: dplyr::filter(...) ``` ### LinkingTo For packages with C/C++ code using headers from other packages. ```dcf # DESCRIPTION: LinkingTo: Rcpp, RcppArmadillo ``` **Use for:** - Rcpp packages - Packages providing C++ headers - Compiled code dependencies **Often combined with Imports:** ```dcf Imports: Rcpp (>= 1.0.0) LinkingTo: Rcpp ``` ### Config/Needs/* Dependencies for development tools, not package functionality. ```dcf # DESCRIPTION: Config/Needs/website: pkgdown Config/Needs/coverage: covr Config/Needs/development: devtools, usethis, roxygen2 ``` **Use for:** - pkgdown for website - covr for coverage - Development tools - CI-specific packages **Not installed by default:** ```r # Install with: pak::pak("mypackage", dependencies = TRUE) # Includes Config/Needs/* ``` ## Adding Dependencies ### Using usethis Helpers ```r # Add to Imports: usethis::use_package("dplyr") usethis::use_package("rlang", min_version = "1.0.0") # Add to Suggests: usethis::use_package("ggplot2", type = "Suggests") # Add to Imports with @importFrom: usethis::use_import_from("dplyr", c("filter", "mutate", "select")) # Adds to DESCRIPTION AND creates roxygen2 skeleton # Add minimum R version: usethis::use_package("R", min_version = "4.1.0", type = "Depends") ``` ### Manual Addition ```dcf # DESCRIPTION: Imports: dplyr (>= 1.1.0), rlang (>= 1.0.0), tidyr, purrr Suggests: ggplot2 (>= 3.4.0), testthat (>= 3.0.0) ``` **Version specifications:** ```dcf dplyr # Any version dplyr (>= 1.0.0) # At least 1.0.0 dplyr (>= 1.0.0, < 2.0.0) # Rarely used, not recommended ``` ## Importing Functions to Namespace ### Pattern 1: Explicit Namespace (Recommended) ```r # No NAMESPACE imports needed # Just use pkg::fun() everywhere: my_function <- function(data) { data %>% dplyr::filter(value > 0) %>% dplyr::mutate(doubled = value * 2) %>% dplyr::select(id, doubled) } ``` **Advantages:** - Clear where functions come from - No NAMESPACE management needed - Easy to understand - No import conflicts **Disadvantages:** - More typing - Slightly verbose ### Pattern 2: Selective Import (@importFrom) ```r # Import specific functions: #' @importFrom dplyr filter mutate select #' @importFrom rlang .data .env my_function <- function(data) { data %>% filter(value > 0) %>% mutate(doubled = .data$value * 2) %>% select(id, doubled) } ``` **When to use:** - Functions used many times - Infix operators (%>%, %||%, :=) - Core package dependencies - Reduces verbosity **Where to put @importFrom:** ```r # Option 1: In function documentation: #' My function #' @importFrom dplyr filter mutate my_function <- function() { ... } # Option 2: In package-level doc (R/mypackage-package.R): #' @importFrom dplyr filter mutate select arrange #' @importFrom rlang .data .env %||% "_PACKAGE" # Option 3: Dedicated imports file (R/aaa-imports.R): #' @importFrom dplyr filter mutate select #' @importFrom rlang .data %||% NULL ``` ### Pattern 3: Full Import (@import) - Rare ```r #' @import rlang ``` **Only for:** - rlang (if building tidy evaluation package) - Your own internal package **Avoid for most packages:** - Namespace pollution - Potential conflicts - Unclear provenance ### Operators and Infix Functions **Always import operators:** ```r # WRONG - doesn't work: data %>% dplyr::filter(x > 0) # Error: %>% not found # RIGHT: #' @importFrom magrittr %>% data %>% dplyr::filter(x > 0) # Or use base pipe (R >= 4.1): data |> dplyr::filter(x > 0) # No import needed ``` **Common operators to import:** ```r #' @importFrom magrittr %>% #' @importFrom rlang %||% !! !!! #' @importFrom data.table := .N .SD ``` ## Using Dependencies in Different Contexts ### In Package Code (R/) ```r # Imports dependencies - use pkg::fun() or @importFrom: #' @importFrom dplyr filter my_function <- function(data) { filter(data, value > 0) # OK: imported } # Or: my_function <- function(data) { dplyr::filter(data, value > 0) # OK: explicit namespace } # Suggests dependencies - MUST check first: my_optional_feature <- function(data) { rlang::check_installed("ggplot2", reason = "for plotting") ggplot2::ggplot(data, ggplot2::aes(x, y)) + ggplot2::geom_point() } ``` ### In Examples (@examples) ```r # Imports - can use freely: #' @examples #' my_function(mtcars) # Suggests - must check or wrap: #' @examples #' \dontrun{ #' # Requires ggplot2 #' my_plot(mtcars) #' } #' #' @examplesIf requireNamespace("ggplot2", quietly = TRUE) #' my_plot(mtcars) ``` ### In Tests (tests/testthat/) ```r # Imports - can use freely: test_that("function works", { result <- my_function(data) expect_equal(result$value, expected) }) # Suggests - MUST skip if not available: test_that("plotting works", { skip_if_not_installed("ggplot2") plot <- my_plot(data) expect_s3_class(plot, "gg") }) test_that("integration with optional package", { skip_if_not_installed("dplyr") library(dplyr) result <- data %>% my_transform() %>% summarize(mean = mean(value)) expect_equal(result$mean, 5) }) ``` ### In Vignettes (vignettes/) ```r # YAML header for Suggests dependency: # --- # title: "My Vignette" # vignette: > # %\VignetteIndexEntry{My Vignette} # %\VignetteEngine{knitr::rmarkdown} # --- # First chunk - setup with conditional evaluation: # ```{r setup, include=FALSE} # knitr::opts_chunk$set( # eval = requireNamespace("ggplot2", quietly = TRUE) # ) # ``` # Now code chunks only run if ggplot2 available: # ```{r} # library(ggplot2) # ggplot(data, aes(x, y)) + geom_point() # ``` ``` **Alternative: Use separate vignettes:** ```dcf # DESCRIPTION: Suggests: knitr, rmarkdown, ggplot2 # vignettes/basic-usage.Rmd - no optional deps # vignettes/advanced-plotting.Rmd - requires ggplot2 ``` ### In Documentation (roxygen2) ```r # References to Suggests packages: #' @description #' This function provides plotting capabilities. Requires the #' \pkg{ggplot2} package to be installed. #' #' @seealso [ggplot2::ggplot()] for more plotting options ``` ## Minimum Version Specifications ### When to Specify Versions ```dcf # Always specify if you need specific features:
Voir sur GitHub
Ce SKILL.md est tres volumineux, SkillsMP affiche donc ici seulement la premiere section. Voir sur GitHub