From 08eb0db1f13aa6da697b2f140cb8f498c6684629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Sun, 5 Feb 2023 21:57:42 +0100 Subject: [PATCH 1/9] improve precompilation coverage --- src/other/precompile.jl | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/other/precompile.jl b/src/other/precompile.jl index 916a7880b5..a85272bd81 100644 --- a/src/other/precompile.jl +++ b/src/other/precompile.jl @@ -22,16 +22,48 @@ SnoopPrecompile.@precompile_all_calls begin outerjoin(df, df, on=:a, makeunique=true) outerjoin(df, df, on=:b, makeunique=true) outerjoin(df, df, on=:c, makeunique=true) - semijoin(df, df, on=:a) - semijoin(df, df, on=:b) - semijoin(df, df, on=:c) leftjoin!(df, DataFrame(a=[2, 5, 3, 1, 0]), on=:a) leftjoin!(df, DataFrame(b=["a", "b", "c", "d", "e"]), on=:b) leftjoin!(df, DataFrame(c=1:5), on=:c) reduce(vcat, [df, df]) show(IOBuffer(), df) subset(df, :q) - @view df[1:3, :] + subset!(copy(df), :q) + df[:, 1:2] + df[1:2, :] + df[1:2, 1:2] @view df[:, 1:2] + @view df[1:2, :] + @view df[1:2, 1:2] transform!(df, :c, [:c :f] .=> [sum, mean, std], :c => :d, [:a, :c] => cor) + deleteat!(df, 1) + append!(df, copy(df)) + push!(df, copy(df[1, :])) + eachrow(df) + eachcol(df) + empty(df) + empty!(copy(df)) + filter(:q => identity, df) + filter!(:q => identity, df) + first(df) + last(df) + hcat(df, df, makeunique=true) + issorted(df) + pop!(df) + popfirst!(df) + repeat(df, 2) + reverse(df) + reverse!(df) + unique(df, :a) + unique!(df, :a) + wide = DataFrame(id=1:6, + a=repeat(1:3, inner=2), + b=repeat(1.0:2.0, inner=3), + c=repeat(1.0:1.0, inner=6), + d=repeat(1.0:3.0, inner=2)) + long = stack(wide) + unstack(long) + unstack(long, :variable, :value, combine=sum) + flatten(DataFrame(a=[[1, 2], [3, 4]], b=[1, 2]), :a) + dropmissing(DataFrame(a=[1, 2, 3, missing], b=["a", missing, "c", "d"])) end From 3f4a5696d1bc5bf58beb7a858fd15aa64fd0695e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Sun, 5 Feb 2023 22:54:19 +0100 Subject: [PATCH 2/9] one more precompilation set --- src/other/precompile.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/other/precompile.jl b/src/other/precompile.jl index a85272bd81..1e1d7abe01 100644 --- a/src/other/precompile.jl +++ b/src/other/precompile.jl @@ -66,4 +66,8 @@ SnoopPrecompile.@precompile_all_calls begin unstack(long, :variable, :value, combine=sum) flatten(DataFrame(a=[[1, 2], [3, 4]], b=[1, 2]), :a) dropmissing(DataFrame(a=[1, 2, 3, missing], b=["a", missing, "c", "d"])) + df = DataFrame(rand(20, 2), :auto) + df.id = repeat(1:2, 10) + combine(df, AsTable(r"x") .=> [ByRow(sum), ByRow(mean)]) + combine(groupby(df, :id), AsTable(r"x") .=> [ByRow(sum), ByRow(mean)]) end From df231f530f222897e8a6666dbd5d815b1c0dada7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Mon, 6 Feb 2023 09:49:33 +0100 Subject: [PATCH 3/9] add CSV as dependency --- Project.toml | 2 ++ src/DataFrames.jl | 1 + src/other/precompile.jl | 1 + 3 files changed, 4 insertions(+) diff --git a/Project.toml b/Project.toml index 386490985d..31773b0aba 100644 --- a/Project.toml +++ b/Project.toml @@ -23,6 +23,7 @@ Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" TableTraits = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" +CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" [compat] CategoricalArrays = "0.10.0" @@ -42,6 +43,7 @@ TableTraits = "0.4, 1" Tables = "1.9.0" Unitful = "1" julia = "1.6" +CSV = "0.10.9" [extras] CategoricalArrays = "324d7699-5711-5eae-9e2f-1d82baa6b597" diff --git a/src/DataFrames.jl b/src/DataFrames.jl index a2a652154a..bf8fe8ff9b 100644 --- a/src/DataFrames.jl +++ b/src/DataFrames.jl @@ -11,6 +11,7 @@ using PrettyTables using Random using Tables: ByRow import SnoopPrecompile +import CSV import DataAPI, DataAPI.allcombinations, diff --git a/src/other/precompile.jl b/src/other/precompile.jl index 1e1d7abe01..f8b0c89cc8 100644 --- a/src/other/precompile.jl +++ b/src/other/precompile.jl @@ -70,4 +70,5 @@ SnoopPrecompile.@precompile_all_calls begin df.id = repeat(1:2, 10) combine(df, AsTable(r"x") .=> [ByRow(sum), ByRow(mean)]) combine(groupby(df, :id), AsTable(r"x") .=> [ByRow(sum), ByRow(mean)]) + CSV.read(IOBuffer("a,b,c\n1,1.0,a"), DataFrame) end From 8d11b997d1d22f1eb6f470ce1f4bfd1b5305ee49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Mon, 6 Feb 2023 17:53:06 +0100 Subject: [PATCH 4/9] avoid dispatch ambiguity --- src/abstractdataframe/abstractdataframe.jl | 6 ++++++ test/dataframe.jl | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/src/abstractdataframe/abstractdataframe.jl b/src/abstractdataframe/abstractdataframe.jl index fe6fb842f5..5661e56e1a 100644 --- a/src/abstractdataframe/abstractdataframe.jl +++ b/src/abstractdataframe/abstractdataframe.jl @@ -1892,6 +1892,12 @@ function Base.reduce(::typeof(vcat), return res end +# definition needed to avoid dispatch ambiguity +Base.reduce(::typeof(vcat), + dfs::CSV.SentinelArrays.ChainedVector{T, A} where {T<:AbstractDataFrame, + A<:AbstractVector{T}}) = + reduce(vcat, collect(AbstractDataFrame, dfs)) + function _vcat(dfs::AbstractVector{AbstractDataFrame}; cols::Union{Symbol, AbstractVector{Symbol}, AbstractVector{<:AbstractString}}=:setequal) diff --git a/test/dataframe.jl b/test/dataframe.jl index d338aa2fed..6ffc758f8a 100644 --- a/test/dataframe.jl +++ b/test/dataframe.jl @@ -1892,6 +1892,11 @@ end DataFrame(c=[missing, missing])) end +@testset "vcat ChainedVector ambiguity" begin + dfs = DataFrames.CSV.SentinelArrays.ChainedVector([[DataFrame(a=1)], [DataFrame(a=2)]]) + @test reduce(vcat, dfs) == DataFrame(a=1:2) +end + @testset "names for Type, predicate + standard tests of cols" begin df_long = DataFrame(a1=1:3, a2=[1, missing, 3], b1=1.0:3.0, b2=[1.0, missing, 3.0], From 7e7a91cb25f104831b471b54b132eed30a29567e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Tue, 7 Feb 2023 12:54:10 +0100 Subject: [PATCH 5/9] add instructions how to disable precompilation --- docs/src/man/basics.md | 41 +++++++++++++++++++--- src/DataFrames.jl | 1 - src/abstractdataframe/abstractdataframe.jl | 6 ---- src/other/precompile.jl | 8 +++++ 4 files changed, 44 insertions(+), 12 deletions(-) diff --git a/docs/src/man/basics.md b/docs/src/man/basics.md index 300b503a90..105520cdea 100644 --- a/docs/src/man/basics.md +++ b/docs/src/man/basics.md @@ -16,7 +16,7 @@ or ```julia julia> ] # ']' should be pressed -(@v1.6) pkg> add DataFrames +(@v1.9) pkg> add DataFrames ``` If you want to make sure everything works as expected you can run the tests @@ -35,9 +35,9 @@ you have installed with the `status` command. ```julia julia> ] -(@v1.6) pkg> status DataFrames - Status `C:\Users\TeAmp0is0N\.julia\environments\v1.6\Project.toml` - [a93c6f00] DataFrames v1.1.1 +(@v1.9) pkg> status DataFrames + Status `~\v1.6\Project.toml` + [a93c6f00] DataFrames v1.5.0 ``` Throughout the rest of the tutorial we will assume that you have installed the @@ -52,6 +52,37 @@ The most fundamental type provided by DataFrames.jl is `DataFrame`, where typically each row is interpreted as an observation and each column as a feature. +!!! note + + DataFrames.jl uses precompilation to improve its responsiveness. However, + in some scenarios users might want to avoid precompilaion to improve + package installation time and load time. To disable precompilation of + DataFrames.jl in your current project you need to install the + [SnoopPrecompile.jl](https://github.com/timholy/SnoopCompile.jl/tree/master/SnoopPrecompile) + package and then run the following code: + ``` + using SnoopPrecompile + SnoopPrecompile.Preferences.set_preferences!(SnoopPrecompile, + "skip_precompile" => + union(SnoopPrecompile.Preferences.load_preference(SnoopPrecompile, + "skip_precompile", + String[]), + ["DataFrames"]); + force=true) + ``` + If you later would want to re-enable precompilation of DataFrames.jl you + can do it using the following commands: + ``` + using SnoopPrecompile + SnoopPrecompile.Preferences.set_preferences!(SnoopPrecompile, + "skip_precompile" => + filter(!=("DataFrames"), + SnoopPrecompile.Preferences.load_preference(SnoopPrecompile, + "skip_precompile", + String[])); + force=true) + ``` + ## Constructors and Basic Utility Functions ### Constructors @@ -1785,7 +1816,7 @@ in them: julia> select(german, Not(["Age", "Saving accounts", "Checking account", "Credit amount", "Purpose"])) 1000×5 DataFrame - Row │ id Sex Job Housing Duration + Row │ id Sex Job Housing Duration │ Int64 String7 Int64 String7 Int64 ──────┼────────────────────────────────────────── 1 │ 0 male 2 own 6 diff --git a/src/DataFrames.jl b/src/DataFrames.jl index bf8fe8ff9b..a2a652154a 100644 --- a/src/DataFrames.jl +++ b/src/DataFrames.jl @@ -11,7 +11,6 @@ using PrettyTables using Random using Tables: ByRow import SnoopPrecompile -import CSV import DataAPI, DataAPI.allcombinations, diff --git a/src/abstractdataframe/abstractdataframe.jl b/src/abstractdataframe/abstractdataframe.jl index 5661e56e1a..fe6fb842f5 100644 --- a/src/abstractdataframe/abstractdataframe.jl +++ b/src/abstractdataframe/abstractdataframe.jl @@ -1892,12 +1892,6 @@ function Base.reduce(::typeof(vcat), return res end -# definition needed to avoid dispatch ambiguity -Base.reduce(::typeof(vcat), - dfs::CSV.SentinelArrays.ChainedVector{T, A} where {T<:AbstractDataFrame, - A<:AbstractVector{T}}) = - reduce(vcat, collect(AbstractDataFrame, dfs)) - function _vcat(dfs::AbstractVector{AbstractDataFrame}; cols::Union{Symbol, AbstractVector{Symbol}, AbstractVector{<:AbstractString}}=:setequal) diff --git a/src/other/precompile.jl b/src/other/precompile.jl index f8b0c89cc8..b767caf085 100644 --- a/src/other/precompile.jl +++ b/src/other/precompile.jl @@ -1,6 +1,14 @@ import SnoopPrecompile SnoopPrecompile.@precompile_all_calls begin + import CSV + + # definition needed to avoid dispatch ambiguity + Base.reduce(::typeof(vcat), + dfs::CSV.SentinelArrays.ChainedVector{T, A} where {T<:AbstractDataFrame, + A<:AbstractVector{T}}) = + reduce(vcat, collect(AbstractDataFrame, dfs)) + df = DataFrame(a=[2, 5, 3, 1, 0], b=["a", "b", "c", "a", "b"], c=1:5, p=PooledArray(["a", "b", "c", "a", "b"]), q=[true, false, true, false, true], From 2bee3d52cbcd2187c60a858b867c819ed4eb9dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Tue, 7 Feb 2023 21:07:41 +0100 Subject: [PATCH 6/9] use only SentinelArrays and InlineStrings --- Project.toml | 5 +-- docs/src/man/basics.md | 41 ++++++++++++---------- src/DataFrames.jl | 2 ++ src/abstractdataframe/abstractdataframe.jl | 6 ++++ src/other/precompile.jl | 11 +----- 5 files changed, 34 insertions(+), 31 deletions(-) diff --git a/Project.toml b/Project.toml index 31773b0aba..cc56cb70b2 100644 --- a/Project.toml +++ b/Project.toml @@ -6,6 +6,7 @@ version = "1.5.0" Compat = "34da2185-b29b-5c13-b0c7-acf172513d20" DataAPI = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" Future = "9fa8497b-333b-5362-9e8d-4d0656e87820" +InlineStrings = "842dd82b-1e85-43dc-bf29-5d0ee9dffc48" InvertedIndices = "41ab1584-1d38-5bbf-9106-f11c6c58b48f" IteratorInterfaceExtensions = "82899510-4779-5014-852e-03e436cf321d" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" @@ -22,8 +23,8 @@ SortingAlgorithms = "a2af1166-a08f-5f64-846c-94a0d3cef48c" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" TableTraits = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" +SentinelArrays = "91c51154-3ec4-41a3-a24f-3f23e20d615c" Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" -CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" [compat] CategoricalArrays = "0.10.0" @@ -36,6 +37,7 @@ Missings = "0.4.2, 1" PooledArrays = "1.4.2" PrettyTables = "2.1" Reexport = "0.1, 0.2, 1" +SentinelArrays = "1.2" ShiftedArrays = "1, 2" SnoopPrecompile = "1" SortingAlgorithms = "0.1, 0.2, 0.3, 1" @@ -43,7 +45,6 @@ TableTraits = "0.4, 1" Tables = "1.9.0" Unitful = "1" julia = "1.6" -CSV = "0.10.9" [extras] CategoricalArrays = "324d7699-5711-5eae-9e2f-1d82baa6b597" diff --git a/docs/src/man/basics.md b/docs/src/man/basics.md index 105520cdea..ffca96d922 100644 --- a/docs/src/man/basics.md +++ b/docs/src/man/basics.md @@ -52,34 +52,37 @@ The most fundamental type provided by DataFrames.jl is `DataFrame`, where typically each row is interpreted as an observation and each column as a feature. -!!! note - - DataFrames.jl uses precompilation to improve its responsiveness. However, - in some scenarios users might want to avoid precompilaion to improve - package installation time and load time. To disable precompilation of - DataFrames.jl in your current project you need to install the +!!! note "Advanced installation configuration" + + **Advanced installation settings.** + DataFrames.jl puts in extra time and effort when the package is being built + (precompiled) to make sure it is more responsive when you are using it. + However, in some scenarios users might want to avoid this extra + precompilaion effort to reduce the time needed to build the package and + later to load it. To disable precompilation of DataFrames.jl in your current + project you need to install the [SnoopPrecompile.jl](https://github.com/timholy/SnoopCompile.jl/tree/master/SnoopPrecompile) - package and then run the following code: + and [Preferences.jl](https://github.com/JuliaPackaging/Preferences.jl) + packages and then run the following code: ``` - using SnoopPrecompile - SnoopPrecompile.Preferences.set_preferences!(SnoopPrecompile, - "skip_precompile" => - union(SnoopPrecompile.Preferences.load_preference(SnoopPrecompile, - "skip_precompile", - String[]), - ["DataFrames"]); + using SnoopPrecompile, Preferences + Preferences.set_preferences!(SnoopPrecompile, + "skip_precompile" => union(Preferences.load_preference(SnoopPrecompile, + "skip_precompile", + String[]), + ["DataFrames"]); force=true) ``` If you later would want to re-enable precompilation of DataFrames.jl you can do it using the following commands: ``` - using SnoopPrecompile - SnoopPrecompile.Preferences.set_preferences!(SnoopPrecompile, + using SnoopPrecompile, Preferences + Preferences.set_preferences!(SnoopPrecompile, "skip_precompile" => filter(!=("DataFrames"), - SnoopPrecompile.Preferences.load_preference(SnoopPrecompile, - "skip_precompile", - String[])); + Preferences.load_preference(SnoopPrecompile, + "skip_precompile", + String[])); force=true) ``` diff --git a/src/DataFrames.jl b/src/DataFrames.jl index a2a652154a..d32ffe99b9 100644 --- a/src/DataFrames.jl +++ b/src/DataFrames.jl @@ -11,6 +11,8 @@ using PrettyTables using Random using Tables: ByRow import SnoopPrecompile +import SentinelArrays +import InlineStrings import DataAPI, DataAPI.allcombinations, diff --git a/src/abstractdataframe/abstractdataframe.jl b/src/abstractdataframe/abstractdataframe.jl index fe6fb842f5..dc0237ddef 100644 --- a/src/abstractdataframe/abstractdataframe.jl +++ b/src/abstractdataframe/abstractdataframe.jl @@ -1892,6 +1892,12 @@ function Base.reduce(::typeof(vcat), return res end +# definition needed to avoid dispatch ambiguity +Base.reduce(::typeof(vcat), + dfs::SentinelArrays.ChainedVector{T, A} where {T<:AbstractDataFrame, + A<:AbstractVector{T}}) = + reduce(vcat, collect(AbstractDataFrame, dfs)) + function _vcat(dfs::AbstractVector{AbstractDataFrame}; cols::Union{Symbol, AbstractVector{Symbol}, AbstractVector{<:AbstractString}}=:setequal) diff --git a/src/other/precompile.jl b/src/other/precompile.jl index b767caf085..c8584adc84 100644 --- a/src/other/precompile.jl +++ b/src/other/precompile.jl @@ -1,14 +1,6 @@ import SnoopPrecompile SnoopPrecompile.@precompile_all_calls begin - import CSV - - # definition needed to avoid dispatch ambiguity - Base.reduce(::typeof(vcat), - dfs::CSV.SentinelArrays.ChainedVector{T, A} where {T<:AbstractDataFrame, - A<:AbstractVector{T}}) = - reduce(vcat, collect(AbstractDataFrame, dfs)) - df = DataFrame(a=[2, 5, 3, 1, 0], b=["a", "b", "c", "a", "b"], c=1:5, p=PooledArray(["a", "b", "c", "a", "b"]), q=[true, false, true, false, true], @@ -19,8 +11,8 @@ SnoopPrecompile.@precompile_all_calls begin combine(df, :c, [:c :f] .=> [sum, mean, std], :c => :d, [:a, :c] => cor) transform(df, :c, [:c :f] .=> [sum, mean, std], :c => :d, [:a, :c] => cor) groupby(df, :a) - groupby(df, :q) groupby(df, :p) + groupby(df, :q) gdf = groupby(df, :b) combine(gdf, :c, [:c :f] .=> [sum, mean, std], :c => :d, [:a, :c] => cor) transform(gdf, :c, [:c :f] .=> [sum, mean, std], :c => :d, [:a, :c] => cor) @@ -78,5 +70,4 @@ SnoopPrecompile.@precompile_all_calls begin df.id = repeat(1:2, 10) combine(df, AsTable(r"x") .=> [ByRow(sum), ByRow(mean)]) combine(groupby(df, :id), AsTable(r"x") .=> [ByRow(sum), ByRow(mean)]) - CSV.read(IOBuffer("a,b,c\n1,1.0,a"), DataFrame) end From eb717aab0cfec310a15344463363f15f12ee1786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Tue, 7 Feb 2023 22:13:30 +0100 Subject: [PATCH 7/9] fix test --- test/dataframe.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/dataframe.jl b/test/dataframe.jl index 6ffc758f8a..febfe4cd35 100644 --- a/test/dataframe.jl +++ b/test/dataframe.jl @@ -1893,7 +1893,7 @@ end end @testset "vcat ChainedVector ambiguity" begin - dfs = DataFrames.CSV.SentinelArrays.ChainedVector([[DataFrame(a=1)], [DataFrame(a=2)]]) + dfs = DataFrames.SentinelArrays.ChainedVector([[DataFrame(a=1)], [DataFrame(a=2)]]) @test reduce(vcat, dfs) == DataFrame(a=1:2) end From b2bed90d27ea1ed3592013ac723a4a0b5c8eeefa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Fri, 10 Feb 2023 22:57:12 +0100 Subject: [PATCH 8/9] Update src/abstractdataframe/abstractdataframe.jl Co-authored-by: Milan Bouchet-Valat --- src/abstractdataframe/abstractdataframe.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/abstractdataframe/abstractdataframe.jl b/src/abstractdataframe/abstractdataframe.jl index dc0237ddef..7b7779e813 100644 --- a/src/abstractdataframe/abstractdataframe.jl +++ b/src/abstractdataframe/abstractdataframe.jl @@ -1895,7 +1895,7 @@ end # definition needed to avoid dispatch ambiguity Base.reduce(::typeof(vcat), dfs::SentinelArrays.ChainedVector{T, A} where {T<:AbstractDataFrame, - A<:AbstractVector{T}}) = + A<:AbstractVector{T}}) = reduce(vcat, collect(AbstractDataFrame, dfs)) function _vcat(dfs::AbstractVector{AbstractDataFrame}; From 72bdb21cf9bed197e5a358827586d4f6e5c3ecdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogumi=C5=82=20Kami=C5=84ski?= Date: Sat, 11 Feb 2023 08:34:10 +0100 Subject: [PATCH 9/9] Update docs/src/man/basics.md Co-authored-by: Milan Bouchet-Valat --- docs/src/man/basics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/man/basics.md b/docs/src/man/basics.md index ffca96d922..20c1d2405e 100644 --- a/docs/src/man/basics.md +++ b/docs/src/man/basics.md @@ -61,7 +61,7 @@ feature. precompilaion effort to reduce the time needed to build the package and later to load it. To disable precompilation of DataFrames.jl in your current project you need to install the - [SnoopPrecompile.jl](https://github.com/timholy/SnoopCompile.jl/tree/master/SnoopPrecompile) + [SnoopPrecompile.jl](https://timholy.github.io/SnoopCompile.jl/stable/snoop_pc/) and [Preferences.jl](https://github.com/JuliaPackaging/Preferences.jl) packages and then run the following code: ```