I want to unload package and all its dependancies. But I do not want to unload packages that I have previously loaded with library()
or packages that are dependencies of packages that I loaded with library()
. How can I do it?

- 6,032
- 10
- 50
- 80
-
Maybe like this? https://stackoverflow.com/questions/6979917/how-to-unload-a-package-without-restarting-r – M.Viking Sep 21 '19 at 23:58
-
@M.Viking I have already looked at it but did not found "But I do not want to unload packages that I have previously loaded with `library()` or packages that are dependencies of packages that I loaded with `library()`." – vasili111 Sep 22 '19 at 00:05
1 Answers
EDIT: I've updated my answer to the question linked above,
showing a possible alternative to track explicit usages of library
.
It would be possible to use it to compute attached
in the code below instead of using search
.
Here's one possibility I found using the remotes
package:
transitive_deps <- function(package, acc = character()) {
direct_deps <- remotes::local_package_deps(system.file(package = package))
filtered_deps <- setdiff(direct_deps, acc)
if (length(filtered_deps) == 0L) {
package
}
else {
acc <- union(acc, filtered_deps)
for (dep in filtered_deps) { acc <- union(acc, transitive_deps(dep, acc)) }
union(package, acc)
}
}
unload_deep <- function(package) {
# find all transitive dependencies of the package
deps <- transitive_deps(package) # alternatively: remotes::package_deps(package)$package
# do not unload base packages
deps <- setdiff(deps, installed.packages(priority = "base")[, "Package"])
# do not unload packages explicitly attached with library()
attached <- search()
deps <- setdiff(deps, substring(attached, unlist(gregexpr(":", attached)) + 1L)) # remove "package:" prefix
# first unload provided package
tryCatch(unloadNamespace(package), error = function(...) {
package <- paste0("package:", package)
if (package %in% search()) {
# at least try to detach it if some other package imports it
detach(package, character.only = TRUE)
}
})
deps <- setdiff(deps, package)
# try to unload remaining
while (length(deps) > 0L) {
unloaded_one <- FALSE
for (dep in deps) {
flag <- try(unloadNamespace(dep), silent = TRUE)
if (!inherits(flag, "try-error")) {
unloaded_one <- TRUE
break
}
}
if (unloaded_one) {
deps <- setdiff(deps, dep)
}
else {
# could not unload any, must be used by other unrelated packages
break
}
}
# return
invisible()
}
You need to pass a character in package
.
Also, as mentioned in the code comments,
you can use remotes::package_deps(package)$package
instead of the transitive_deps
helper.
I think the former already filters base
packages,
but I believe it checks online each time you use it.
The transitive_deps
helper is far from perfect,
it just tries to find direct dependencies
(which is what remotes::local_package_deps
returns)
recursively,
hopefully avoiding some repetition by using acc
to accumulate already seen packages.
The order in which packages are unloaded is important,
because you cannot unload a package that is imported by another currently loaded package.
Unfortunately the order in deps
is not always perfect for that,
that's why there's a try
in the loop,
to skip problematic packages until all dependent packages have been unloaded.

- 4,950
- 1
- 18
- 37