Giter VIP home page Giter VIP logo

attachment's Introduction

R-CMD-check Coverage status CRAN status downloads

attachment

The goal of attachment is to help to deal with package dependencies during package development. It also gives useful tools to install or list missing packages used inside Rscripts or Rmds.

When building a package, we have to add @importFrom in our documentation or pkg::fun in the R code. The most important is not to forget to add the list of dependencies in the “Imports” or “Suggests” package lists in the DESCRIPTION file.

Why do you have to repeat twice the same thing ?
And what happens when you remove a dependency for one of your functions ? Do you really want to run a “Find in files” to verify that you do not need this package anymore ?

Let {attachment} help you ! This reads your NAMESPACE, your functions in R directory and your vignettes, then update the DESCRIPTION file accordingly. Are you ready to be lazy ?

See full documentation realized using {pkgdown} at https://thinkr-open.github.io/attachment/

Installation

CRAN version

install.packages("attachment")

Development version

install.packages('attachment', repos = c('https://thinkr-open.r-universe.dev', 'https://cloud.r-project.org'))

Declare all dependencies in DESCRIPTION during package development

What you really want is to fill and update your description file along with the modifications of your documentation. Indeed, only the following function will really be called. Use and abuse during the development of your package !

attachment::att_amend_desc()

{attachment} detects all calls to library(pkg), @importFrom pkg fun, pkg::fun() in the different classical directories of your R package, then list them in the correct “Imports” or “Suggests” category in the DESCRIPTION file, according to their position in the package.

Declare extra dependencies for extra uses

If you want to add extra packages like {pkgdown} or {covr} that are not listed in any script in your package, a call for your development packages would be:

attachment::att_amend_desc(extra.suggests = c("pkgdown", "covr"), update.config = TRUE)

Note the update.config = TRUE parameter that will save the parameters used in the call of att_amend_desc() to the package configuration file: “dev/config_attachment.yaml”.

If you run att_amend_desc() a second time afterwards, directly from the console, it will use the last set of parameters extracted from the configuration file.

Indeed, we recommend to store the complete command line in a “dev/dev_history.R” file to update and run it when needed. If the parameters do not change, you can run attachment::att_amend_desc() directly in the console, wherever you are, it will use the configuration file.

Automatically fill the “Remotes” field

If you would like to detect the sources of your installations so that you can add dependencies in the “Remotes” field of your DESCRIPTION file, to mimic your local installation, you will use:

attachment::set_remotes_to_desc()

Example on a fake package

# Copy example package in a temporary directory
tmpdir <- tempfile(pattern = "fakepkg")
dir.create(tmpdir)
file.copy(system.file("dummypackage",package = "attachment"), tmpdir, recursive = TRUE)
#> [1] TRUE
dummypackage <- file.path(tmpdir, "dummypackage")
# browseURL(dummypackage)

# Fill the DESCRIPTION file automatically
# `inside_rmd` is specifically designed here to allow to run this command line in the "Readme.Rmd" file
desc_file <- attachment::att_amend_desc(path = dummypackage, inside_rmd = TRUE, update.config = TRUE)
#> 'update.config' was set to TRUE, hence, 'use.config' was forced to FALSE
#> Saving attachment parameters to yaml config file
#> Updating dummypackage documentation
#> ────────────────────────────────────────────────────────────────────────────────
#> Changes in roxygen2 7.0.0:
#> * `%` is now escaped automatically in Markdown mode.
#> Please carefully check .Rd files for changes
#> ────────────────────────────────────────────────────────────────────────────────
#> 
#> Setting `RoxygenNote` to "7.2.2"
#> ℹ Loading dummypackage
#> Writing '�]8;;file:///tmp/Rtmp3Dpn4h/fakepkg3538450e5c49/dummypackage/NAMESPACE�NAMESPACE�]8;;�'
#> Writing '�]8;;file:///tmp/Rtmp3Dpn4h/fakepkg3538450e5c49/dummypackage/NAMESPACE�NAMESPACE�]8;;�'
#> ℹ Loading dummypackage
#> Package(s) Rcpp is(are) in category 'LinkingTo'. Check your Description file to be sure it is really what you want.
#> 
#> [-] 1 package(s) removed: utils.
#> 
#> [+] 2 package(s) added: stats, glue.

# Add Remotes if you have some installed
attachment::set_remotes_to_desc(path.d = desc_file)
#> There are no remote packages installed on your computer to add to description
#> NULL

# Clean state
unlink(tmpdir, recursive = TRUE)

More on finding Remotes repositories (non installed from CRAN)

Find packages installed out of CRAN. This helps fill the “Remotes” field in DESCRIPTION file with set_remotes_to_desc().
Behind the scene, it uses find_remotes().

  • See the examples below if {fusen} is installed from GitHub
    • Also works for GitLab, Bioconductor, Git, Local installations
# From GitHub
remotes::install_github("ThinkR-open/fusen",
                        quiet = TRUE, upgrade = "never")
attachment::find_remotes("fusen")
#> $fusen
#> [1] "ThinkR-open/fusen"

Find and install missing dependencies required for your R scripts

To quickly install missing packages from a DESCRIPTION file, use:

attachment::install_from_description()
#> All required packages are installed

To quickly install missing packages needed to compile Rmd files or run R scripts, use:

attachment::att_from_rmds(path = ".") |> attachment::install_if_missing()

attachment::att_from_rscripts(path = ".") |> attachment::install_if_missing()

Function attachment::create_dependencies_file() will create a dependencies.R file in inst/ directory. This R script contains the procedure to quickly install missing dependencies:

# Remotes ----
# remotes::install_github("ThinkR-open/fcuk")
# Attachments ----
to_install <- c("covr", "desc", "devtools", "glue", "knitr", "magrittr", "rmarkdown", "stats", "stringr", "testthat", "utils")
for (i in to_install) {
  message(paste("looking for ", i))
  if (!requireNamespace(i)) {
    message(paste("     installing", i))
    install.packages(i)
  }
}

