Examining loaded packages in module namespaces/environments
- Dominant language
- R
- Stars
- 979
- Forks
- 49
- PR merge metrics
- No merged PRs in 30d
Description
In my spare time, I've been working on a rudimentary module manager ("boxingtape - grab") in the vein of yarn/npm (still extremely WIP, early stages, etc.). One thing I've been trying to implement is the drilling of modules in order to document requisite packages for installation. I have this working to an extent, the main issue being that I can't control namespace leakage, as "grab" has to be loaded in order to drill the modules in the first place.
I've tried a few hacky solutions, but I think the main issue is that I haven't been able to examine the packages in module environments. I've thought of just attaching all the modules to the global environment and then assessing them there, but the issue is then cleaning up the mess caused by that. E.g.:
```
eval({rlang::parse_expr(glue("box::use({moduleString})"))},
envir = .GlobalEnv
)
```
I suppose this is a rather long-winded way of asking about the ability to assess loaded packages in module namespaces and environments, ~~or ways in which I could assess loaded namespaces in a given module~~. As above, I can force a module to be loaded in a specific environment, but that doesn't seem to give me access to its ~~contents~~ loaded packages. Is there a way of getting access to what packages they implement? I looked at box::name() which seems to point me in the right direction with regard to namespaces, but I haven't had any luck yet.
Thanks!
...Sorry about the double colon usage
### Specifics
Edit: for some more background on the specifics re: package use, I'm listing all files in a local modules directory, and mapping them to box:
```
fullList <- list.files(
path = glue("{here()}/modules"),
recursive = TRUE,
ignore.case = TRUE,
pattern = {
".r$"
}
)
modFiles <- tools::file_path_sans_ext(
glue(
'../{fullList[ !grepl("grab", fullList) ] }'
)
)
walk(modFiles, ~ suppressMessages(screen_names(.x)))
screen_names <- function(x) {
splitName <- stri_reverse(stri_split_fixed(stri_reverse(x), "/", n = 2)[[1]])[2:1]
moduleString <- glue("{splitName[1]}/`{splitName[2]}`")
eval(
rlang::parse_expr(glue("box::use({moduleString})")),
# This isn't really necessary, but I've tried a few
# variations of setting an environment to call from
envir = rlang::current_env()
)
}
```
From here, I can use sessionInfo(), loadedNamespaces(), .packages(), etc., to see what packages are exposed. Doing so, however, means that the global environment is tainted by the function call (as the packages are still visible in loadedNamespaces wherever they are loaded from), and for the same reason gives an inacurate view of what packages a project might use. Ideally, I'd like to access the loaded namespaces of modules _only_, giving a more accurate view of package usage. This would also have the upside of allowing me to get the exact package dependencies of each module.
**Edit 2**: Sorry to bombard with edits, just trying to get my head around this! I've been able to access module environments through trial and error, but I haven't been able to assess attached packages, only modules. For instance, if I get the environment of module "grab", I can see the children of grab, but not any package that is loaded (if I assess the environment of a _local_ object that directly loads a package, I can see the package loaded via `get()`).
Contributor guide
Research direction
Start with box::name() and the module environments reached through box::use(), then compare their contents with loadedNamespaces() and .packages() as described in the issue. A solution is complete when it can identify packages used by individual modules without relying on or contaminating .GlobalEnv.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- r
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100