Preferences: private API
PortfolioOptimisers.PREFERENCE_KEYS — Constant
PREFERENCE_KEYSThe Preferences.jl keys read at package load to seed the global config defaults (see apply_preferences!):
"equation_max_length"/"equation_max_depth": positive integers forEQUATION_LIMITS."max_n_sim"/"max_n_subsets"/"max_frontier"/"max_bins"/"max_hop_count"/"max_search_grid"/"max_ep_grid": positive integers forRESOURCE_LIMITS."suggestion_min_score": real number for theSTRING_DISTANCEthreshold."suggestion_distance": aPREFERENCE_DISTANCESname for theSTRING_DISTANCEmetric."compact_show": boolean or integer forCOMPACT_SHOW."show_nothing_fields": boolean for the global switch ofSHOW_NOTHING_FIELDS."show_nothing_fields_by_type": a table of booleans, one per type name, for the per-name entries ofSHOW_NOTHING_FIELDS.
Preferences.jl offers no way to enumerate the keys a project has set, so a misspelled key cannot be detected and is silently ignored (the shipped default applies) — misspelled or invalid values under these keys fail closed at load. A name inside the "show_nothing_fields_by_type" table that matches no type is a value the package cannot refuse either: a type outside the package can render through @define_pretty_show, so an unknown name is accepted and does nothing.
A valid value is applied, but a value that widens a guard is announced with a warning (see relaxed_preferences_msg): a preference file is data, it travels with a cloned project, and it applies before any user code runs.
Related
PortfolioOptimisers.PREFERENCE_DISTANCES — Constant
PREFERENCE_DISTANCESEnumerated allowlist mapping the names accepted by the "suggestion_distance" preference to their StringDistances.StringDistance objects. Membership and dispatch are one Dict — the same single-source-of-truth discipline as the equation parser's function allowlist (docs/adr/0025-enumerated-parser-allowlist.md): an unknown name fails closed at load with a typed error carrying a did_you_mean suggestion.
Supported names: "levenshtein", "damerau_levenshtein", "jaro", "jaro_winkler", "ratcliff_obershelp".
Related
PortfolioOptimisers.apply_preferences! — Function
apply_preferences!(prefs::AbstractDict{<:AbstractString})
Apply load-time preference values to the global config defaults (EQUATION_LIMITS, RESOURCE_LIMITS, STRING_DISTANCE, COMPACT_SHOW, SHOW_NOTHING_FIELDS). Called by the package __init__ with the PREFERENCE_KEYS values read via Preferences.load_preference; nothing values (unset preferences) are skipped and keep the shipped default.
Fails closed on an invalid value: it throws a typed ArgumentError naming the key and value, so the package refuses to load rather than silently running with a value the project got wrong. Values are applied through the set_*! setters, so they receive the same validation as runtime calls.
A valid value is applied whatever its size — the caps exist to turn an OOM kill into a typed error, not to second-guess a sizing choice, and a project on a large machine may legitimately raise one. A value that widens a guard is announced with a @warn built by relaxed_preferences_msg, because the channel needs no code: a LocalPreferences.toml is data, it travels with a cloned project, and it applies before any user code runs. Widening means a raised RESOURCE_LIMITS or EQUATION_LIMITS cap, or a lowered STRING_DISTANCE suggestion threshold. A value that tightens a guard, or that equals the default it replaces, is silent. The comparison is against the default in effect when the preference is applied, which at load is the shipped default. See the amendment of docs/adr/0041-one-resource-cap-per-sink.md.
To persist a configuration, put the keys in the active project's LocalPreferences.toml, e.g.:
[PortfolioOptimisers]
equation_max_length = 512
equation_max_depth = 64
max_n_sim = 50_000
max_n_subsets = 1_000
max_frontier = 1_000
max_bins = 500
max_hop_count = 100
max_search_grid = 10_000
max_ep_grid = 500
suggestion_min_score = 0.8
suggestion_distance = "damerau_levenshtein"
compact_show = 4
show_nothing_fields = true
[PortfolioOptimisers.show_nothing_fields_by_type]
SimpleVariance = falseAlgorithm
- Start
relaxationsempty. It collects one(key, default, value)triple per guard the preferences widen. - Read the two equation keys. When either is set, check that every set value is a positive integer, read the current
EQUATION_LIMITSdefault, record a triple for each value above its default, and apply both throughset_equation_limits!. A key the project left unset keeps the value it already has. - Read the seven resource keys and repeat step 2 against
RESOURCE_LIMITSandset_resource_limits!. - Read
"suggestion_min_score". When it is set, check that it is a real number, record a triple when it is below the current threshold, and apply it throughset_string_distance!. A lower threshold widens the guard, which is the opposite direction from a cap. - Read
"suggestion_distance". When it is set, check that it is a string, and look it up inPREFERENCE_DISTANCES. An unknown name raises, and the message carries adid_you_meansuggestion. Apply the resolved distance throughset_string_distance!. - Read
"compact_show". When it is set, check that it is a boolean or an integer, and apply it throughset_compact_show!. This key guards nothing, so it records no triple. - Hand
prefstoapply_show_preferences!, which reads"show_nothing_fields"and"show_nothing_fields_by_type". Neither key guards anything, so neither records a triple. - When
relaxationsis not empty, emit the text ofrelaxed_preferences_msgas a warning.
Arguments
prefs: One entry per key ofPREFERENCE_KEYS. Anothingvalue means the project set no preference for that key, and the shipped default stands.
Validation
- Each of the nine cap keys is a positive integer that is not a
Bool. "suggestion_min_score"is a real number that is not aBool."suggestion_distance"is a string, and it names an entry ofPREFERENCE_DISTANCES."compact_show"is aBoolor anInteger."show_nothing_fields"is aBool, and"show_nothing_fields_by_type"is a table ofBoolvalues, both checked byapply_show_preferences!.- A breach of any rule above raises an
ArgumentErrorthat names the key and the value, so the package refuses to load.
Returns
nothing.
Related
PortfolioOptimisers.apply_show_preferences! — Function
apply_show_preferences!(
prefs::AbstractDict{<:AbstractString}
)
Apply the two load-time preferences of SHOW_NOTHING_FIELDS: the global switch and the per-name table. Called by apply_preferences!, which owns the contract of the preference channel; nothing values (unset preferences) are skipped and keep the shipped default.
Fails closed on an invalid value, as apply_preferences! does: a typed ArgumentError names the key and the value. A name inside the table that matches no type is not refused; see PREFERENCE_KEYS.
Algorithm
- Read
"show_nothing_fields". When it is set, check that it is aBool, and apply it through the one-argument form ofset_show_nothing_fields!. - Read
"show_nothing_fields_by_type". When it is set, check that it is a table, then check that every value is aBool, and apply each entry through the per-name form ofset_show_nothing_fields!, with the key converted to aSymbol.
Arguments
prefs: The dictionary thatapply_preferences!receives. Only the two keys above are read.
Validation
"show_nothing_fields"is aBool."show_nothing_fields_by_type"is a dictionary, and every value in it is aBool.- A breach of either rule raises an
ArgumentErrorthat names the key and the value.
Returns
nothing.
Related
PortfolioOptimisers.__init__ — Function
__init__()Package load hook: reads the PREFERENCE_KEYS preferences of the active project via Preferences.load_preference and applies them to the global config defaults through apply_preferences!. An invalid preference value fails closed — the package refuses to load — rather than running with a value the project got wrong.
This is the one channel that reaches the guards without running code: a LocalPreferences.toml is data, it travels with a cloned project or a template, and it is read here, before any user code. A valid value is therefore applied but not silent — a value that widens a guard is announced with a warning (see relaxed_preferences_msg).
Algorithm
- Read every key of
PREFERENCE_KEYSwithPreferences.load_preference, givingnothingfor a key the active project did not set. - Pass the resulting dictionary to
apply_preferences!, which validates each value and applies it.
Returns
nothing.
Related
PortfolioOptimisers.relaxed_preferences_msg — Function
relaxed_preferences_msg(
relaxations::AbstractVector
) -> String
Build the warning text for the load-time preferences that widened a guard (see apply_preferences!). One line per key: the key, the default it replaced, and the value the project asked for.
A preference file is data. It ships with a cloned project or a template, it is often untracked, and __init__ applies it at using PortfolioOptimisers, before any user code runs. A value that tightens a guard needs no announcement, so the warning names the widened guards alone: the RESOURCE_LIMITS and EQUATION_LIMITS caps a file raised, and a STRING_DISTANCE suggestion threshold it lowered (a lower threshold admits more candidates, which is the info-leak direction of docs/adr/0026-lenient-constraint-names-with-suggestions.md).
Never interpolates the whole preference dictionary, so a key the message does not name stays out of the log — the same info-leak-safe message discipline as unknown_variable_msg.
Algorithm
- Open
msgwith the number of widened guards and the sentence that says when a preference applies. - Append one line per triple, naming the key, the default it replaced, and the value the project asked for.
- Close
msgwith the two repairs: delete the key, or widen the guard for one scope with awith_*helper.
Arguments
relaxations: One(key, default, value)triple per widened guard, inPREFERENCE_KEYSorder.
Returns
msg::String: Multi-line warning text, one line per triple.
Related