Allow the CI to install all dependencies required for your bookdown, pagedown, quarto, …

If you write a {bookdown} and want to publish it on Github using GitHub Actions or GitLab CI for instance, you will need a DESCRIPTION file with list of dependencies just like for a package. In this case, you can use the function to description from import/suggest: att_to_desc_from_is().

usethis::use_description()
# bookdown Imports are in Rmds
imports <- c("bookdown", attachment::att_from_rmds("."))
attachment::att_to_desc_from_is(path.d = "DESCRIPTION",
                                imports = imports, suggests = NULL)

Then, install dependencies with

remotes::install_deps()

List packages required in any script or notebook

Of course, you can also use {attachment} out of a package to list all package dependencies of R scripts using att_from_rscripts() or Rmd/qmd files using att_from_rmds().
If you are running this inside a Rmd, you may need parameter inside_rmd = TRUE.

library(attachment)
dummypackage <- system.file("dummypackage", package = "attachment")

att_from_rscripts(path = dummypackage)
#> [1] "stats"        "testthat"     "dummypackage"
att_from_rmds(path = file.path(dummypackage, "vignettes"), inside_rmd = TRUE)
#> [1] "knitr"     "rmarkdown" "glue"

Vignettes included

Package {attachment} has vignettes to present the different functions available. There is also a recommendation to have a dev_history.R in the root directory of your package. (Have a look at dev_history.R in the present package)

vignette("a-fill-pkg-description", package = "attachment")
vignette("b-bookdown-and-scripts", package = "attachment")
vignette("use_renv", package = "attachment")
vignette("create-dependencies-file", package = "attachment")

The vignettes are available on the {pkgdown} page, in the “Articles” menu: https://thinkr-open.github.io/attachment/

Code of Conduct

Please note that the attachment project is released with a Contributor Code of Conduct. By contributing to this project, you agree to abide by its terms

attachment's People

Contributors

cderv avatar colinfay avatar dagousket avatar dianebeldame avatar espinielli avatar maelle avatar murielledelmotte avatar statnmap avatar vincentguyader avatar yogat3ch avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

attachment's Issues

As a Dev, I want to have all the instructions to check before submission to CRAN

As a Dev, I want to have all the instructions to check before submission to CRAN

Criteria of success

  • all the instructions to check before submission to CRAN are listed in the file dev_history

## Prepare for CRAN ----

  • The devtools::test() is successful

image

  • The testthat::test_dir("tests/testthat/") is successful

image

Technical

Prepare for CRAN ----

pkgload::load_all()
devtools::test()
testthat::test_dir("tests/testthat/")

As dev, I'd like a function to read `att_amend_desc()` parameters from a yaml file

As dev, I'd like a function to read att_amend_desc() parameters from a yaml file so that I can re-use them later on

Validation

  • a new fonction exist to load att_amend_desc() parameters from a yaml file

image

=> https://github.com/ThinkR-open/attachment/blob/main/R/load_att_params.R

  • when I call this function with a yaml file as input, it returns the named list of parameters

image

  • if a yaml does not exist, it throws an error

image

  • if yaml entries do not correspond to att_amend_desc() parameters, it throws an error

image

  • when I call this function with a yaml file, it sends a message to the user to warn him which parameters have been loaded

image

=> https://github.com/ThinkR-open/attachment/blob/main/tests/testthat/test-load_att_params.R

Tech-Dev

  • make a new function in flat for yaml param handling that takes a yaml and return a named list of parameters
  • make unit test to read yaml
  • avoid the use of additional dependencies, except for {yaml}
  • make the function send the parameter loaded as message

Take README.rmd into account for suggested packages

Sometimes README contains examples to explain how the package is used and external packages might be needed in order to get or transform data.

Those packages should be listed as suggested packages. What do you think?

As dev, I want create_dependencies_file() to use sub-functions to create the output to be used in dockerfiler::add_dockerfile()

create_dependencies_file() uses DESCRIPTION as source of information.
_Note that DESCRIPTION file can be auto-fill using find_remotes()

Criteria of success

  • A dependencies_file_text() exists and is tested

image

  • It is used in create_dependencies_file()

image

  • create_dependencies_file() returns a list with the contents of dependencies_file_text() to be reused elsewhere

image

Technicals

  • I'd like to have a subfunction that would help create the output as follows to be used in golem::add_dockerfile()

⚠️ fonction plus trop utilisée et qui utilisait : dockerfiler::doc_from_desc()

# Remotes ----
install.packages("remotes")
remotes::install_github('local::mylocalpackage')
remotes::install_cran('cli')
remotes::install_cran('config')
...
  • I'd like to have a subfunction that would help create this other output as follows to be used in dockerfiler::add_dockerfile()
# Remotes ----
install.packages("remotes")
remotes::install_github('local::mylocalpackage')
remotes::install_version('cli', version = "0.1.0")
remotes::install_version('config', version = "2.1.2")
...
  • I think that listing all packages with their version with install_version() is not reliable, because of versions of sub-dependencies. I would recommend to redirect users to {renv} and create the Dockerfile using {renv}.
  • It would be interesting to create the "socle" part of {dockerfiler} that install all deps, even without {renv}

att_to_description() can't deal with tests files

When using att_to_description(), it removes {spelling} from Suggests although it is used it in tests/spelling.R created by use_spell_check().

I tried att_to_description(dir.v = c("vignettes", "tests")) but doesn't work.

att_to_description(extra.suggests = "spelling") works but it will not be convenient with more packages used only in tests/.

Fix retrieve output from YAML

bookdown::html_document2 is not correctly retrieved with att_from_rmd() ans code_folding: "show" may lead to parse problems

---
title: "My Title"
author: "Sébastien Rochette"
date: "23/01/2021"
output: 
  bookdown::html_document2:
    toc: true
    code_folding: "show"
