Would it make sense to have a use_all_packages function to automate a step further adding package dependencies to DESCRIPTION?
This is (sort of) a feature request, but mainly a question: do you guys think this is a good/bad idea?, or if it makes sense at all.
What I have in mind is something like this: to use {renv} to find all dependencies() in your package and automatically add them to DESCRIPTION (using usethis::use_package). So something like this would do:
use_all_packages <- function() {
undesc_deps <- renv::dependencies() %>%
dplyr::mutate(fromdesc = endsWith(Source, "/DESCRIPTION")) %>%
dplyr::group_by(Package) %>%
dplyr::summarize(indesc = any(fromdesc)) %>%
dplyr::filter(!indesc) %>%
dplyr::filter(Package != usethis::proj_get() %>% basename()) %>%
dplyr::filter(Package != "renv") %>%
dplyr::filter(Package != "purrr")
purrr::walk(undesc_deps$Package, usethis::use_package)
}
(of course it would need to be much better implemented to make it into usethis; this is just a quick-and-dirty snippet that gets the job done).
Would love to hear your thoughts about this.
I have a hard time seeing the use case for this. It feels relevant when someone has ... developed a whole package but never created DESCRIPTION or run R CMD check? Which can't or doesn't actually happen.
I think you see the tools you see in usethis, e.g. use_package(), because we advocate and use an incremental approach. Develop a bit, test, check, wrap up loose ends. Repeat. For me, in package development, I never need to discover and add a large set of packages to DESCRIPTION at once.
I could see this coming up in a non-package project, where one is using DESCRIPTION for convenience, i.e. for documenting the set of needed packages. And renv::dependencies() would be a great way to bootstrap that. But I don't think that justifies putting an official function in usethis. I think you'd do something ad hoc, like you show above, to get started and then carry on.
With the availability GitHub Actions and the awesome r-lib/actions collection, I am starting to use (abuse?) DESCRIPTION to compile dependencies, for RMarkdown projects that can run on a schedule.
I can use the "install-dependencies" part of one action meant for package-checking, then add parts of other actions to run the RMarkdown. FWIW, here's a link to the Action and its DESCRIPTION.
I've seen others discuss using DESCRIPTION for non-packages, just as @jennybc notes - I don't claim my approach to be either original or optimal.
I didn't know about renv::dependencies() - I would rely on the action failing 😳 to discover missing dependencies, so thanks!
I'm not advocating for any action (pardon the pun) one way or the other, but just to say I find this interesting.
Maybe renv should have a way to write its discovered dependencies as a DESCRIPTION file.
This is interesting timing because I was just thinking yesterday of making a PR to renv to do exactly that. However, I like the distinction renv has between implicit dependency caching (the default) and explicit dependency caching (using DESCRIPTION). I ended up deciding not to pursue it because I thought explicit dependency caching should be incremental and intentional the way that R package dev is. The big, obvious difference, though, is that a run of the mill renv project won't have something like R CMD CHECK to poke you about it.
Bouncing off of your ideas, @jennybc and @malcolmbarrett, maybe a (potentially renv) function could check your DESCRIPTION file and let you know what you are missing. It could be up to you to copy/paste a list of missing packages into your DESCRIPTION. Perhaps it would remain your (the user's) responsibility to manage remotes.
I like the implicit/explicit distinction on dependency management.
Is there an established set of practices for off-label use of DESCRIPTION for projects? I remember reading about it from time to time but, I can't place where - apologies if it has been Jenny and/or Malcolm 😬
Many thanks for your thoughtful reply. I was actually expecting something along those lines for an answer.
I have a hard time seeing the use case for this. It feels relevant when someone has ... developed a whole package but never created DESCRIPTION or run
R CMD check? Which can't or doesn't actually happen.
Well, the use case I had in mind was converting a non-package project into a package. For us, this happened in the context of a small data analysis project that grew up enough to justify a data-analysis-as-package approach. And perhaps that is not so uncommon (small projects turned big boys, that you could not anticipate they would grow so much). Although I guess, it still does not justify an official function in usethis.
I think you see the tools you see in usethis, e.g.
use_package(), because we advocate and use an incremental approach. Develop a bit, test, check, wrap up loose ends. Repeat. For me, in package development, I never need to discover and add a large set of packages to DESCRIPTION at once.
I am totally sold on the incremental approach you advocate. I just felt specifying dependencies in DESCRIPTION is something that can be automated a step further, which would be in line with usethis's approach ("automates repetitive tasks"). After all, every package used in a package should be in the DESCRIPTION.
I could see this coming up in a non-package project, where one is using DESCRIPTION for convenience, i.e. for documenting the set of needed packages. And
renv::dependencies()would be a great way to bootstrap that. But I don't think that justifies putting an official function in usethis. I think you'd do something _ad hoc_, like you show above, to get started and then carry on.
So yeah, renv::dependencies() is super helpful for all this!. Thanks for it and all the other great tools you put out there.
Bouncing off of your ideas, @jennybc and @malcolmbarrett, maybe a (potentially renv) function could check your DESCRIPTION file and let you know what you are missing.
That'd be cool. And perhaps it can also warn you about legacy packages declared as dependencies in DESCRIPTION but not actually used in code (that little package you only used in a function you factored out of your package, but forgot to remove the dependency from DESCRIPTION).
This seems like a reasonable idea to me, but it doesn't feel like a great fit for usethis currently. At this point in time, we believe that you should be managing your dependencies "by hand" — taking a dependency on a package is not something that we currently want to automate wholesale in this way. We may reconsider this position in the future, but for now, I think this code belongs somewhere other than usethis. Even though I'm closing this issue, I really appreciate the feedback, and hope you'll continue to contribute in the future 😄