# Best way to store package specific user settings?

**URL:** https://discourse.julialang.org/t/best-way-to-store-package-specific-user-settings/60626
**Category:** General Usage
**Created:** [May 6, 2021, 7:47am UTC](https://discourse.julialang.org/t/best-way-to-store-package-specific-user-settings/60626 "2021-05-06T07:47:19Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)
#### Post date: [May 6, 2021, 7:47am UTC](https://discourse.julialang.org/t/best-way-to-store-package-specific-user-settings/60626/1 "2021-05-06T07:47:19Z")

</div>

I want to add persistent theming back to Makie and I wanted to get a feel for what methods are out there and what the tradeoffs of different approaches are.

One consideration is where to store settings files. Should we just add a folder under .julia or maybe even make a .makie folder in the home directory? That’s how matplotlib does it for example. Or use scratch spaces maybe? (Haven’t used those yet)

The other question is what format people use to store settings. Yaml, toml, json, just a jl file? I can imagine that we want users to set parameters that are easier to write in a bit of julia code, but is it good practice to just eval some settings file into the current module at package load time? I mean only the user can edit this, so it seems fine in that regard, but could also cause unexpected results.

I’d be happy for experiences you had with your own packages.

---

<div class="post-metadata">

### Author: ![mike](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mike/32/39_2.png) [@mike](https://discourse.julialang.org/u/mike)
#### Post date: [May 6, 2021, 8:00am UTC](https://discourse.julialang.org/t/best-way-to-store-package-specific-user-settings/60626/2 "2021-05-06T08:00:14Z")

</div>

[GitHub - JuliaPackaging/Preferences.jl: Project Preferences Package](https://github.com/JuliaPackaging/Preferences.jl) might be worth a try?

---

<div class="post-metadata">

### Author: ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)
#### Post date: [May 6, 2021, 8:10am UTC](https://discourse.julialang.org/t/best-way-to-store-package-specific-user-settings/60626/3 "2021-05-06T08:10:46Z")

</div>

That looks nice on first glance. But this would not work with any preferences set as Julia code of course. Unless one evals strings that are stored, hmm. For example, define a range of colors with LA () from Colors.jl or something like that.

---

<div class="post-metadata">

### Author: ![mike](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mike/32/39_2.png) [@mike](https://discourse.julialang.org/u/mike)
#### Post date: [May 6, 2021, 8:16am UTC](https://discourse.julialang.org/t/best-way-to-store-package-specific-user-settings/60626/4 "2021-05-06T08:16:48Z")

</div>

Yeah, you wouldn’t be able to store arbitrary code in those preferences unless you want to go the `eval` route. I guess that could be seen as a pro or con really 😃

---

<div class="post-metadata">

### Author: ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)
#### Post date: [May 6, 2021, 9:05am UTC](https://discourse.julialang.org/t/best-way-to-store-package-specific-user-settings/60626/5 "2021-05-06T09:05:41Z")

</div>

You could serialize and base64-encode your Julia object as a string `s` and then deserialize it when loading the preference:

```julia
julia> using Colors

julia> cols = range(colorant"red", stop=colorant"green", length=15)
15-element Array{RGB{N0f8},1} with eltype RGB{FixedPointNumbers.N0f8}:
 RGB{N0f8}(1.0,0.0,0.0)
 RGB{N0f8}(0.929,0.035,0.0)
 RGB{N0f8}(0.859,0.071,0.0)
 RGB{N0f8}(0.784,0.11,0.0)
 RGB{N0f8}(0.714,0.145,0.0)
 RGB{N0f8}(0.643,0.18,0.0)
 RGB{N0f8}(0.573,0.216,0.0)
 RGB{N0f8}(0.502,0.251,0.0)
 RGB{N0f8}(0.427,0.286,0.0)
 RGB{N0f8}(0.357,0.322,0.0)
 RGB{N0f8}(0.286,0.357,0.0)
 RGB{N0f8}(0.216,0.392,0.0)
 RGB{N0f8}(0.141,0.431,0.0)
 RGB{N0f8}(0.071,0.467,0.0)
 RGB{N0f8}(0.0,0.502,0.0)

julia> using Serialization, Base64

julia> s = base64encode(sprint(serialize, cols))
"N0pMDwQAAAAVEAEDUkdCHws/MwtstsumuGBahFn3AqA9AQpDb2xvclR5cGVzRAEAAAAQAQZOb3JtZWQfC5Pqbom3ecWQolx9SheMxFMBEUZpeGVkUG9pbnROdW1iZXJzRAIAAAAAA+fu/wAA7QkA2xIAyBwAtiUApC4AkjcAgEAAbUkAW1IASVsAN2QAJG4AEncAAIAA"

julia> deserialize(IOBuffer(base64decode(s)))
15-element Array{RGB{N0f8},1} with eltype RGB{FixedPointNumbers.N0f8}:
 RGB{N0f8}(1.0,0.0,0.0)
 RGB{N0f8}(0.929,0.035,0.0)
 RGB{N0f8}(0.859,0.071,0.0)
 RGB{N0f8}(0.784,0.11,0.0)
 RGB{N0f8}(0.714,0.145,0.0)
 RGB{N0f8}(0.643,0.18,0.0)
 RGB{N0f8}(0.573,0.216,0.0)
 RGB{N0f8}(0.502,0.251,0.0)
 RGB{N0f8}(0.427,0.286,0.0)
 RGB{N0f8}(0.357,0.322,0.0)
 RGB{N0f8}(0.286,0.357,0.0)
 RGB{N0f8}(0.216,0.392,0.0)
 RGB{N0f8}(0.141,0.431,0.0)
 RGB{N0f8}(0.071,0.467,0.0)
 RGB{N0f8}(0.0,0.502,0.0)

```

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [May 6, 2021, 1:50pm UTC](https://discourse.julialang.org/t/best-way-to-store-package-specific-user-settings/60626/6 "2021-05-06T13:50:02Z")

</div>

> [@jules](#):
>
> define a range of colors with LA () from Colors.jl or something like that

Just store the component values as vectors. I would go with TOML, not that it is a standard library.

---

<div class="post-metadata">

### Author: ![MA\_Laforge](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ma_laforge/32/385_2.png) [@MA\_Laforge](https://discourse.julialang.org/u/MA_Laforge)
#### Post date: [May 9, 2021, 2:40pm UTC](https://discourse.julialang.org/t/best-way-to-store-package-specific-user-settings/60626/7 "2021-05-09T14:40:00Z")

</div>

> [@mike](#):
>
> [GitHub - JuliaPackaging/Preferences.jl: Project Preferences Package](https://github.com/JuliaPackaging/Preferences.jl) might be worth a try?

Thanks for pointing to Preferences.jl @mike. That compile-time preference thing looks very promising. I might use it to get a cairo-only version of InsepctDR.jl (plotting) running on machines without displays (where Gtk fails to build)!

I still would rather have get a dual-package repository going where one package is Cairo-only, and the other provides the Gtk GUI, but Preferences.jl might be a good “in the meantime” thing.

---

<div class="post-metadata">

### Author: ![MA\_Laforge](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ma_laforge/32/385_2.png) [@MA\_Laforge](https://discourse.julialang.org/u/MA_Laforge)
#### Post date: [May 9, 2021, 3:08pm UTC](https://discourse.julialang.org/t/best-way-to-store-package-specific-user-settings/60626/8 "2021-05-09T15:08:36Z")

</div>

I’ve struggled with this issue with many of my packages as well. Here’s what I did with InspectDR.jl:

### Specify defaults in `~/.julia/config/startup.jl`

`InspectDR.jl` allows users to tailor default settings using a `Dict` called `Main.DEFAULTS_INSPECTDR`. The intent is to get users to specify these _ **session-specific** _ settings in their `~/.julia/config/startup.jl` file:

```julia
DEFAULTS_INSPECTDR = Dict(
	:droppoints => :always, #{:always, :never, :noglyph, :hasline}
	:fontscale => 2,
	:fontname => "DejaVu Serif",
	:halloc_legend => 200,
	:notation_x => :SI, #ex: m, μ, n, p, ...
	:notation_y => :ENG, #Always powers of 3, unlike :SCI
	:rendersvg => false,
	:length_tickmajor => 10,
	:length_tickminor => 5,
	#[...]
)

```

### Settings read @ package initialization

- Settings are read in upon the initialization of `InspectDR` (` __init__ ()` function).
- Settings are read _ **into** _ a module level (“global”) “`defaults::Defaults`” variable.

```julia-auto
mutable struct Defaults
	rendersvg::Bool #Might want to dissalow SVG renderings for performance reasons
	xaxiscontrol_visible::Bool
	pointdropmatrix::PointDropMatrix
	colorscale::ColorScale #Default used for heatmaps

	plotlayout::PlotLayout #Can tweak pretty much everything here
	mplotlayout::MultiplotLayout
end
Defaults() = Defaults(
	false, false, PDM_NEVER, ColorScale(),
	PlotLayout(PREDEFAULTS), MultiplotLayout(PREDEFAULTS)
)

```

### 👍 Advantage

Users don’t have to `import InspectDR` from `~/.julia/config/startup.jl` in order to directly manipulate the `defaults` structure (which they _ **could** _ do).

This is _ **extremely** _ important to me - because I don’t want users to _ **have** _ to load InspectDR every time they start Julia: No need to slow down Julia if they aren’t going to use my module.

### 👎 Disadvantages

- You need to write specific code to read through the settings and write to the `defaults::Defaults` module-level variable.
- Users don’t get to use the facilities/structures provided by my module. The option `Dict()` has to stick to base Julia types (or types from very lightweight modules).

**Ex: fonts**  
Using the `Dict()` system, users cannot even specify default font using a simple `Font(12, "Serif")` object - because that is defined in InspectDR itself.

---

<div class="post-metadata">

### Author: ![MA\_Laforge](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ma_laforge/32/385_2.png) [@MA\_Laforge](https://discourse.julialang.org/u/MA_Laforge)
#### Post date: [May 9, 2021, 3:17pm UTC](https://discourse.julialang.org/t/best-way-to-store-package-specific-user-settings/60626/9 "2021-05-09T15:17:25Z")

</div>

But I thought of a potentially more interesting when I saw your post:

### `Requires.jl` solution

`Requires.jl` is fairly lightweight, so it seems reasonable to require users to import Requires.jl in their `~/.julia/config/startup.jl` file to get package-specific settings working:

(`~/.julia/config/startup.jl`):

```julia-auto
using Requires
@require DSP="717857b8-e6f2-59f4-9121-6e50c889abd2" begin
	@show DSP.conv([1,2],[1,2])

	#Configure your module here!
end

```

Alternatively, users could push all the settings code to a separate file:

```julia-auto
@require DSP="717857b8-e6f2-59f4-9121-6e50c889abd2" include("DSPconfig.jl")

```

### 👍 Advantages

- Fast.
- Simple.
- Straightforward.
- Users get to actually use the structures your module provides.

### 👎 Disadvantages

- Not sure yet.