editor_options: 
  chunk_output_type: console
---

Escape code that needs to be escaped

With the code below {attachment} detects nknitr which is because knitr is written as character in the code of the function and is on a new line. Indeed, when {attachment} reads this code, it probably reads it with FALSE}\nknitr::opts_chunk, then thinks that nknitr is a package.
We may need to escape these escapes or replace with space, or something else

create_vignette_head <- function(pkg, vignette_name, yaml_options = NULL) {
  pkgname <- basename(pkg)

  # Get all yaml options except Title, output, editor_options
  yaml_options <- yaml_options[
    !names(yaml_options) %in% c("output", "title", "editor_options")]

  enc2utf8(
    glue(
      '---
title: ".{vignette_name}."
output: rmarkdown::html_vignette',
      ifelse(length(yaml_options) != 0,
             glue::glue_collapse(
               c("",
                 glue("{names(yaml_options)}: \"{yaml_options}\""), ""),
               sep = "\n"),
             "\n"),
      'vignette: >
  %\\VignetteIndexEntry{.{vignette_name}.}
  %\\VignetteEngine{knitr::rmarkdown}
  %\\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

```{r setup}
library(.{pkgname}.)
```
    ',
    .open = ".{", .close = "}."
    )
  )
}

attachment add uninstalled package in DESCRIPTION

