r-lib / withr

Methods For Temporarily Modifying Global State
http://withr.r-lib.org
Other
169 stars 38 forks source link

local_package() used in a function detaches package from global environment #260

Open venpopov opened 3 weeks ago

venpopov commented 3 weeks ago

I expect withr functions to have no side-effects, but was just surprised by this behavior. If I use withr::local_package("somepackage") inside of a function, after I call this function the package is not attached in the global environment even if it was before:

packageVersion("withr")
#> [1] '3.0.0'

# load dplyr in the global environment
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

# this works
mutate(mtcars, mpg = 2*mpg) |> head(1)
#>           mpg cyl disp  hp drat   wt  qsec vs am gear carb
#> Mazda RX4  42   6  160 110  3.9 2.62 16.46  0  1    4    4

# use withr::local_package() to load dplyr in a function
f <- function() {
  withr::local_package("dplyr")
  print("dplyr is loaded in f() via withr::local_package()")
}

# run the function
f()
#> [1] "dplyr is loaded in f() via withr::local_package()"

# this does not work - dplyr was detached
mutate(mtcars, mpg = 2 * mpg) |> head(1)
#> Error in mutate(mtcars, mpg = 2 * mpg): could not find function "mutate"

Created on 2024-06-11 with reprex v2.1.0

In contrast, nearly the same code with withr::with_package does not have this problem:

packageVersion("withr")
#> [1] '3.0.0'

# load dplyr in the global environment
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

# this works
mutate(mtcars, mpg = 2*mpg) |> head(1)
#>           mpg cyl disp  hp drat   wt  qsec vs am gear carb
#> Mazda RX4  42   6  160 110  3.9 2.62 16.46  0  1    4    4

# use withr::local_package() to load dplyr in a function
f <- function() {
  withr::with_package("dplyr", {
    print("dplyr is loaded in f() via withr::with_package()")
  })
}

# run the function
f()
#> [1] "dplyr is loaded in f() via withr::local_package()"

# no problem:
mutate(mtcars, mpg = 2 * mpg) |> head(1)
#>           mpg cyl disp  hp drat   wt  qsec vs am gear carb
#> Mazda RX4  42   6  160 110  3.9 2.62 16.46  0  1    4    4

Created on 2024-06-11 with reprex v2.1.0

venpopov commented 3 weeks ago

Related: #202