config icon indicating copy to clipboard operation
config copied to clipboard

Allow for a "config.user.yml" by default

Open colearendt opened this issue 5 years ago • 5 comments

In many projects, there are "default" and "available" values that are stored in config.yml. However, sometimes a fork / implementation of the project may want to use different parameters without

It'd be really nice to allow a default like config.user.yml that could be .gitignore'd for user modifications without retaining dirty git state, templatizing config.yml, etc.

config::get("myvalue")

Would:

  • read values from config.yml as per usual
  • overwrite values from config.yml with those from config.user.yml
  • potentially allow unsetting values in config.user.yml somehow? By setting to null?

colearendt avatar Jul 13 '20 17:07 colearendt

This would also be useful in local development where I would for example want to connect to my local database instead of a production one.

The same can roughly be achieved using the environments, but I feel the file overload is pragmatically simpler and faster.

Fuco1 avatar Jan 05 '21 20:01 Fuco1

I think it can be managed with the available package functions in few lines of code.

Let's say that we have a global configuration file that is versionned on the repository:

lGlobalConf <- list(default = list(trials = 5, dataset = "data-complete.csv", extra = "Something",
                                   subParam = list(a = 1, b = 2)))
yaml::write_yaml(lGlobalConf, file = "config.yml")

which is the following yaml file:

default:
  trials: 5.0
  dataset: data-complete.csv
  extra: Something
  subParam:
    a: 1.0
    b: 2.0

And a use config file that overwrite some global options on a config file not versionned on the repository:

lUserConf <- list(default = list(dataset = "data-sampled.csv", extra = NULL, subParam = list(b = 99)))
yaml::write_yaml(lUserConf, file = "config.user.yml")

which is the following yaml file:

default:
  dataset: data-sampled.csv
  extra: ~
  subParam:
    b: 99.0

We can manage the overwrite mechanism this way with the current functions in the 'config' package:

rm(list = ls()) # Reset R session memory

# Load global configuration
cfg <- config::get()
# Load user configuration if exists
if(file.exists("config.user.yml")) cfgUser <- config::get(file = "config.user.yml")
# Merge configuration with user values overwritting global values
cfg <- config::merge(cfg, cfgUser)
#Display resulting configuration
str(cfg)
List of 4
 $ subParam:List of 2
  ..$ a: num 1
  ..$ b: num 99
 $ trials  : num 5
 $ dataset : chr "data-sampled.csv"
 $ extra   : NULL

We can see that user parameters have overwritten global ones even in nested structures. The NULL value doesn't remove the related configuration key as expected but since a condition is.null(cfg.extra) returns the same value whether the list item exists or not, I don't think this is a real issue.

What do you think about it?

DDorch avatar Apr 28 '21 14:04 DDorch

I want to deploy my application on the rsconnect server, but I can't connect to the data in the rsconnect vault. I have created a config.yml file as follows:

default:
   data_CI: 'Y:/Production/Flavour Common/MACDATA/DATAHOUSE/Rshiny/'

rsconnect:
   data_CI: '/userdata/macdata/data/'

I don't use a driver to connect the data. I have access to the files in the rsconnect thanks to WinCSP which allows me to add the files and to give them the rights of reading or writing When I test my application locally, it works fine, but when I go into the server, I get an error message like this:

Warning: Error in : `.x` is empty, and no `.init` supplied 

06/09 07:31:11.345 (GMT)  
[No stack trace available] 

Please help me ! Thank in advance

yannessanga avatar Jun 09 '21 08:06 yannessanga

@yannessanga, I don't think your question is related to the topic of this issue which is relative to a particular feature request on config. I don't even know if your problem is related to the use of the config package or rsconnect. You should probably ask your question on https://stackoverflow.com/ to get help from users.

DDorch avatar Jun 13 '21 07:06 DDorch

I have implement to concept "default" and "user" config with a default configuration provided by a package and a user one provided by a 'config.yml' file located by default in the working directory. In that way the user of the package can overwrite some pieces of the configuration:

#' Read default configuration of the package and complete it with eventual user config
#'
#' @param userFile location of the user config YML file
#' @param package The package where stand the default configuration (located in "inst/config.yml" of the package by default)
#'
#' @return A configuration as it is returned by [config::get]
#' @export
#'
#' @examples
#' cfg <- getConfig()
#' str(cfg)
getConfig <- function(userFile = "config.yml", pathDefaultCfg = system.file("config.yml", package = "myPackage")) {
  cfg <- config::get(file = pathDefaultCfg)
  if(file.exists(userFile)) {cfg = config::merge(cfg,config::get(file = userFile))}
  cfg
}

I think it's not necessary to implement mechanism of default/user config in the config package. Because (1) there is no obvious way to implement this (config.yml/config.user.yml vs different paths) and (2) it is relatively easy to write your own script of such a mechanism in 3 lines of code.

So, I am in favour of closing this feature request.

DDorch avatar Jun 13 '21 07:06 DDorch