# Create fake package ----
pkg_path <- tempfile(pattern = "pkg.")
dir.create(pkg_path)
usethis::create_package(pkg_path, open = FALSE)
cat("
#' Function
#' @importFrom dplyr filter
#' @importFrom ggplot ggplot
#' @export
my_fun <- function() {
data %>%
filter(col == 3) %>%
mutate(new_col = 1) %>%
ggplot() +
  aes(x, y, colour = new_col) +
  geom_point()
}

#' Function not exported but with doc
my_not_exported_doc <- function() {
  message('Not exported but with title, should have @noRd')
}
", file = file.path(pkg_path, "R", "function.R"))

attachment::att_amend_desc(path = pkg_path)
attachment::att_amend_desc(path = pkg_path)
# Error: Dependency package(s) 'ggplot' not available.
# Run `rlang::last_error()` to see where the error occurred.
# In addition: Warning message:
#   In (function (dep_name, dep_ver = "*")  :
#         Dependency package 'ggplot' not available.

this breaks, NAMESPACE, DESCPRIPTION etc

we need to check thant package is installed before beeing added in DESPRIPTION

As dev, I want to take in account for `@main` in the Remotes field of DESCRIPTION

As dev, I'd like the "Remotes" field to keep my URL if I specify a commit tag after @

Validation

  • If a package like {glue} is listed manually by the user in Imports or Suggests, I can specify Remotes as follows, and it should not be deleted with att_amend_desc():
Remotes: 
    git::https://github.com/tidyverse/glue@main

image

Tech

  • Start by creating a unit test to verify that @main is not deleted
  • Does add_remotes_to_desc() accounts for @main and delete it if renewed ?

Add option to check missing or not

missing_packages breaks workflows with bookdown in CI (in particular if you use gitlabr::use_gitlab_ci() bookdown CI templates: https://github.com/statnmap/gitlabr/tree/main/inst/gitlab-ci):

The package pagedown is missing or more probably misspelled.
Please correct your typo or install it.

The line below should work because it was added to list dependencies necessary to build the bookdown and then used to install missing packages from remotes::install_local(). Hence, missing package is expected there.

imports <- unique(c("bookdown", "knitr", "pagedown", attachment::att_from_rmds(".", recursive = FALSE)));
attachment::att_to_desc_from_is(path.d = "DESCRIPTION", imports = imports)

There should be an option to warn instead of stop, although that would also mean that potentially we add bad package name in the list in DESCRIPTION. But we will see it at install.

Then, I will add a error_missing = TRUE by default.

  • This needs to stop during package development otherwise, bad DESCRIPTION breaks the check()
  • It will then be necessary to modify all production CI with error_missing = FALSE.
  • It will also be necessary fix it in {gitlabr}

Cannot install attachment: Removed from CRAN

I cannot install the current attachment package from CRAN.

$ Rscript -e "install.packages('attachment', repos='http://cran.us.r-project.org')"
Warning message:
package ‘attachment’ is not available for this version of R

A version of this package for your version of R might be available elsewhere,
see the ideas at
https://cran.r-project.org/doc/manuals/r-patched/R-admin.html#Installing-packages

Checking the project page https://cran.r-project.org/package=attachment, it seems the package was removed:

Package ‘attachment’ was removed from the CRAN repository.

Formerly available versions can be obtained from the archive.

Archived on 2022-09-08 as check problems were not corrected in time.

A summary of the most recent check results can be obtained from the check results archive.

Please use the canonical form https://cran.r-project.org/package=attachment to link to this page.

The problem seems to be:

Version: 0.2.5
Check: for unstated dependencies in ‘tests’
Result: WARN
Warning: unable to access index for repository https://bioconductor.org/packages/3.14/bioc/src/contrib:
cannot open URL 'https://bioconductor.org/packages/3.14/bioc/src/contrib/PACKAGES'
Warning: unable to access index for repository https://bioconductor.org/packages/3.14/data/annotation/src/contrib:
cannot open URL 'https://bioconductor.org/packages/3.14/data/annotation/src/contrib/PACKAGES'
Warning: unable to access index for repository https://bioconductor.org/packages/3.14/data/experiment/src/contrib:
cannot open URL 'https://bioconductor.org/packages/3.14/data/experiment/src/contrib/PACKAGES'
Flavor: r-oldrel-windows-ix86+x86_64

As a dev, I need an `extra.imports` parameter for `att_amend_desc()`

Context

There are some cases where the required packages are not directly listed in the "R/" directory. For instance, a Rmd file in "inst/" that is run from a function of the package. If there are specific packages in the Rmd file, there are not detected by attachment::att_amend_desc()

I think I will not recommend this practice as it may lead to more packages than needed in Imports of the DESCRIPTION file. I would prefer recommend using @importFrom package function where better suited, or opening an issue here to explain where {attachment} failed to detect a dependency.

See: https://thinkr-open.github.io/attachment/dev/articles/a-fill-pkg-description.html#a-package-was-not-detected-by-att_amend_desc

Validation

  • I can directly add an 'Import' during the att_amend_desc() for specific cases with extra.imports field
  • extra.imports is more important that extra.suggests
  • If I use extra.imports and the package was not already detected as "imports" by {attachment}, there is a message informing the user that this practice must be used with caution because they had hard dependencies.
    • Add a comment: please open an issue on {attachment} to explain the use case that forced you to use this parameter

A few steps before CRAN submission

Validation

  • Package was cleaned for files created in userspace during the process. If some are remaining, they are in the session "tmp/" directory.

image

  • The revdepcheck is good for {golem}
  • The revdepcheck is good for {fusen}
  • The CRAN comment says that we corrected the WARN in the "check_results_attachment.html"

Technicals

As dev, I want create_dependencies_file() to take other sources into account

create_dependencies_file() uses DESCRIPTION as source of information.
_Note that DESCRIPTION file can be auto-fill using find_remotes()

Criteria of success

  • If my DESCRIPTION contains
Depends:
    mylocalpackage
Remotes:
    local::mylocalpackage

Then "dependencies_file.R" should looks like this

output

# Remotes ----
install.packages("remotes")
remotes::install_local('mylocalpackage')
# Attachments ----
to_install <- c("cli", "config", "DBI", "dplyr", "glue", "golem", "htmltools", "knitr", "mylocalpackage", "magrittr", "purrr", "readr", "readxl", "rmarkdown", "shiny", "shinythemes", "stringdist", "stringr", "tibble", "tidyr", "writexl")
  for (i in to_install) {
    message(paste("looking for ", i))
    if (!requireNamespace(i)) {
      message(paste("     installing", i))
      install.packages(i)
    }
  }

And NOT like today:

# Remotes ----
install.packages("remotes")
remotes::install_github('local::mylocalpackage')
# Attachments ----
to_install <- c("cli", "config", "DBI", "dplyr", "glue", "golem", "htmltools", "knitr", "mylocalpackage", "magrittr", "purrr", "readr", "readxl", "rmarkdown", "shiny", "shinythemes", "stringdist", "stringr", "tibble", "tidyr", "writexl")
  for (i in to_install) {
    message(paste("looking for ", i))
    if (!requireNamespace(i)) {
      message(paste("     installing", i))
      install.packages(i)
    }
  }

Technicals

  • I think that listing all packages with their version with install_version() is not reliable, because of versions of sub-dependencies. I would recommend to redirect users to {renv} and create the Dockerfile using {renv}.
  • At least, what is interesting is to list deps coming from GitHub, GitLab, etc... Except that remotes::install_deps() does read the DESCRIPTION correctly. Just need to use set_remotes_to_desc() during the process to be sure DESCRIPTION file is up-to-date.

Get remotes in desc for github packages

We could use something like this to get remotes for DESCRIPTION files

pkg <- attachment::att_from_description()
test <- lapply(pkg, function(x){
  packageDescription(x)
  }) %>%
  setNames(pkg)
cran_or_not <- lapply(test, function(x){
  print(x)
  x[["Repository"]]
  }) %>%
  sapply(., is.null)

github_pkg <- names(cran_or_not[cran_or_not])
cran_pkg <- names(cran_or_not[!cran_or_not])
github_repo <- lapply(github_pkg,function(x) {
  desc <- test[[x]]
  tolower(paste(desc$RemoteUsername, desc$RemoteRepo, sep = "/"))
  }) %>%
  setNames(github_pkg)
lapply(cran_pkg, install.packages)
lapply(github_repo, remotes::install_github)

As dev, I want to improve create_dependencies_file() with the install_if_missing parameter

As a dev, I want to improve create_dependencies_file() so that the name of the install_if_missing parameter is more explicit

Criteria of success

  • The name of the parameter to check the presence of a package version is more explicit

image

  • the parameter changes the installation instruction of the remote package

image

Technicals

  • replace install_if_missing -> install_only_if_missing
  • Modify dependencies_file to check also {remotes}

Get dependencies in Rmd inline code

If a call is made only in a inline code like ``r length(devtools::revdep("shiny"))`` for instance, attachment::att_from_rmds() will not detect it.

Call to fusen::inflate modifies warning level in global options

It appears that calling the function fusen::inflate() modifies the warning level in the user global R options from 0 (default) to -1 (ignore all warnings), without advertising it, which is a problem when you are then doing some development (e.g. in Rstudio) expecting some code to throw a warning.

I encountered this problem both inside Rstudio and in R console from the command line.

Here is a minimum working example (from the fusen::inflate() man page).

# warning option
options("warn")

    ## $warn
    ## [1] 0

# Create a new project
dummypackage <- tempfile("dummypackage")
dir.create(dummypackage)

# {fusen} steps 1
dev_file <- fusen::add_flat_template(
    template = "full", pkg = dummypackage, overwrite = TRUE)

    ## Created file .here in /tmp/Rtmpzolcwa/dummypackage4188925db7dfa . Please start a new R session in the new project directory.

# warning option
options("warn")

    ## $warn
    ## [1] 0

# {fusen} steps 2
fusen::fill_description(
    pkg = dummypackage, fields = list(Title = "Dummy Package"))

    ## [1] "/tmp/Rtmpzolcwa/dummypackage4188925db7dfa/DESCRIPTION"

# warning option
options("warn")

    ## $warn
    ## [1] 0

# {fusen} steps 3
flat_file <- dev_file[grepl("flat", dev_file)]
fusen::inflate(
    pkg = dummypackage, flat_file = flat_file,
    vignette_name = "Exploration of my Data", check = FALSE
)

    ## ✔ Setting active project to '/tmp/RtmpgzmK7n/dummypackage419b7345c4985'
    ## ℹ Loading dummypackage419b7345c4985
    ## Writing NAMESPACE
    ## Loading required namespace: testthat
    ## ✔ Adding 'knitr' to Suggests field in DESCRIPTION
    ## ✔ Setting VignetteBuilder field in DESCRIPTION to 'knitr'
    ## ✔ Adding 'inst/doc' to '.gitignore'
    ## Updating dummypackage419b7345c4985 documentation
    ## ℹ Loading dummypackage419b7345c4985
    ## Writing NAMESPACE
    ## Writing my_median.Rd
    ## Writing my_other_median.Rd
    ## Writing sub_median.Rd
    ## ℹ Loading dummypackage419b7345c4985
    ## [+] 3 package(s) added: stats, rmarkdown, testthat.
    ## [1] "/tmp/RtmpgzmK7n/dummypackage419b7345c4985"

# warning option
options("warn")

    ## $warn
    ## [1] -1

And here is my sessionInfo():

## R version 4.2.2 (2022-10-31)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Arch Linux
## 
## Matrix products: default
## BLAS:   /usr/lib/libblas.so.3.11.0
## LAPACK: /usr/lib/liblapack.so.3.11.0
## 
## locale:
##  [1] LC_CTYPE=en_IE.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=en_IE.UTF-8        LC_COLLATE=en_IE.UTF-8    
##  [5] LC_MONETARY=en_IE.UTF-8    LC_MESSAGES=en_IE.UTF-8   
##  [7] LC_PAPER=en_IE.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=en_IE.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] dummypackage41a847f926621_0.0.0.9000 conflicted_1.1.0                    
## 
## loaded via a namespace (and not attached):
##  [1] tidyselect_1.2.0 xfun_0.36        parsermd_0.1.2   purrr_1.0.1     
##  [5] vctrs_0.5.1      generics_0.1.3   testthat_3.1.6   htmltools_0.5.4 
##  [9] usethis_2.1.6    yaml_2.3.6       utf8_1.2.2       rlang_1.0.6     
## [13] pillar_1.8.1     glue_1.6.2       withr_2.5.0      DBI_1.1.3       
## [17] fusen_0.4.1      lifecycle_1.0.3  stringr_1.5.0    commonmark_1.8.1
## [21] memoise_2.0.1    evaluate_0.19    knitr_1.41       tzdb_0.3.0      
## [25] fastmap_1.1.0    fansi_1.0.3      attachment_0.3.1 Rcpp_1.0.9      
## [29] readr_2.1.3      backports_1.4.1  checkmate_2.1.0  cachem_1.0.6    
## [33] desc_1.4.2       pkgload_1.3.2    fs_1.5.2         brio_1.1.3      
## [37] digest_0.6.31    hms_1.1.2        stringi_1.7.12   dplyr_1.0.10    
## [41] rprojroot_2.0.3  here_1.0.1       cli_3.6.0        tools_4.2.2     
## [45] magrittr_2.0.3   tibble_3.1.8     crayon_1.5.2     tidyr_1.2.1     
## [49] pkgconfig_2.0.3  ellipsis_0.3.2   xml2_1.3.3       assertthat_0.2.1
## [53] rmarkdown_2.19   roxygen2_7.2.3   rstudioapi_0.14  R6_2.5.1        
## [57] compiler_4.2.2

Package misspelled in DESCRIPTION error after `attachment::att_amend_desc()`

Starting out with {golem} and attempting to get to run_app() for the first time.

Running attachment::att_amend_desc() from dev/02_dev.R and get the following:

> attachment::att_amend_desc()
Updating spatialGolex documentation
ℹ Loading spatialGolex
Writing NAMESPACE
Writing NAMESPACE
ℹ Loading spatialGolex
Error in att_to_desc_from_is(path.d, imports, suggests, normalize, must.exist) : 
  The package spelling is missing or misspelled.
Please correct your typo or install it.

Package spelling is in the DESCRIPTION:

Package: spatialGolex
Title: Spatial Shiny app
....
Suggests: 
    spelling,
    testthat (>= 3.0.0)
Config/testthat/edition: 3
....

Could I have done something wrong elsewhere?

Find package used in `r `

If I have an Rmd with

`r pkg::fun()`

{attachment} won't be able to find it.

> x <- tempfile(fileext = ".Rmd")
> file.create(x)
[1] TRUE
> write("`r dplyr::select(iris, Species)`", x)
> readLines(x)
[1] "`r dplyr::select(iris, Species)`"
> attachment::att_from_rmd(x)
logical(0)

Would be nice to catch it.

Search for packages listed as text for "Suggests"

Apparently, now all packages that are listed in Suggests must be conditionally loaded. You have to test if they are installed, otherwise you should not run the vignette or the test.
I'll have to look for the packages in another way in {attachment}... 😞
Example here for a vignette : https://github.com/adamhsparks/epicrop/blob/d311ab5489e3f82fd6a67cdba8348af361c87fe5/vignettes/epirice.Rmd#L20
And here for a unit test: openplantpathology/hagis@b9227fc

Search for : skip_if_not_installed() or requireNamespace()

Clean att_from_namespace()

test why this NAMESPACE does not work properly:

# Generated by roxygen2: do not edit by hand

export("%>%")
importFrom(Rcpp,evalCpp)
importFrom(magrittr,"%>%")
useDynLib(rcpp.pkg, .registration = TRUE)

Also clean not used readLines(path)

`attachment::att_amend_desc()` loads functions but dependencies cannot be resolved.

Expected Result

If functions are loaded and made available to the users they should be runable without any trouble.

Actual Result

If I run attachment::att_amend_desc() my package function are available in the global environment but do not run properly because R cannot resolve their dependencies.

Reprex

Below is the full reprex of the issue.

dummypackage <- tempfile('dummypackage')
suppressMessages(
  usethis::create_package(
    path = dummypackage, 
    open = FALSE,
  )
)
#> Package: dummypackage17699584f5f07
#> Title: What the Package Does (One Line, Title Case)
#> Version: 0.0.0.9000
#> Authors@R (parsed):
#>     * First Last <[email protected]> [aut, cre] (YOUR-ORCID-ID)
#> Description: What the package does (one paragraph).
#> License: `use_mit_license()`, `use_gpl3_license()` or friends to pick a
#>     license
#> Encoding: UTF-8
#> Roxygen: list(markdown = TRUE)
#> RoxygenNote: 7.2.0

# Add a dummy function using an external dependency
# namely the {magrittr} pipe %>% 
r_file <- file.path(dummypackage, "R", "fun.R")
file.create(r_file)
#> [1] TRUE
writeLines(
  text = "#' @importFrom magrittr %>%
#' @export
my_length <- function(x) {
  x %>% length()
}",
con = r_file
)

# Add {magrittr} in the DESCRIPTION Imports Field
usethis::use_package("magrittr")
#> Error: Path '/tmp/RtmpT8Kiax/reprex-1761e3d8a0014-milky-cub/' does not appear to be inside a project or package.

# Convert Roxygen tags to .Rd
roxygen2::roxygenise(
  package.dir = dummypackage
)
#> ℹ Loading dummypackage17699584f5f07
#> Writing 'NAMESPACE'
#> Writing 'NAMESPACE'

# => This fails because the package is loaded before the NAMESPACE is created.
# roxygen2::roxygenise() uses roxygen2::load_pkgload() which by default equals to
# pkgload::load_all(path, helpers = FALSE, attach_testthat = FALSE)$env
# This is because: "roxygen2 is a dynamic documentation system, which means it 
# works with the objects inside your package, not just the source code used to create them."
# -> First all functions are loaded then the NAMESPACE is generated. 
# my_length() is available in the global environmeent but as there was no NAMESPACE when 
# it was loaded it cannot resolve its dependencies.
my_length(1)
#> Error in x %>% length(): could not find function "%>%"

# Re running roxygen2::load_pkgload(), reloads my_length() 
# but this time the NAMESPACE does exists, R can use it to 
# resolve dependencies and then... 
roxygen2::load_pkgload(path = dummypackage)
#> ℹ Loading dummypackage17699584f5f07
#> <environment: namespace:dummypackage17699584f5f07>

# ... my_length() works
my_length(1)
#> [1] 1

# Removing the NAMESPACE
namespace <- file.path(dummypackage, "NAMESPACE")
file.remove(namespace)
#> [1] TRUE

roxygen2::roxygenise(
  package.dir = dummypackage
)
#> ℹ Loading dummypackage17699584f5f07
#> Writing 'NAMESPACE'
#> Writing 'NAMESPACE'
# Does not work
my_length(1)
#> Error in x %>% length(): could not find function "%>%"

roxygen2::roxygenise(
  package.dir = dummypackage
)
#> ℹ Loading dummypackage17699584f5f07
# Works since roxygen2::roxygenise() was run 2 times
# The NAMESPACE was around when the package was loaded the second time.
my_length(1)
#> [1] 1


# attachment::att_amend_desc() systematically remove the NAMESPACE, 
# thus running running this function 2 times wont fix the problem
attachment::att_amend_desc(
  path = dummypackage
)
#> Updating dummypackage17699584f5f07 documentation
#> ℹ Loading dummypackage17699584f5f07Writing 'NAMESPACE'Writing 'NAMESPACE'[+] 1 package(s) added: magrittr.
# Does not work
my_length(1)
#> Error in x %>% length(): could not find function "%>%"
attachment::att_amend_desc(
  path = dummypackage
)
#> Updating dummypackage17699584f5f07 documentation
#> ℹ Loading dummypackage17699584f5f07Writing 'NAMESPACE'Writing 'NAMESPACE'
# Still does not work
my_length(1)
#> Error in x %>% length(): could not find function "%>%"


attachment::att_amend_desc(
  path = dummypackage
)
#> Updating dummypackage17699584f5f07 documentation
#> ℹ Loading dummypackage17699584f5f07Writing 'NAMESPACE'Writing 'NAMESPACE'
roxygen2::load_pkgload(path = dummypackage)
#> ℹ Loading dummypackage17699584f5f07
#> <environment: namespace:dummypackage17699584f5f07>
# works !
my_length(1)
#> [1] 1

# The main culprit is attachment::att_from_namespace()
# This where the NAMESPACE is removed and recreated with roxygen2::roxygenise()
# each time
attachment::att_from_namespace(
  path = file.path(dummypackage, "NAMESPACE")
)
#> Updating dummypackage17699584f5f07 documentation
#> ℹ Loading dummypackage17699584f5f07Writing 'NAMESPACE'Writing 'NAMESPACE'
#> [1] "magrittr"
# Does not work
my_length(1)
#> Error in x %>% length(): could not find function "%>%"

roxygen2::load_pkgload(path = dummypackage)
#> ℹ Loading dummypackage17699584f5f07
#> <environment: namespace:dummypackage17699584f5f07>
# works !
my_length(1)
#> [1] 1

Created on 2022-07-08 by the reprex package (v2.0.1)

Session info
sessioninfo::session_info()
#> ─ Session info ───────────────────────────────────────────────────────────────
#>  setting  value
#>  version  R version 4.2.1 (2022-06-23)
#>  os       Pop!_OS 22.04 LTS
#>  system   x86_64, linux-gnu
#>  ui       X11
#>  language (EN)
#>  collate  en_US.UTF-8
#>  ctype    en_US.UTF-8
#>  tz       Europe/Amsterdam
#>  date     2022-07-08
#>  pandoc   2.18 @ /usr/lib/rstudio/bin/quarto/bin/tools/ (via rmarkdown)
#> 
#> ─ Packages ───────────────────────────────────────────────────────────────────
#>  ! package                   * version    date (UTC) lib source
#>    attachment                  0.2.5.9000 2022-07-08 [1] local
#>    brio                        1.1.3      2021-11-30 [1] CRAN (R 4.2.0)
#>    cli                         3.3.0      2022-04-25 [1] CRAN (R 4.2.0)
#>    crayon                      1.5.1      2022-03-26 [1] CRAN (R 4.2.0)
#>    desc                        1.4.1      2022-03-06 [1] CRAN (R 4.2.0)
#>    digest                      0.6.29     2021-12-01 [1] CRAN (R 4.2.0)
#>  R dummypackage17699584f5f07 * 0.0.0.9000 <NA>       [?] <NA>
#>    ellipsis                    0.3.2      2021-04-29 [1] CRAN (R 4.2.0)
#>    evaluate                    0.15       2022-02-18 [1] CRAN (R 4.2.0)
#>    fansi                       1.0.3      2022-03-24 [1] CRAN (R 4.2.0)
#>    fastmap                     1.1.0      2021-01-25 [1] CRAN (R 4.2.0)
#>    fs                          1.5.2      2021-12-08 [1] CRAN (R 4.2.0)
#>    glue                        1.6.2      2022-02-24 [1] CRAN (R 4.2.0)
#>    highr                       0.9        2021-04-16 [1] CRAN (R 4.2.0)
#>    htmltools                   0.5.2      2021-08-25 [1] CRAN (R 4.2.0)
#>    knitr                       1.39       2022-04-26 [1] CRAN (R 4.2.0)
#>    lifecycle                   1.0.1      2021-09-24 [1] CRAN (R 4.2.0)
#>    magrittr                    2.0.3      2022-03-30 [1] CRAN (R 4.2.0)
#>    pillar                      1.7.0      2022-02-01 [1] CRAN (R 4.2.0)
#>    pkgconfig                   2.0.3      2019-09-22 [1] CRAN (R 4.2.0)
#>    pkgload                     1.3.0      2022-06-27 [1] CRAN (R 4.2.0)
#>    purrr                       0.3.4      2020-04-17 [1] CRAN (R 4.2.0)
#>    R6                          2.5.1      2021-08-19 [1] CRAN (R 4.2.0)
#>    reprex                      2.0.1      2021-08-05 [1] CRAN (R 4.2.0)
#>    rlang                       1.0.3      2022-06-27 [1] CRAN (R 4.2.0)
#>    rmarkdown                   2.14       2022-04-25 [1] RSPM (R 4.2.0)
#>    roxygen2                    7.2.0      2022-05-13 [1] CRAN (R 4.2.0)
#>    rprojroot                   2.0.3      2022-04-02 [1] CRAN (R 4.2.0)
#>    rstudioapi                  0.13       2020-11-12 [1] CRAN (R 4.2.0)
#>    sessioninfo                 1.2.2      2021-12-06 [1] CRAN (R 4.2.0)
#>    stringi                     1.7.6      2021-11-29 [1] CRAN (R 4.2.0)
#>    stringr                     1.4.0      2019-02-10 [1] CRAN (R 4.2.0)
#>    testthat                    3.1.4      2022-04-26 [1] CRAN (R 4.2.0)
#>    tibble                      3.1.7      2022-05-03 [1] CRAN (R 4.2.0)
#>    usethis                     2.1.6      2022-05-25 [1] CRAN (R 4.2.0)
#>    utf8                        1.2.2      2021-07-24 [1] CRAN (R 4.2.0)
#>    vctrs                       0.4.1      2022-04-13 [1] CRAN (R 4.2.0)
#>    withr                       2.5.0      2022-03-03 [1] CRAN (R 4.2.0)
#>    xfun                        0.31       2022-05-10 [1] CRAN (R 4.2.0)
#>    xml2                        1.3.3      2021-11-30 [1] CRAN (R 4.2.0)
#>    yaml                        2.3.5      2022-02-21 [1] CRAN (R 4.2.0)
#> 
#>  [1] /home/bob/R/x86_64-pc-linux-gnu-library/4.2
#>  [2] /opt/R/4.2.1/lib/R/library
#> 
#>  R ── Package was removed from disk.
#> 
#> ──────────────────────────────────────────────────────────────────────────────

R CMD check fails with dev roxygen2

  ══ Failed tests ════════════════════════════════════════════════════════════════
  ── Failure (test-att_from_namespace.R:88:3): bad namespace can be corrected ────
  `att_from_namespace(...)` did not throw the expected error.
  
  [ FAIL 1 | WARN 0 | SKIP 1 | PASS 116 ]
  Error: Test failures
  Execution halted

Possibly because roxygen2 now tries harder to avoid creating a bad NAMESPACE. I'm aiming for a CRAN release May 13.

Deal with local package dependencies in find_remotes()

For now in extract_pkg_info(),

What is desired ?

DESCRIPTION

Imports:
    mylocalpackage
Remotes:
    local::mylocalpackage

Technically

To test:

  • remotes::install_local( ) from path to compressed file
  • remotes::install_local( ) from path to local directory
  • Recovering the content of the files DESCRIPTION
  • Create a fake_desc_local

As dev, I'd like a function to store `att_amend_desc()` parameters in a yaml file

As dev, I'd like a function to store att_amend_desc() parameters in a yaml file so that I can re-use them later on

Validation

  • a new fonction exist to store att_amend_desc() parameters in a yaml file

image

=> https://github.com/ThinkR-open/attachment/blob/main/R/save_att_params.R

  • when I call this function with a list of parameters used in att_amend_desc(), it saves them inside a yaml

image

  • if a yaml already exists, it will overwrite based on a logical param

image

  • if I run the function without parameter but still specify to overwrite, it will clear the yaml file or create an empty new yaml if it does not already exists

image

=> https://github.com/ThinkR-open/attachment/blob/main/tests/testthat/test-save_att_params.R

Tech-Dev

  • make a new flat file for yaml param handling that takes a named list of parameters as input
  • make unit test to write yaml
  • avoid the use of additional dependencies, except for {yaml}

Add unit tests

  • Test for Remotes field in DESCRIPTION for att_amend_desc()
    • Test that the field keeps existing if package is in imports/suggests
    • Test that the field disappears if the package is not in imports/suggests
  • Test for Remotes field in DESCRIPTION for create_dependencies_file()
    • Test that the field keeps existing if package is in imports/suggests
    • Test that the field disappears if the package is not in imports/suggests
  • Test the good functioning of pkg_ignore in att_amend_desc()
    • Test that package is correctly ignored and does not appear in DESCRIPTION
  • Test for non existing directories for dir.r and dir.t in att_amend_desc()

CRAN comments

  • Please add \value to .Rd files regarding exported methods and explain
    the functions results in the documentation.
    Please write about the
    structure of the output (class) and also what the output means. (If a
    function does not return a value, please document that too, e.g.
    \value{No return value, called for side effects} or similar)
    Missing Rd-tags:
    attachment-deprecated.Rd: \value

=> Added in the meta description of attachment-deprecated

#' @keywords internal
#' @return List of functions used for deprecation side effects.
#' Output depends on the deprecated function.
  • Please always write package names, software names and API (application
    programming interface) names in single quotes in title and description.
    e.g: --> 'R'
    Please note that package names are case sensitive.

=> Corrected R to ".R" in the description as I speak about the extension and not the software.
Similarly corrected Rmd to ".Rmd"

  • Please omit the redundant "Tools to help" at the start of your description.

=> Changed to: Manage dependencies during package development.

  • You are using installed.packages() in your code. As mentioned in the
    notes of installed.packages() help page, this can be very slow.
    Therefore do not use installed.packages(). -> man/find_remotes.Rd

=> The example where it appeared was changed to: find_remotes(list.files(.libPaths())).
Hence, we only retrieve installed packages names, and not all the extra information not needed
for this example.

"This needs to read several files per installed package, which will be
slow on Windows and on some network-mounted file systems. It will be
slow when thousands of packages are installed, so do not use it to find
out if a named package is installed (use find.package or system.file)
nor to find out if a package is usable (call requireNamespace or require
and check the return value) nor to find details of a small number of
packages (use packageDescription)." [installed.packages() help page]

As dev, I want create_dependencies_file() to have a parameter install_if_missing

create_dependencies_file() uses DESCRIPTION as source of information.
_Note that DESCRIPTION file can be auto-fill using find_remotes()

Criteria of success

  • create_dependencies_file() to have an install_if_missing install_only_if_missing parameter

image

  • From a DESCRIPTION file such as:
    image

    • If install_if_missing = FALSE (by default) , the installation instructions don't check, beforehand, if the packages are missing

image

  • If install_if_missing = TRUE (by default) , the installation instructions check, beforehand, if the packages are missing

image

Technicals

  • Add a parameter install_if_missing = FALSE that will add a if(requireNamespace(quietly = TRUE)) {} before each install if the parameter is TRUE
# Remotes ----
if(requireNamespace("remotes", quietly = TRUE)) {install.packages("remotes")}
if(requireNamespace("mylocalpackage", quietly = TRUE)) {remotes::install_github('local::mylocalpackage')}
...
  • I think that listing all packages with their version with install_version() is not reliable, because of versions of sub-dependencies. I would recommend to redirect users to {renv} and create the Dockerfile using {renv}.
  • It would be interesting to create the "socle" part of {dockerfiler} that install all deps, even without {renv}

As a dev, I would like a config file that stores parameters for `att_amend_desc()`

Context

When I have a specific package, I change default parameters of att_amend_desc(), like pkg_ignore or extra.suggest. I'd like to be able to run att_amend_desc() directly in my console, but using my parameters, without having to go to the "dev_history" file where this line of code is written

Validation

  • I can run att_amend_desc() with parameters, and it replaces the config file

Screenshot 2023-04-04 at 12 25 29

  • I can run att_amend_desc(use.config = TRUE) from anywhere, directly in the console, and it uses the last version of parameters of att_amend_desc() stored in a config file

(running the last chunk of the flat file dev/flat_save_att_params.Rmd both perform inflate() + att_amend_dec() with saved config :)
Screenshot 2023-04-04 at 12 32 38

  • The user is informed about what is happening

(when updating config)
image

(when using config)
image

  • I have the possibility to run a temporary version of att_amend_desc() with some parameters, without changing the config file (default behavior)

(e.g., removing two pkgs from suggest)
Screenshot 2023-04-04 at 12 57 50

Tech

  • att_amend_desc() has two new parameters named update.config = FALSE and use.config = FALSE by default
#' @param update.config logical Should the list of parameter be saved for later use with use.config
#' @param use.config logical Should the att_amend_desc use the parameters saved in config
#' @param path.y character Path to yaml config file

Improve doc for bookdown with CI

Update vignette part on Bookdown with:

  • Title 2: Use {attachment} with Bookdown dependencies
  • Add: usethis::use_description()
  • Run lines already available in vignette
  • For CI: Add install.packages("remotes"); remotes::install_deps()
  • Then build your bookdown
  • See examples in {gitlabr} gitlab-ci.yml.

Do not use stringified references to packages

I have the string `gastempt::powexp_slope() in a test-comment, leading to this package being included in suggests. Strings should not be searched for dependencies.

cap = paste0("Meal volume (left) and flow when gastric emptying function is a power exponential function. Slope was computed with  function `gastempt::powexp_slope()`"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.