From ad715ff60c7962f82c10492389a387ee13c92960 Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Mon, 27 Oct 2025 15:52:06 +0100 Subject: [PATCH 01/23] Implement inheritance of field names for structures based on supertypes: - utils function necessary for inheritance - changes to update_descriptive_names! to add inheritance step - Changes to descriptive_names.yml; removing redundant descriptive names and adding descriptive names to supertypes. --- src/descriptive_names.yml | 140 +++----------------- src/utils_GUI/GUI_utils.jl | 8 +- src/utils_gen/utils.jl | 260 +++++++++++++++++++++++++++++++++++++ 3 files changed, 287 insertions(+), 121 deletions(-) diff --git a/src/descriptive_names.yml b/src/descriptive_names.yml index 02b0075..5422d89 100644 --- a/src/descriptive_names.yml +++ b/src/descriptive_names.yml @@ -3,36 +3,17 @@ structures: # EnergyModelsBase ## node.jl - StorCapOpex: + AbstractStorageParameters: capacity: "Installed capacity" opex_var: "Relative variable operating expense per energy unit" opex_fixed: "Relative fixed operating expense per installed capacity" - StorCap: - capacity: "Installed capacity" - - StorCapOpexVar: - capacity: "Installed capacity" - opex_var: "Relative variable operating expense per energy unit" - - StorCapOpexFixed: - capacity: "Installed capacity" - opex_fixed: "Relative fixed operating expense per installed capacity" - - StorOpexVar: - opex_var: "Relative variable operating expense per energy unit" - - RefSource: + Node: cap: "Installed capacity" opex_var: "Relative variable operating expense per energy unit produced" opex_fixed: "Relative fixed operating expense per installed capacity" - RefNetworkNode: - cap: "Installed capacity" - opex_var: "Relative variable operating expense per energy unit produced" - opex_fixed: "Relative fixed operating expense per installed capacity" - - RefSink: + Sink: cap: "Demand" penalty: surplus: "Penalties for surplus" @@ -40,90 +21,43 @@ structures: # EnergyModelsGeography ## mode.jl - RefDynamic: - trans_cap: "Capacity of the transmission mode" - trans_loss: "Relative loss of the transported resource during transmission" - opex_var: "Relative variable operating expense per energy unit transported" - opex_fixed: "Relative fixed operating expense per installed capacity" - - RefStatic: - trans_cap: "Capacity of the transmission mode" - trans_loss: "Relative loss of the transported resource during transmission" - opex_var: "Relative variable operating expense per energy unit transported" - opex_fixed: "Relative fixed operating expense per installed capacity" - - PipeSimple: - consumption_rate: "Rate at which the resource is consumed, as a ratio of the volume of the resource going into the inlet" + TransmissionMode: trans_cap: "Capacity of the transmission mode" trans_loss: "Relative loss of the transported resource during transmission" opex_var: "Relative variable operating expense per energy unit transported" opex_fixed: "Relative fixed operating expense per installed capacity" - - PipeLinepackSimple: consumption_rate: "Rate at which the resource is consumed, as a ratio of the volume of the resource going into the inlet" - trans_cap: "Capacity of the transmission mode" - trans_loss: "Relative loss of the transported resource during transmission" - opex_var: "Relative variable operating expense per energy unit transported" - opex_fixed: "Relative fixed operating expense per installed capacity" + trans_loss: "Relative loss of the transported resource during transmission" # EnergyModelsInvestment ## investment_data.jl - NoStartInvData: - capex: "Capital costs for investing in a capacity" - max_inst: "Maximum installed capacity in a strategic period" - - StartInvData: + AbstractInvData: capex: "Capital costs for investing in a capacity" max_inst: "Maximum installed capacity in a strategic period" initial: "Initial capacity in the first strategic period" ## investment_mode.jl + Investment: + min_add: "Minimum added capacity in a strategic period" + max_add: "Maximum added capacity in a strategic period" + increment: "Used increment for discrete investments" + capex_offset: "Offset for the CAPEX in a strategic period" FixedInvestment: cap: "Capacity used for the fixed investments" BinaryInvestment: cap: "Capacity used for the binary investments" - DiscreteInvestment: - increment: "Used increment for discrete investments" - - ContinuousInvestment: - min_add: "Minimum added capacity in a strategic period" - max_add: "Maximum added capacity in a strategic period" - - SemiContinuousInvestment: - min_add: "Minimum added capacity in a strategic period" - max_add: "Maximum added capacity in a strategic period" - - SemiContinuousOffsetInvestment: - max_add: "Maximum added capacity in a strategic period" - min_add: "Minimum added capacity in a strategic period" - capex_offset: "Offset for the CAPEX in a strategic period" - ## lifetime_mode.jl - StudyLife: - lifetime: "Chosen lifetime of the technology" - - PeriodLife: - lifetime: "Chosen lifetime of the technology" - - RollingLife: + LifetimeMode: lifetime: "Chosen lifetime of the technology" # EnergyModelsRenewableProducers ## datastructures.jl - NonDisRES: - cap: "Installed capacity" + AbstractNonDisRES: profile: "Power production profile as a ratio of installed capacity" - opex_var: "Relative variable operating expense per energy unit produced" - opex_fixed: "Relative fixed operating expense per installed capacity" - HydroStor: - level_init: "Initial stored energy in the dam" - level_inflow: "Inflow of power per operational period" - level_min: "Minimum fraction of the reservoir capacity required" - - PumpedHydroStor: + HydroStorage: level_init: "Initial stored energy in the dam" level_inflow: "Inflow of power per operational period" level_min: "Minimum fraction of the reservoir capacity required" @@ -141,15 +75,15 @@ structures: opex_var: "Variable operational costs per water flow" opex_fixed: "Fixed operational costs" - HydroGenerator: - cap: "Installed discharge or power capacity" + HydroUnit: opex_var: "Variable operational costs per energy unit produced" opex_fixed: "Fixed operational costs" + HydroGenerator: + cap: "Installed discharge or power capacity" + HydroPump: cap: "Installed pumping capacity" - opex_var: "Variable operational costs per energy unit produced" - opex_fixed: "Fixed operational costs" CycleLife: stack_cost: "Relative cost for replacing a battery stack" @@ -162,22 +96,9 @@ structures: ## node.jl HeatPump: - cap: "Installed capacity" t_source: "Heat source temperature" t_sink: "Heat sink temperature" eff_carnot: "Carnot Efficiency" - opex_var: "Variable operating expense per energy unit produced" - opex_fixed: "Fixed operating expense per installed capacity" - - HeatExchanger: - cap: "Installed capacity" - opex_var: "Variable operating expense per energy unit produced" - opex_fixed: "Fixed operating expense per installed capacity" - - DirectHeatUpgrade: - cap: "Installed capacity" - opex_var: "Variable operating expense per energy unit produced" - opex_fixed: "Fixed operating expense per installed capacity" ## resource.jl ResourceHeat: @@ -186,52 +107,31 @@ structures: # EnergyModelsHydrogen ## node.jl - Electrolyzer: - cap: "Installed capacity" + AbstractElectrolyzer: opex_var: "Variable operating expense per capacity used" - opex_fixed: "Fixed operating expense per installed capacity" - stack_replacement_cost: "Replacement cost of electrolyzer stacks" - - SimpleElectrolyzer: - cap: "Installed capacity" - opex_var: "Variable operating expense per capacity used" - opex_fixed: "Fixed operating expense per installed capacity" stack_replacement_cost: "Replacement cost of electrolyzer stacks" CommitParameters: opex: "Operating cost per installed capacity and operational duration" time: "Minimum time node must remain in a state before transitioning" - RampBi: + AbstractRampParameters: up: "Maximum positive rate of change of a node" down: "Maximum negative rate of change of a node" - RampUp: - up: "Maximum positive rate of change of a node" - - RampDown: - down: "Maximum negative rate of change of a node" - Reformer: - cap: "Installed capacity" opex_var: "Variable operating expense per capacity usage" opex_fixed: "Fixed operating expense per installed capacity" # EnergyModelsCO2 CO2Source: - cap: "Installed capacity" opex_var: "Variable operating expense per energy unit produced" - opex_fixed: "Fixed operating expense" RefNetworkNodeRetrofit: - cap: "Installed capacity" opex_var: "Variable operating expense per energy unit produced" - opex_fixed: "Fixed operating expense" CCSRetroFit: - cap: "Installed capacity" opex_var: "Variable operating expense per unit of CO₂ captured" - opex_fixed: "Fixed operating expense" variables: diff --git a/src/utils_GUI/GUI_utils.jl b/src/utils_GUI/GUI_utils.jl index 679b670..7d0b441 100644 --- a/src/utils_GUI/GUI_utils.jl +++ b/src/utils_GUI/GUI_utils.jl @@ -631,10 +631,16 @@ function update_descriptive_names!(gui::GUI) # Filter packages with names matching the pattern "EnergyModels*" emx_packages = filter(pkg -> occursin(r"EnergyModels", pkg), keys(installed_packages)) - # Search through EMX packages if icons are available there + # apply inheritances for fetching descriptive names + # create a dictionary were the keys are all the types defined in emx_packages and the values are the types they inherit from + emx_supertypes_dict = get_supertypes(emx_packages) + + inherit_descriptive_names_from_supertypes!(descriptive_names, emx_supertypes_dict) + for package ∈ emx_packages package_path::Union{String,Nothing} = dirname(dirname(Base.find_package(package))) if !isnothing(package_path) + # check for presence of file to extend descriptive names path_to_descriptive_names_ext = joinpath( package_path, "ext", "EMGUIExt", "descriptive_names.yml", ) diff --git a/src/utils_gen/utils.jl b/src/utils_gen/utils.jl index 80557b3..56da611 100644 --- a/src/utils_gen/utils.jl +++ b/src/utils_gen/utils.jl @@ -270,3 +270,263 @@ function save_results(model::Model; directory = joinpath(pwd(), "csv_files")) YAML.write(io, metadata) end end + +""" + get_types(input) -> Vector{Symbol} + +Retrieves the names of all defined types from modules or packages. + +# Method Overloads + +- `get_types(modul::Module)`: + Returns a vector of type names defined in the given module. + +- `get_types(moduls::Vector{Module})`: + Returns a combined vector of type names from multiple modules. + +- `get_types(pkg::Union{String, Symbol})`: + Converts the package name to a module (via `Main`) and returns its defined types. + +- `get_types(pkgs::Union{Vector{<:Union{String, Symbol}}, Set{<:Union{String, Symbol}}})`: + Returns a combined vector of type names from multiple packages. + +# Arguments +- `input`: Can be a single module, a vector of modules, a single package name (as `String` or `Symbol`), or a collection of package names. + +# Returns +- `Vector{Symbol}`: A list of names corresponding to types defined in the given module(s) or package(s). + +# Description +This set of functions helps extract type definitions from Julia modules or packages. It filters out non-type bindings and collects only those that are instances of `DataType`. + +# Example +```julia +get_types(Base) # returns type names defined in Base + +get_types(["Base", "Core"]) # returns type names from both packages +``` +""" +function get_types(modul::Module) + types = [] + for name in names(modul) + if isdefined(modul, name) && getfield(modul, name) isa DataType + push!(types, name) + end + end + return types +end + +function get_types(moduls::Vector{Module}) + types=[] + for modul in moduls + append!(types, get_types(modul)) + end + return types +end + +function get_types(pkg::Union{String,Symbol}) + return get_types(getfield(Main, Symbol(pkg))) +end + +function get_types(pkgs::Union{Vector{<:Union{String,Symbol}}, Set{<:Union{String,Symbol}}}) + types = [] + for pkg in pkgs + append!(types, get_types(pkg)) + end + return types +end + +""" + get_supertypes(input) -> Dict{Symbol, Vector{Type}} + +Retrieves the supertypes of all defined types from modules or packages. + +# Method Overloads + +- `get_supertypes(modul::Module)`: + Returns a dictionary mapping type names to their supertypes from the given module. + +- `get_supertypes(moduls::Vector{Module})`: + Merges and returns supertypes from multiple modules. + +- `get_supertypes(pkg::Union{String, Symbol})`: + Converts the package name to a module (via `Main`) and returns its type supertypes. + +- `get_supertypes(pkgs::Union{Vector{<:Union{String, Symbol}}, Set{<:Union{String, Symbol}}})`: + Merges and returns supertypes from multiple packages via their names. + +# Arguments +- `input`: Can be a single module, a vector of modules, a single package name (as `String` or `Symbol`), or a collection of package names. + +# Returns +- `Dict{Symbol, Vector{Type}}`: A dictionary where each key is a type name and the value is a vector of its supertypes. + +# Description +This set of functions helps extract the inheritance hierarchy of types defined in Julia modules or packages. It filters out non-type bindings and collects supertypes using `supertypes`. + +""" +function get_supertypes(modul::Module) + types=Dict() + for name in names(modul) + if isdefined(modul, name) && getfield(modul, name) isa DataType + types[name] = supertypes(getfield(modul, name)) + end + end + return types +end + +function get_supertypes(moduls::Vector{Module}) + types=Dict() + for modul in moduls + merge!(types, get_supertypes(modul)) + end + return types +end + +function get_supertypes(pkg::Union{String,Symbol}) + return get_supertypes(getfield(Main, Symbol(pkg))) +end + +function get_supertypes(pkgs::Union{Vector{<:Union{String,Symbol}}, Set{<:Union{String,Symbol}}}) + types = Dict() + for pkg in pkgs + merge!(types, get_supertypes(pkg)) + end + return types +end + +""" + has_fields(type::Type) -> Bool + +Checks whether a given type is a concrete struct with at least one field. + +# Arguments +- `type::Type`: The type to be inspected. + +# Returns +- `Bool`: Returns `true` if the type is a concrete struct and has one or more fields; otherwise, returns `false`. + +# Description +This function combines three checks: +- `isconcretetype(type)`: Ensures the type is concrete (i.e., can be instantiated). +- `isstructtype(type)`: Ensures the type is a struct. +- `nfields(type) > 0`: Ensures the struct has at least one field. + +# Example +```julia +struct MyStruct + x::Int +end + +has_fields(MyStruct) # returns true + +abstract type AbstractType end +has_fields(AbstractType) # returns false +``` +""" +function has_fields(type) + return (isconcretetype(type) && isstructtype(type) && nfields(type) > 0) +end + +""" + update_tree!(current_lvl::Dict{Type, Union{Dict, Nothing}}, tmp_type::Type) -> Nothing + +Ensures that a given type exists as a key in the current level of a nested type dependency dictionary. + +# Arguments +- `current_lvl::Dict{Type, Union{Dict, Nothing}}`: The current level of the nested dictionary structure representing type dependencies. +- `tmp_type::Type`: The type to be added as a key in the current level if it does not already exist. + +# Behavior +If `tmp_type` is not already a key in `current_lvl`, it adds it with an empty dictionary as its value, preparing for further nesting. + +# Returns +- `Nothing`: This function modifies `current_lvl` in-place and does not return a value. + +""" +function update_tree!(current_lvl, tmp_type::Type) + if !haskey(current_lvl, tmp_type) + current_lvl[tmp_type] = Dict{Type, Union{Dict, Nothing}}() + end + return +end + + +""" + get_types_structure(emx_supertypes_dict::Dict{Any, Vector{Type}}) -> Dict{Type, Union{Dict, Nothing}} + +Constructs a nested dictionary representing type dependencies from a dictionary of supertypes. + +# Arguments +- `emx_supertypes_dict::Dict{Any, Vector{Type}}`: A dictionary where each key corresponds to a type identifier, and the value is a vector of supertypes ordered from the most general to the most specific. + +# Returns +- `Dict{Type, Union{Dict, Nothing}}`: A nested dictionary structure where each type is a key pointing to its subtype hierarchy. Leaf nodes point to `nothing`. + +# Description +This function builds a tree-like structure of type dependencies by iterating through each type's supertypes and nesting them accordingly. It uses the helper function `update_tree!` to insert types into the correct level of the hierarchy. +``` +""" +function get_types_structure(emx_supertypes_dict) + # make a visualization of the type dependencies by building a nested dictionary of types + emx_type_dependencies = Dict{Type, Union{Dict, Nothing}}() + for (emx_type_id, emx_supertypes) in emx_supertypes_dict + i = 0 + current_lvl = emx_type_dependencies + while i < length(emx_supertypes) + tmp_type = emx_supertypes[end-i] + update_tree!(current_lvl,tmp_type) + current_lvl = current_lvl[tmp_type] + i+=1 + end + end + return emx_type_dependencies +end + +""" + inherit_descriptive_names_from_supertypes!(descriptive_names, emx_supertypes_dict) + +Copies descriptive field names from supertypes to subtypes in the `descriptive_names` dictionary. + +# Arguments +- `descriptive_names::Dict`: A dictionary containing descriptive names for structure fields, + organized by type. +- `emx_supertypes_dict::Dict`: A dictionary mapping type identifiers to arrays of types, + where the first element is the type itself and the remaining elements are its supertypes. + +# Description +For each type in `emx_supertypes_dict`, this function checks if the type has fields. +For each field, it looks for descriptive names in the supertypes. +If a descriptive name exists for a field in a supertype but not in the subtype, + it copies the descriptive name from the supertype to the subtype. + +# Modifies +- Updates `descriptive_names` in-place by inheriting missing descriptive names from supertypes. +""" +function inherit_descriptive_names_from_supertypes!(descriptive_names, emx_supertypes_dict) + for (emx_type_id, emx_supertypes) in emx_supertypes_dict + emx_type = emx_supertypes[1] + # check if emx_type has field names and if so retrieve them, otherwise continue + if !has_fields(emx_type) + continue + end + emx_type_fieldnames = fieldnames(emx_type) + for fname in emx_type_fieldnames + for emx_supertype in emx_supertypes[2:end] # skip first element as it is the type itself + #check if the supertype has an entry in descriptive names for fname + if haskey(descriptive_names[:structures], Symbol(emx_supertype)) && + haskey(descriptive_names[:structures][Symbol(emx_supertype)], Symbol(fname)) + # if so, and if the emx_type does not have an entry for fname, copy it + if !haskey(descriptive_names[:structures], Symbol(emx_type)) || + !haskey(descriptive_names[:structures][Symbol(emx_type)], Symbol(fname)) + if !haskey(descriptive_names[:structures], Symbol(emx_type)) + descriptive_names[:structures][Symbol(emx_type)] = Dict{Symbol,Any}() + end + descriptive_names[:structures][Symbol(emx_type)][Symbol(fname)] = + descriptive_names[:structures][Symbol(emx_supertype)][Symbol(fname)] + end + end + end + end + end +end From 43070ac5cfabdaca3215d162e907055d90beb461 Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Tue, 4 Nov 2025 13:22:18 +0100 Subject: [PATCH 02/23] Julia formatter --- src/utils_gen/utils.jl | 50 +++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/src/utils_gen/utils.jl b/src/utils_gen/utils.jl index 56da611..b4e2bd2 100644 --- a/src/utils_gen/utils.jl +++ b/src/utils_gen/utils.jl @@ -308,7 +308,7 @@ get_types(["Base", "Core"]) # returns type names from both packages """ function get_types(modul::Module) types = [] - for name in names(modul) + for name ∈ names(modul) if isdefined(modul, name) && getfield(modul, name) isa DataType push!(types, name) end @@ -318,7 +318,7 @@ end function get_types(moduls::Vector{Module}) types=[] - for modul in moduls + for modul ∈ moduls append!(types, get_types(modul)) end return types @@ -328,9 +328,9 @@ function get_types(pkg::Union{String,Symbol}) return get_types(getfield(Main, Symbol(pkg))) end -function get_types(pkgs::Union{Vector{<:Union{String,Symbol}}, Set{<:Union{String,Symbol}}}) +function get_types(pkgs::Union{Vector{<:Union{String,Symbol}},Set{<:Union{String,Symbol}}}) types = [] - for pkg in pkgs + for pkg ∈ pkgs append!(types, get_types(pkg)) end return types @@ -367,7 +367,7 @@ This set of functions helps extract the inheritance hierarchy of types defined i """ function get_supertypes(modul::Module) types=Dict() - for name in names(modul) + for name ∈ names(modul) if isdefined(modul, name) && getfield(modul, name) isa DataType types[name] = supertypes(getfield(modul, name)) end @@ -377,7 +377,7 @@ end function get_supertypes(moduls::Vector{Module}) types=Dict() - for modul in moduls + for modul ∈ moduls merge!(types, get_supertypes(modul)) end return types @@ -387,9 +387,11 @@ function get_supertypes(pkg::Union{String,Symbol}) return get_supertypes(getfield(Main, Symbol(pkg))) end -function get_supertypes(pkgs::Union{Vector{<:Union{String,Symbol}}, Set{<:Union{String,Symbol}}}) +function get_supertypes( + pkgs::Union{Vector{<:Union{String,Symbol}},Set{<:Union{String,Symbol}}}, +) types = Dict() - for pkg in pkgs + for pkg ∈ pkgs merge!(types, get_supertypes(pkg)) end return types @@ -446,12 +448,11 @@ If `tmp_type` is not already a key in `current_lvl`, it adds it with an empty di """ function update_tree!(current_lvl, tmp_type::Type) if !haskey(current_lvl, tmp_type) - current_lvl[tmp_type] = Dict{Type, Union{Dict, Nothing}}() + current_lvl[tmp_type] = Dict{Type,Union{Dict,Nothing}}() end return end - """ get_types_structure(emx_supertypes_dict::Dict{Any, Vector{Type}}) -> Dict{Type, Union{Dict, Nothing}} @@ -469,13 +470,13 @@ This function builds a tree-like structure of type dependencies by iterating thr """ function get_types_structure(emx_supertypes_dict) # make a visualization of the type dependencies by building a nested dictionary of types - emx_type_dependencies = Dict{Type, Union{Dict, Nothing}}() - for (emx_type_id, emx_supertypes) in emx_supertypes_dict + emx_type_dependencies = Dict{Type,Union{Dict,Nothing}}() + for (emx_type_id, emx_supertypes) ∈ emx_supertypes_dict i = 0 current_lvl = emx_type_dependencies while i < length(emx_supertypes) tmp_type = emx_supertypes[end-i] - update_tree!(current_lvl,tmp_type) + update_tree!(current_lvl, tmp_type) current_lvl = current_lvl[tmp_type] i+=1 end @@ -504,26 +505,35 @@ If a descriptive name exists for a field in a supertype but not in the subtype, - Updates `descriptive_names` in-place by inheriting missing descriptive names from supertypes. """ function inherit_descriptive_names_from_supertypes!(descriptive_names, emx_supertypes_dict) - for (emx_type_id, emx_supertypes) in emx_supertypes_dict + for (emx_type_id, emx_supertypes) ∈ emx_supertypes_dict emx_type = emx_supertypes[1] # check if emx_type has field names and if so retrieve them, otherwise continue if !has_fields(emx_type) continue end emx_type_fieldnames = fieldnames(emx_type) - for fname in emx_type_fieldnames - for emx_supertype in emx_supertypes[2:end] # skip first element as it is the type itself + for fname ∈ emx_type_fieldnames + for emx_supertype ∈ emx_supertypes[2:end] # skip first element as it is the type itself #check if the supertype has an entry in descriptive names for fname if haskey(descriptive_names[:structures], Symbol(emx_supertype)) && - haskey(descriptive_names[:structures][Symbol(emx_supertype)], Symbol(fname)) + haskey( + descriptive_names[:structures][Symbol(emx_supertype)], + Symbol(fname), + ) # if so, and if the emx_type does not have an entry for fname, copy it if !haskey(descriptive_names[:structures], Symbol(emx_type)) || - !haskey(descriptive_names[:structures][Symbol(emx_type)], Symbol(fname)) + !haskey( + descriptive_names[:structures][Symbol(emx_type)], + Symbol(fname), + ) if !haskey(descriptive_names[:structures], Symbol(emx_type)) - descriptive_names[:structures][Symbol(emx_type)] = Dict{Symbol,Any}() + descriptive_names[:structures][Symbol(emx_type)] = + Dict{Symbol,Any}() end descriptive_names[:structures][Symbol(emx_type)][Symbol(fname)] = - descriptive_names[:structures][Symbol(emx_supertype)][Symbol(fname)] + descriptive_names[:structures][Symbol(emx_supertype)][Symbol( + fname, + )] end end end From 0ac130fa983fe3ce84b741f24ce1cdcf2d882b8b Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Wed, 5 Nov 2025 13:07:04 +0100 Subject: [PATCH 03/23] Add InteractiveUtils to Project.toml --- Project.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Project.toml b/Project.toml index 4971895..b36ad9d 100644 --- a/Project.toml +++ b/Project.toml @@ -26,6 +26,7 @@ SparseVariables = "2749762c-80ed-4b14-8f33-f0736679b02b" TimeStruct = "f9ed5ce0-9f41-4eaa-96da-f38ab8df101c" XLSX = "fdbf4ff8-1666-58a4-91e7-1b58723a45e0" YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6" +InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" [weakdeps] EnergyModelsGeography = "3f775d88-a4da-46c4-a2cc-aa9f16db6708" @@ -58,3 +59,4 @@ TimeStruct = "0.9" XLSX = "0.10" YAML = "0.4" julia = "1.10" +InteractiveUtils = "1" From abe0e62d13aea5f38692f9f43b97f0df5e910e7f Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Wed, 5 Nov 2025 13:07:24 +0100 Subject: [PATCH 04/23] Add InteractiveUtils to package --- src/EnergyModelsGUI.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/EnergyModelsGUI.jl b/src/EnergyModelsGUI.jl index 6c47c4c..8aa66ee 100644 --- a/src/EnergyModelsGUI.jl +++ b/src/EnergyModelsGUI.jl @@ -23,6 +23,9 @@ using Colors # To format numbers with @sprintf using Printf +# To retrieve supertypes +using InteractiveUtils + # Use GLMakie front end to visualize the GUI figure using GLMakie From 0bd069d2ea738edbf8c7dc0eda30481814bb6dcb Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Wed, 5 Nov 2025 13:07:39 +0100 Subject: [PATCH 05/23] remove duplicate entry in descriptive names --- src/descriptive_names.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/descriptive_names.yml b/src/descriptive_names.yml index 5422d89..b1fbdd0 100644 --- a/src/descriptive_names.yml +++ b/src/descriptive_names.yml @@ -27,7 +27,6 @@ structures: opex_var: "Relative variable operating expense per energy unit transported" opex_fixed: "Relative fixed operating expense per installed capacity" consumption_rate: "Rate at which the resource is consumed, as a ratio of the volume of the resource going into the inlet" - trans_loss: "Relative loss of the transported resource during transmission" # EnergyModelsInvestment ## investment_data.jl From 698e3b85dd071c554287c035efc9ee96aba01a10 Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Wed, 5 Nov 2025 13:08:02 +0100 Subject: [PATCH 06/23] Add initial test of inheritance of descriptive names --- test/test_interactivity.jl | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/test_interactivity.jl b/test/test_interactivity.jl index 7d1b38b..085f271 100644 --- a/test/test_interactivity.jl +++ b/test/test_interactivity.jl @@ -92,6 +92,26 @@ pin_plot_button = get_button(gui, :pin_plot) @test descriptive_names[:variables][:trans_cap_rem] == str6 EMGUI.close(gui2) end + + @testset "Test inheritance of descriptive names" begin + path_to_descriptive_names = joinpath(pkgdir(EMGUI), "src", "descriptive_names.yml") + descriptive_names_raw = + YAML.load_file(path_to_descriptive_names; dicttype = Dict{Symbol,Any}) + str1 = "Relative fixed operating expense per installed capacity" + gui2 = GUI( + case; + path_to_descriptive_names = path_to_descriptive_names, + ) + @test descriptive_names_raw[:structures][:Node][:opex_fixed] == str1 + @test :StorCapOpexFixed ∉ keys(descriptive_names_raw[:structures]) + @test :RefNetworkNode ∉ keys(descriptive_names_raw[:structures]) + + descriptive_names = EMGUI.get_var(gui2, :descriptive_names) + @test :Node ∉ keys(descriptive_names[:structures]) + @test descriptive_names[:structures][:StorCapOpexFixed][:opex_fixed] == str1 + @test descriptive_names[:structures][:RefNetworkNode][:opex_fixed] == str1 + EMGUI.close(gui2) + end end # Test specific GUI functionalities From 9aeb855763bcdb47237d8730611258e43c64b5c1 Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Wed, 5 Nov 2025 23:04:52 +0100 Subject: [PATCH 07/23] fix tests and processing of supertypes --- src/utils_GUI/GUI_utils.jl | 2 -- src/utils_gen/utils.jl | 11 ++++++++--- test/test_interactivity.jl | 1 - 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/utils_GUI/GUI_utils.jl b/src/utils_GUI/GUI_utils.jl index 7d0b441..7a4ffd4 100644 --- a/src/utils_GUI/GUI_utils.jl +++ b/src/utils_GUI/GUI_utils.jl @@ -634,9 +634,7 @@ function update_descriptive_names!(gui::GUI) # apply inheritances for fetching descriptive names # create a dictionary were the keys are all the types defined in emx_packages and the values are the types they inherit from emx_supertypes_dict = get_supertypes(emx_packages) - inherit_descriptive_names_from_supertypes!(descriptive_names, emx_supertypes_dict) - for package ∈ emx_packages package_path::Union{String,Nothing} = dirname(dirname(Base.find_package(package))) if !isnothing(package_path) diff --git a/src/utils_gen/utils.jl b/src/utils_gen/utils.jl index b4e2bd2..d5dcd7c 100644 --- a/src/utils_gen/utils.jl +++ b/src/utils_gen/utils.jl @@ -515,9 +515,14 @@ function inherit_descriptive_names_from_supertypes!(descriptive_names, emx_super for fname ∈ emx_type_fieldnames for emx_supertype ∈ emx_supertypes[2:end] # skip first element as it is the type itself #check if the supertype has an entry in descriptive names for fname - if haskey(descriptive_names[:structures], Symbol(emx_supertype)) && + # Extract only what is after the dot in emx_supertype, if any + supertype_str = string(emx_supertype) + supertype_key = + occursin(r"\.", supertype_str) ? + match(r"\.([^.]+)$", supertype_str).captures[1] : supertype_str + if haskey(descriptive_names[:structures], Symbol(supertype_key)) && haskey( - descriptive_names[:structures][Symbol(emx_supertype)], + descriptive_names[:structures][Symbol(supertype_key)], Symbol(fname), ) # if so, and if the emx_type does not have an entry for fname, copy it @@ -531,7 +536,7 @@ function inherit_descriptive_names_from_supertypes!(descriptive_names, emx_super Dict{Symbol,Any}() end descriptive_names[:structures][Symbol(emx_type)][Symbol(fname)] = - descriptive_names[:structures][Symbol(emx_supertype)][Symbol( + descriptive_names[:structures][Symbol(supertype_key)][Symbol( fname, )] end diff --git a/test/test_interactivity.jl b/test/test_interactivity.jl index 085f271..c882ddd 100644 --- a/test/test_interactivity.jl +++ b/test/test_interactivity.jl @@ -107,7 +107,6 @@ pin_plot_button = get_button(gui, :pin_plot) @test :RefNetworkNode ∉ keys(descriptive_names_raw[:structures]) descriptive_names = EMGUI.get_var(gui2, :descriptive_names) - @test :Node ∉ keys(descriptive_names[:structures]) @test descriptive_names[:structures][:StorCapOpexFixed][:opex_fixed] == str1 @test descriptive_names[:structures][:RefNetworkNode][:opex_fixed] == str1 EMGUI.close(gui2) From 8efcc4b3701adf54d623333d5e02025b5bbb48a3 Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Thu, 6 Nov 2025 15:30:47 +0100 Subject: [PATCH 08/23] Fix feature for parametric structs that have type UnionAll and added tests --- src/utils_gen/utils.jl | 18 ++++++++++++++---- test/test_interactivity.jl | 14 +++++++++++--- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/utils_gen/utils.jl b/src/utils_gen/utils.jl index d5dcd7c..e70d378 100644 --- a/src/utils_gen/utils.jl +++ b/src/utils_gen/utils.jl @@ -309,7 +309,12 @@ get_types(["Base", "Core"]) # returns type names from both packages function get_types(modul::Module) types = [] for name ∈ names(modul) - if isdefined(modul, name) && getfield(modul, name) isa DataType + if isdefined(modul, name) && ( + getfield(modul, name) isa DataType || ( + getfield(modul, name) isa UnionAll && + Base.unwrap_unionall(getfield(modul, name)) isa DataType + ) + ) push!(types, name) end end @@ -368,7 +373,12 @@ This set of functions helps extract the inheritance hierarchy of types defined i function get_supertypes(modul::Module) types=Dict() for name ∈ names(modul) - if isdefined(modul, name) && getfield(modul, name) isa DataType + if isdefined(modul, name) && ( + getfield(modul, name) isa DataType || ( + getfield(modul, name) isa UnionAll && + Base.unwrap_unionall(getfield(modul, name)) isa DataType + ) + ) types[name] = supertypes(getfield(modul, name)) end end @@ -410,7 +420,6 @@ Checks whether a given type is a concrete struct with at least one field. # Description This function combines three checks: -- `isconcretetype(type)`: Ensures the type is concrete (i.e., can be instantiated). - `isstructtype(type)`: Ensures the type is a struct. - `nfields(type) > 0`: Ensures the struct has at least one field. @@ -427,7 +436,8 @@ has_fields(AbstractType) # returns false ``` """ function has_fields(type) - return (isconcretetype(type) && isstructtype(type) && nfields(type) > 0) + t = type isa UnionAll ? Base.unwrap_unionall(type) : type + return (t isa DataType && isstructtype(t) && nfields(t) > 0) end """ diff --git a/test/test_interactivity.jl b/test/test_interactivity.jl index c882ddd..0f0dba2 100644 --- a/test/test_interactivity.jl +++ b/test/test_interactivity.jl @@ -98,7 +98,8 @@ pin_plot_button = get_button(gui, :pin_plot) descriptive_names_raw = YAML.load_file(path_to_descriptive_names; dicttype = Dict{Symbol,Any}) str1 = "Relative fixed operating expense per installed capacity" - gui2 = GUI( + str2 = "Initial stored energy in the dam" + gui3 = GUI( case; path_to_descriptive_names = path_to_descriptive_names, ) @@ -106,10 +107,17 @@ pin_plot_button = get_button(gui, :pin_plot) @test :StorCapOpexFixed ∉ keys(descriptive_names_raw[:structures]) @test :RefNetworkNode ∉ keys(descriptive_names_raw[:structures]) - descriptive_names = EMGUI.get_var(gui2, :descriptive_names) + @test descriptive_names_raw[:structures][:HydroStorage][:level_init] == str2 + @test :HydroStor ∉ keys(descriptive_names_raw[:structures]) + @test :PumpedHydroStor ∉ keys(descriptive_names_raw[:structures]) + + descriptive_names = EMGUI.get_var(gui3, :descriptive_names) @test descriptive_names[:structures][:StorCapOpexFixed][:opex_fixed] == str1 @test descriptive_names[:structures][:RefNetworkNode][:opex_fixed] == str1 - EMGUI.close(gui2) + + @test descriptive_names[:structures][:HydroStor][:level_init] == str2 + @test descriptive_names[:structures][:PumpedHydroStor][:level_init] == str2 + EMGUI.close(gui3) end end From fa364909f83d9e598a04ca65d9b8f17d5011d916 Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Mon, 27 Oct 2025 15:52:06 +0100 Subject: [PATCH 09/23] Implement inheritance of field names for structures based on supertypes: - utils function necessary for inheritance - changes to update_descriptive_names! to add inheritance step - Changes to descriptive_names.yml; removing redundant descriptive names and adding descriptive names to supertypes. --- src/descriptive_names.yml | 1 + src/utils_GUI/GUI_utils.jl | 2 ++ src/utils_gen/utils.jl | 74 +++++++++++++------------------------- 3 files changed, 27 insertions(+), 50 deletions(-) diff --git a/src/descriptive_names.yml b/src/descriptive_names.yml index b1fbdd0..5422d89 100644 --- a/src/descriptive_names.yml +++ b/src/descriptive_names.yml @@ -27,6 +27,7 @@ structures: opex_var: "Relative variable operating expense per energy unit transported" opex_fixed: "Relative fixed operating expense per installed capacity" consumption_rate: "Rate at which the resource is consumed, as a ratio of the volume of the resource going into the inlet" + trans_loss: "Relative loss of the transported resource during transmission" # EnergyModelsInvestment ## investment_data.jl diff --git a/src/utils_GUI/GUI_utils.jl b/src/utils_GUI/GUI_utils.jl index 7a4ffd4..7d0b441 100644 --- a/src/utils_GUI/GUI_utils.jl +++ b/src/utils_GUI/GUI_utils.jl @@ -634,7 +634,9 @@ function update_descriptive_names!(gui::GUI) # apply inheritances for fetching descriptive names # create a dictionary were the keys are all the types defined in emx_packages and the values are the types they inherit from emx_supertypes_dict = get_supertypes(emx_packages) + inherit_descriptive_names_from_supertypes!(descriptive_names, emx_supertypes_dict) + for package ∈ emx_packages package_path::Union{String,Nothing} = dirname(dirname(Base.find_package(package))) if !isnothing(package_path) diff --git a/src/utils_gen/utils.jl b/src/utils_gen/utils.jl index e70d378..2101085 100644 --- a/src/utils_gen/utils.jl +++ b/src/utils_gen/utils.jl @@ -308,13 +308,8 @@ get_types(["Base", "Core"]) # returns type names from both packages """ function get_types(modul::Module) types = [] - for name ∈ names(modul) - if isdefined(modul, name) && ( - getfield(modul, name) isa DataType || ( - getfield(modul, name) isa UnionAll && - Base.unwrap_unionall(getfield(modul, name)) isa DataType - ) - ) + for name in names(modul) + if isdefined(modul, name) && getfield(modul, name) isa DataType push!(types, name) end end @@ -323,7 +318,7 @@ end function get_types(moduls::Vector{Module}) types=[] - for modul ∈ moduls + for modul in moduls append!(types, get_types(modul)) end return types @@ -333,9 +328,9 @@ function get_types(pkg::Union{String,Symbol}) return get_types(getfield(Main, Symbol(pkg))) end -function get_types(pkgs::Union{Vector{<:Union{String,Symbol}},Set{<:Union{String,Symbol}}}) +function get_types(pkgs::Union{Vector{<:Union{String,Symbol}}, Set{<:Union{String,Symbol}}}) types = [] - for pkg ∈ pkgs + for pkg in pkgs append!(types, get_types(pkg)) end return types @@ -372,13 +367,8 @@ This set of functions helps extract the inheritance hierarchy of types defined i """ function get_supertypes(modul::Module) types=Dict() - for name ∈ names(modul) - if isdefined(modul, name) && ( - getfield(modul, name) isa DataType || ( - getfield(modul, name) isa UnionAll && - Base.unwrap_unionall(getfield(modul, name)) isa DataType - ) - ) + for name in names(modul) + if isdefined(modul, name) && getfield(modul, name) isa DataType types[name] = supertypes(getfield(modul, name)) end end @@ -387,7 +377,7 @@ end function get_supertypes(moduls::Vector{Module}) types=Dict() - for modul ∈ moduls + for modul in moduls merge!(types, get_supertypes(modul)) end return types @@ -397,11 +387,9 @@ function get_supertypes(pkg::Union{String,Symbol}) return get_supertypes(getfield(Main, Symbol(pkg))) end -function get_supertypes( - pkgs::Union{Vector{<:Union{String,Symbol}},Set{<:Union{String,Symbol}}}, -) +function get_supertypes(pkgs::Union{Vector{<:Union{String,Symbol}}, Set{<:Union{String,Symbol}}}) types = Dict() - for pkg ∈ pkgs + for pkg in pkgs merge!(types, get_supertypes(pkg)) end return types @@ -420,6 +408,7 @@ Checks whether a given type is a concrete struct with at least one field. # Description This function combines three checks: +- `isconcretetype(type)`: Ensures the type is concrete (i.e., can be instantiated). - `isstructtype(type)`: Ensures the type is a struct. - `nfields(type) > 0`: Ensures the struct has at least one field. @@ -436,8 +425,7 @@ has_fields(AbstractType) # returns false ``` """ function has_fields(type) - t = type isa UnionAll ? Base.unwrap_unionall(type) : type - return (t isa DataType && isstructtype(t) && nfields(t) > 0) + return (isconcretetype(type) && isstructtype(type) && nfields(type) > 0) end """ @@ -458,7 +446,7 @@ If `tmp_type` is not already a key in `current_lvl`, it adds it with an empty di """ function update_tree!(current_lvl, tmp_type::Type) if !haskey(current_lvl, tmp_type) - current_lvl[tmp_type] = Dict{Type,Union{Dict,Nothing}}() + current_lvl[tmp_type] = Dict{Type, Union{Dict, Nothing}}() end return end @@ -480,13 +468,13 @@ This function builds a tree-like structure of type dependencies by iterating thr """ function get_types_structure(emx_supertypes_dict) # make a visualization of the type dependencies by building a nested dictionary of types - emx_type_dependencies = Dict{Type,Union{Dict,Nothing}}() - for (emx_type_id, emx_supertypes) ∈ emx_supertypes_dict + emx_type_dependencies = Dict{Type, Union{Dict, Nothing}}() + for (emx_type_id, emx_supertypes) in emx_supertypes_dict i = 0 current_lvl = emx_type_dependencies while i < length(emx_supertypes) tmp_type = emx_supertypes[end-i] - update_tree!(current_lvl, tmp_type) + update_tree!(current_lvl,tmp_type) current_lvl = current_lvl[tmp_type] i+=1 end @@ -515,40 +503,26 @@ If a descriptive name exists for a field in a supertype but not in the subtype, - Updates `descriptive_names` in-place by inheriting missing descriptive names from supertypes. """ function inherit_descriptive_names_from_supertypes!(descriptive_names, emx_supertypes_dict) - for (emx_type_id, emx_supertypes) ∈ emx_supertypes_dict + for (emx_type_id, emx_supertypes) in emx_supertypes_dict emx_type = emx_supertypes[1] # check if emx_type has field names and if so retrieve them, otherwise continue if !has_fields(emx_type) continue end emx_type_fieldnames = fieldnames(emx_type) - for fname ∈ emx_type_fieldnames - for emx_supertype ∈ emx_supertypes[2:end] # skip first element as it is the type itself + for fname in emx_type_fieldnames + for emx_supertype in emx_supertypes[2:end] # skip first element as it is the type itself #check if the supertype has an entry in descriptive names for fname - # Extract only what is after the dot in emx_supertype, if any - supertype_str = string(emx_supertype) - supertype_key = - occursin(r"\.", supertype_str) ? - match(r"\.([^.]+)$", supertype_str).captures[1] : supertype_str - if haskey(descriptive_names[:structures], Symbol(supertype_key)) && - haskey( - descriptive_names[:structures][Symbol(supertype_key)], - Symbol(fname), - ) + if haskey(descriptive_names[:structures], Symbol(emx_supertype)) && + haskey(descriptive_names[:structures][Symbol(emx_supertype)], Symbol(fname)) # if so, and if the emx_type does not have an entry for fname, copy it if !haskey(descriptive_names[:structures], Symbol(emx_type)) || - !haskey( - descriptive_names[:structures][Symbol(emx_type)], - Symbol(fname), - ) + !haskey(descriptive_names[:structures][Symbol(emx_type)], Symbol(fname)) if !haskey(descriptive_names[:structures], Symbol(emx_type)) - descriptive_names[:structures][Symbol(emx_type)] = - Dict{Symbol,Any}() + descriptive_names[:structures][Symbol(emx_type)] = Dict{Symbol,Any}() end descriptive_names[:structures][Symbol(emx_type)][Symbol(fname)] = - descriptive_names[:structures][Symbol(supertype_key)][Symbol( - fname, - )] + descriptive_names[:structures][Symbol(emx_supertype)][Symbol(fname)] end end end From b95dd72beecfcde7db6d8862d256f74487f9c061 Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Tue, 4 Nov 2025 13:22:18 +0100 Subject: [PATCH 10/23] Julia formatter --- src/utils_gen/utils.jl | 49 ++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/src/utils_gen/utils.jl b/src/utils_gen/utils.jl index 2101085..b4e2bd2 100644 --- a/src/utils_gen/utils.jl +++ b/src/utils_gen/utils.jl @@ -308,7 +308,7 @@ get_types(["Base", "Core"]) # returns type names from both packages """ function get_types(modul::Module) types = [] - for name in names(modul) + for name ∈ names(modul) if isdefined(modul, name) && getfield(modul, name) isa DataType push!(types, name) end @@ -318,7 +318,7 @@ end function get_types(moduls::Vector{Module}) types=[] - for modul in moduls + for modul ∈ moduls append!(types, get_types(modul)) end return types @@ -328,9 +328,9 @@ function get_types(pkg::Union{String,Symbol}) return get_types(getfield(Main, Symbol(pkg))) end -function get_types(pkgs::Union{Vector{<:Union{String,Symbol}}, Set{<:Union{String,Symbol}}}) +function get_types(pkgs::Union{Vector{<:Union{String,Symbol}},Set{<:Union{String,Symbol}}}) types = [] - for pkg in pkgs + for pkg ∈ pkgs append!(types, get_types(pkg)) end return types @@ -367,7 +367,7 @@ This set of functions helps extract the inheritance hierarchy of types defined i """ function get_supertypes(modul::Module) types=Dict() - for name in names(modul) + for name ∈ names(modul) if isdefined(modul, name) && getfield(modul, name) isa DataType types[name] = supertypes(getfield(modul, name)) end @@ -377,7 +377,7 @@ end function get_supertypes(moduls::Vector{Module}) types=Dict() - for modul in moduls + for modul ∈ moduls merge!(types, get_supertypes(modul)) end return types @@ -387,9 +387,11 @@ function get_supertypes(pkg::Union{String,Symbol}) return get_supertypes(getfield(Main, Symbol(pkg))) end -function get_supertypes(pkgs::Union{Vector{<:Union{String,Symbol}}, Set{<:Union{String,Symbol}}}) +function get_supertypes( + pkgs::Union{Vector{<:Union{String,Symbol}},Set{<:Union{String,Symbol}}}, +) types = Dict() - for pkg in pkgs + for pkg ∈ pkgs merge!(types, get_supertypes(pkg)) end return types @@ -446,7 +448,7 @@ If `tmp_type` is not already a key in `current_lvl`, it adds it with an empty di """ function update_tree!(current_lvl, tmp_type::Type) if !haskey(current_lvl, tmp_type) - current_lvl[tmp_type] = Dict{Type, Union{Dict, Nothing}}() + current_lvl[tmp_type] = Dict{Type,Union{Dict,Nothing}}() end return end @@ -468,13 +470,13 @@ This function builds a tree-like structure of type dependencies by iterating thr """ function get_types_structure(emx_supertypes_dict) # make a visualization of the type dependencies by building a nested dictionary of types - emx_type_dependencies = Dict{Type, Union{Dict, Nothing}}() - for (emx_type_id, emx_supertypes) in emx_supertypes_dict + emx_type_dependencies = Dict{Type,Union{Dict,Nothing}}() + for (emx_type_id, emx_supertypes) ∈ emx_supertypes_dict i = 0 current_lvl = emx_type_dependencies while i < length(emx_supertypes) tmp_type = emx_supertypes[end-i] - update_tree!(current_lvl,tmp_type) + update_tree!(current_lvl, tmp_type) current_lvl = current_lvl[tmp_type] i+=1 end @@ -503,26 +505,35 @@ If a descriptive name exists for a field in a supertype but not in the subtype, - Updates `descriptive_names` in-place by inheriting missing descriptive names from supertypes. """ function inherit_descriptive_names_from_supertypes!(descriptive_names, emx_supertypes_dict) - for (emx_type_id, emx_supertypes) in emx_supertypes_dict + for (emx_type_id, emx_supertypes) ∈ emx_supertypes_dict emx_type = emx_supertypes[1] # check if emx_type has field names and if so retrieve them, otherwise continue if !has_fields(emx_type) continue end emx_type_fieldnames = fieldnames(emx_type) - for fname in emx_type_fieldnames - for emx_supertype in emx_supertypes[2:end] # skip first element as it is the type itself + for fname ∈ emx_type_fieldnames + for emx_supertype ∈ emx_supertypes[2:end] # skip first element as it is the type itself #check if the supertype has an entry in descriptive names for fname if haskey(descriptive_names[:structures], Symbol(emx_supertype)) && - haskey(descriptive_names[:structures][Symbol(emx_supertype)], Symbol(fname)) + haskey( + descriptive_names[:structures][Symbol(emx_supertype)], + Symbol(fname), + ) # if so, and if the emx_type does not have an entry for fname, copy it if !haskey(descriptive_names[:structures], Symbol(emx_type)) || - !haskey(descriptive_names[:structures][Symbol(emx_type)], Symbol(fname)) + !haskey( + descriptive_names[:structures][Symbol(emx_type)], + Symbol(fname), + ) if !haskey(descriptive_names[:structures], Symbol(emx_type)) - descriptive_names[:structures][Symbol(emx_type)] = Dict{Symbol,Any}() + descriptive_names[:structures][Symbol(emx_type)] = + Dict{Symbol,Any}() end descriptive_names[:structures][Symbol(emx_type)][Symbol(fname)] = - descriptive_names[:structures][Symbol(emx_supertype)][Symbol(fname)] + descriptive_names[:structures][Symbol(emx_supertype)][Symbol( + fname, + )] end end end From d571f27079ace6b0f12fa9bf6ea6d7f798c40340 Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Wed, 5 Nov 2025 13:07:39 +0100 Subject: [PATCH 11/23] remove duplicate entry in descriptive names --- src/descriptive_names.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/descriptive_names.yml b/src/descriptive_names.yml index 5422d89..b1fbdd0 100644 --- a/src/descriptive_names.yml +++ b/src/descriptive_names.yml @@ -27,7 +27,6 @@ structures: opex_var: "Relative variable operating expense per energy unit transported" opex_fixed: "Relative fixed operating expense per installed capacity" consumption_rate: "Rate at which the resource is consumed, as a ratio of the volume of the resource going into the inlet" - trans_loss: "Relative loss of the transported resource during transmission" # EnergyModelsInvestment ## investment_data.jl From a1d00c260b0298c2c437862da6314c56010e2171 Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Wed, 5 Nov 2025 13:08:02 +0100 Subject: [PATCH 12/23] Add initial test of inheritance of descriptive names --- test/test_interactivity.jl | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/test/test_interactivity.jl b/test/test_interactivity.jl index 0f0dba2..085f271 100644 --- a/test/test_interactivity.jl +++ b/test/test_interactivity.jl @@ -98,8 +98,7 @@ pin_plot_button = get_button(gui, :pin_plot) descriptive_names_raw = YAML.load_file(path_to_descriptive_names; dicttype = Dict{Symbol,Any}) str1 = "Relative fixed operating expense per installed capacity" - str2 = "Initial stored energy in the dam" - gui3 = GUI( + gui2 = GUI( case; path_to_descriptive_names = path_to_descriptive_names, ) @@ -107,17 +106,11 @@ pin_plot_button = get_button(gui, :pin_plot) @test :StorCapOpexFixed ∉ keys(descriptive_names_raw[:structures]) @test :RefNetworkNode ∉ keys(descriptive_names_raw[:structures]) - @test descriptive_names_raw[:structures][:HydroStorage][:level_init] == str2 - @test :HydroStor ∉ keys(descriptive_names_raw[:structures]) - @test :PumpedHydroStor ∉ keys(descriptive_names_raw[:structures]) - - descriptive_names = EMGUI.get_var(gui3, :descriptive_names) + descriptive_names = EMGUI.get_var(gui2, :descriptive_names) + @test :Node ∉ keys(descriptive_names[:structures]) @test descriptive_names[:structures][:StorCapOpexFixed][:opex_fixed] == str1 @test descriptive_names[:structures][:RefNetworkNode][:opex_fixed] == str1 - - @test descriptive_names[:structures][:HydroStor][:level_init] == str2 - @test descriptive_names[:structures][:PumpedHydroStor][:level_init] == str2 - EMGUI.close(gui3) + EMGUI.close(gui2) end end From 529e97cce0830ace5005785db3c2855026b22fa4 Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Wed, 5 Nov 2025 23:04:52 +0100 Subject: [PATCH 13/23] fix tests and processing of supertypes --- src/utils_GUI/GUI_utils.jl | 2 -- src/utils_gen/utils.jl | 11 ++++++++--- test/test_interactivity.jl | 1 - 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/utils_GUI/GUI_utils.jl b/src/utils_GUI/GUI_utils.jl index 7d0b441..7a4ffd4 100644 --- a/src/utils_GUI/GUI_utils.jl +++ b/src/utils_GUI/GUI_utils.jl @@ -634,9 +634,7 @@ function update_descriptive_names!(gui::GUI) # apply inheritances for fetching descriptive names # create a dictionary were the keys are all the types defined in emx_packages and the values are the types they inherit from emx_supertypes_dict = get_supertypes(emx_packages) - inherit_descriptive_names_from_supertypes!(descriptive_names, emx_supertypes_dict) - for package ∈ emx_packages package_path::Union{String,Nothing} = dirname(dirname(Base.find_package(package))) if !isnothing(package_path) diff --git a/src/utils_gen/utils.jl b/src/utils_gen/utils.jl index b4e2bd2..d5dcd7c 100644 --- a/src/utils_gen/utils.jl +++ b/src/utils_gen/utils.jl @@ -515,9 +515,14 @@ function inherit_descriptive_names_from_supertypes!(descriptive_names, emx_super for fname ∈ emx_type_fieldnames for emx_supertype ∈ emx_supertypes[2:end] # skip first element as it is the type itself #check if the supertype has an entry in descriptive names for fname - if haskey(descriptive_names[:structures], Symbol(emx_supertype)) && + # Extract only what is after the dot in emx_supertype, if any + supertype_str = string(emx_supertype) + supertype_key = + occursin(r"\.", supertype_str) ? + match(r"\.([^.]+)$", supertype_str).captures[1] : supertype_str + if haskey(descriptive_names[:structures], Symbol(supertype_key)) && haskey( - descriptive_names[:structures][Symbol(emx_supertype)], + descriptive_names[:structures][Symbol(supertype_key)], Symbol(fname), ) # if so, and if the emx_type does not have an entry for fname, copy it @@ -531,7 +536,7 @@ function inherit_descriptive_names_from_supertypes!(descriptive_names, emx_super Dict{Symbol,Any}() end descriptive_names[:structures][Symbol(emx_type)][Symbol(fname)] = - descriptive_names[:structures][Symbol(emx_supertype)][Symbol( + descriptive_names[:structures][Symbol(supertype_key)][Symbol( fname, )] end diff --git a/test/test_interactivity.jl b/test/test_interactivity.jl index 085f271..c882ddd 100644 --- a/test/test_interactivity.jl +++ b/test/test_interactivity.jl @@ -107,7 +107,6 @@ pin_plot_button = get_button(gui, :pin_plot) @test :RefNetworkNode ∉ keys(descriptive_names_raw[:structures]) descriptive_names = EMGUI.get_var(gui2, :descriptive_names) - @test :Node ∉ keys(descriptive_names[:structures]) @test descriptive_names[:structures][:StorCapOpexFixed][:opex_fixed] == str1 @test descriptive_names[:structures][:RefNetworkNode][:opex_fixed] == str1 EMGUI.close(gui2) From 012f4c1ebbf55bf1528687a47d83c41e03a06478 Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Thu, 6 Nov 2025 15:30:47 +0100 Subject: [PATCH 14/23] Fix feature for parametric structs that have type UnionAll and added tests --- src/utils_gen/utils.jl | 18 ++++++++++++++---- test/test_interactivity.jl | 14 +++++++++++--- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/utils_gen/utils.jl b/src/utils_gen/utils.jl index d5dcd7c..e70d378 100644 --- a/src/utils_gen/utils.jl +++ b/src/utils_gen/utils.jl @@ -309,7 +309,12 @@ get_types(["Base", "Core"]) # returns type names from both packages function get_types(modul::Module) types = [] for name ∈ names(modul) - if isdefined(modul, name) && getfield(modul, name) isa DataType + if isdefined(modul, name) && ( + getfield(modul, name) isa DataType || ( + getfield(modul, name) isa UnionAll && + Base.unwrap_unionall(getfield(modul, name)) isa DataType + ) + ) push!(types, name) end end @@ -368,7 +373,12 @@ This set of functions helps extract the inheritance hierarchy of types defined i function get_supertypes(modul::Module) types=Dict() for name ∈ names(modul) - if isdefined(modul, name) && getfield(modul, name) isa DataType + if isdefined(modul, name) && ( + getfield(modul, name) isa DataType || ( + getfield(modul, name) isa UnionAll && + Base.unwrap_unionall(getfield(modul, name)) isa DataType + ) + ) types[name] = supertypes(getfield(modul, name)) end end @@ -410,7 +420,6 @@ Checks whether a given type is a concrete struct with at least one field. # Description This function combines three checks: -- `isconcretetype(type)`: Ensures the type is concrete (i.e., can be instantiated). - `isstructtype(type)`: Ensures the type is a struct. - `nfields(type) > 0`: Ensures the struct has at least one field. @@ -427,7 +436,8 @@ has_fields(AbstractType) # returns false ``` """ function has_fields(type) - return (isconcretetype(type) && isstructtype(type) && nfields(type) > 0) + t = type isa UnionAll ? Base.unwrap_unionall(type) : type + return (t isa DataType && isstructtype(t) && nfields(t) > 0) end """ diff --git a/test/test_interactivity.jl b/test/test_interactivity.jl index c882ddd..0f0dba2 100644 --- a/test/test_interactivity.jl +++ b/test/test_interactivity.jl @@ -98,7 +98,8 @@ pin_plot_button = get_button(gui, :pin_plot) descriptive_names_raw = YAML.load_file(path_to_descriptive_names; dicttype = Dict{Symbol,Any}) str1 = "Relative fixed operating expense per installed capacity" - gui2 = GUI( + str2 = "Initial stored energy in the dam" + gui3 = GUI( case; path_to_descriptive_names = path_to_descriptive_names, ) @@ -106,10 +107,17 @@ pin_plot_button = get_button(gui, :pin_plot) @test :StorCapOpexFixed ∉ keys(descriptive_names_raw[:structures]) @test :RefNetworkNode ∉ keys(descriptive_names_raw[:structures]) - descriptive_names = EMGUI.get_var(gui2, :descriptive_names) + @test descriptive_names_raw[:structures][:HydroStorage][:level_init] == str2 + @test :HydroStor ∉ keys(descriptive_names_raw[:structures]) + @test :PumpedHydroStor ∉ keys(descriptive_names_raw[:structures]) + + descriptive_names = EMGUI.get_var(gui3, :descriptive_names) @test descriptive_names[:structures][:StorCapOpexFixed][:opex_fixed] == str1 @test descriptive_names[:structures][:RefNetworkNode][:opex_fixed] == str1 - EMGUI.close(gui2) + + @test descriptive_names[:structures][:HydroStor][:level_init] == str2 + @test descriptive_names[:structures][:PumpedHydroStor][:level_init] == str2 + EMGUI.close(gui3) end end From 0f9ed952b69f329ceb6b2e9f540cd7580eb44c7c Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Mon, 27 Oct 2025 15:52:06 +0100 Subject: [PATCH 15/23] Implement inheritance of field names for structures based on supertypes: - utils function necessary for inheritance - changes to update_descriptive_names! to add inheritance step - Changes to descriptive_names.yml; removing redundant descriptive names and adding descriptive names to supertypes. --- src/utils_GUI/GUI_utils.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils_GUI/GUI_utils.jl b/src/utils_GUI/GUI_utils.jl index 7a4ffd4..51d2277 100644 --- a/src/utils_GUI/GUI_utils.jl +++ b/src/utils_GUI/GUI_utils.jl @@ -635,6 +635,7 @@ function update_descriptive_names!(gui::GUI) # create a dictionary were the keys are all the types defined in emx_packages and the values are the types they inherit from emx_supertypes_dict = get_supertypes(emx_packages) inherit_descriptive_names_from_supertypes!(descriptive_names, emx_supertypes_dict) + for package ∈ emx_packages package_path::Union{String,Nothing} = dirname(dirname(Base.find_package(package))) if !isnothing(package_path) From 1f40db2aff38de5805e24d89b93283eff5865bcc Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Wed, 5 Nov 2025 13:08:02 +0100 Subject: [PATCH 16/23] Add initial test of inheritance of descriptive names --- test/test_interactivity.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_interactivity.jl b/test/test_interactivity.jl index 0f0dba2..71a5da9 100644 --- a/test/test_interactivity.jl +++ b/test/test_interactivity.jl @@ -103,6 +103,7 @@ pin_plot_button = get_button(gui, :pin_plot) case; path_to_descriptive_names = path_to_descriptive_names, ) + @test descriptive_names_raw[:structures][:Node][:opex_fixed] == str1 @test :StorCapOpexFixed ∉ keys(descriptive_names_raw[:structures]) @test :RefNetworkNode ∉ keys(descriptive_names_raw[:structures]) From 56621a958e06e3c931212c9ccc30f5dbfdc21b88 Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Wed, 5 Nov 2025 23:04:52 +0100 Subject: [PATCH 17/23] fix tests and processing of supertypes --- src/utils_GUI/GUI_utils.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/utils_GUI/GUI_utils.jl b/src/utils_GUI/GUI_utils.jl index 51d2277..7a4ffd4 100644 --- a/src/utils_GUI/GUI_utils.jl +++ b/src/utils_GUI/GUI_utils.jl @@ -635,7 +635,6 @@ function update_descriptive_names!(gui::GUI) # create a dictionary were the keys are all the types defined in emx_packages and the values are the types they inherit from emx_supertypes_dict = get_supertypes(emx_packages) inherit_descriptive_names_from_supertypes!(descriptive_names, emx_supertypes_dict) - for package ∈ emx_packages package_path::Union{String,Nothing} = dirname(dirname(Base.find_package(package))) if !isnothing(package_path) From 02aa06265ba2881e3ca6f2456601da97f2d6d15d Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Mon, 17 Nov 2025 10:14:07 +0100 Subject: [PATCH 18/23] Moving tests to own file --- test/runtests.jl | 3 ++ test/test_descriptive_names.jl | 66 ++++++++++++++++++++++++++++++++++ test/test_interactivity.jl | 61 ------------------------------- 3 files changed, 69 insertions(+), 61 deletions(-) create mode 100644 test/test_descriptive_names.jl diff --git a/test/runtests.jl b/test/runtests.jl index 1fa0808..1249485 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -41,6 +41,9 @@ global_logger(logger_new) # Test specific GUI functionalities related to interactivity include("test_interactivity.jl") + + # Test descriptive names functionalities + include("test_descriptive_names.jl") end end global_logger(logger_org) diff --git a/test/test_descriptive_names.jl b/test/test_descriptive_names.jl new file mode 100644 index 0000000..bd4bdc5 --- /dev/null +++ b/test/test_descriptive_names.jl @@ -0,0 +1,66 @@ +case, model, m, gui = run_case() + +# Test specific miscellaneous descriptive names +@testset "Test descriptive names" verbose = true begin + + @testset "Test customizing descriptive names" begin + path_to_descriptive_names = joinpath(pkgdir(EMGUI), "src", "descriptive_names.yml") + str1 = "" + str2 = "" + str3 = "" + str4 = "" + str5 = "" + str6 = "" + descriptive_names_dict = Dict( + :structures => Dict( # Input parameter from the case Dict + :RefStatic => Dict(:trans_cap => str1, :opex_fixed => str2), + :RefDynamic => Dict(:opex_var => str3, :directions => str4), + ), + :variables => Dict( # variables from the JuMP model + :stor_discharge_use => str5, + :trans_cap_rem => str6, + ), + ) + gui2 = GUI( + case; + path_to_descriptive_names = path_to_descriptive_names, + descriptive_names_dict = descriptive_names_dict, + ) + descriptive_names = EMGUI.get_var(gui2, :descriptive_names) + @test descriptive_names[:structures][:RefStatic][:trans_cap] == str1 + @test descriptive_names[:structures][:RefStatic][:opex_fixed] == str2 + @test descriptive_names[:structures][:RefDynamic][:opex_var] == str3 + @test descriptive_names[:structures][:RefDynamic][:directions] == str4 + @test descriptive_names[:variables][:stor_discharge_use] == str5 + @test descriptive_names[:variables][:trans_cap_rem] == str6 + EMGUI.close(gui2) + end + + @testset "Test inheritance of descriptive names" begin + path_to_descriptive_names = joinpath(pkgdir(EMGUI), "src", "descriptive_names.yml") + descriptive_names_raw = + YAML.load_file(path_to_descriptive_names; dicttype = Dict{Symbol,Any}) + str1 = "Relative fixed operating expense per installed capacity" + str2 = "Initial stored energy in the dam" + gui3 = GUI( + case; + path_to_descriptive_names = path_to_descriptive_names, + ) + + @test descriptive_names_raw[:structures][:Node][:opex_fixed] == str1 + @test :StorCapOpexFixed ∉ keys(descriptive_names_raw[:structures]) + @test :RefNetworkNode ∉ keys(descriptive_names_raw[:structures]) + + @test descriptive_names_raw[:structures][:HydroStorage][:level_init] == str2 + @test :HydroStor ∉ keys(descriptive_names_raw[:structures]) + @test :PumpedHydroStor ∉ keys(descriptive_names_raw[:structures]) + + descriptive_names = EMGUI.get_var(gui3, :descriptive_names) + @test descriptive_names[:structures][:StorCapOpexFixed][:opex_fixed] == str1 + @test descriptive_names[:structures][:RefNetworkNode][:opex_fixed] == str1 + + @test descriptive_names[:structures][:HydroStor][:level_init] == str2 + @test descriptive_names[:structures][:PumpedHydroStor][:level_init] == str2 + EMGUI.close(gui3) + end +end diff --git a/test/test_interactivity.jl b/test/test_interactivity.jl index 71a5da9..5c2846f 100644 --- a/test/test_interactivity.jl +++ b/test/test_interactivity.jl @@ -59,67 +59,6 @@ pin_plot_button = get_button(gui, :pin_plot) system = EMGUI.parse_case(case) @test Base.show(system) == dump(system; maxdepth = 1) end - - @testset "Test customizing descriptive names" begin - path_to_descriptive_names = joinpath(pkgdir(EMGUI), "src", "descriptive_names.yml") - str1 = "" - str2 = "" - str3 = "" - str4 = "" - str5 = "" - str6 = "" - descriptive_names_dict = Dict( - :structures => Dict( # Input parameter from the case Dict - :RefStatic => Dict(:trans_cap => str1, :opex_fixed => str2), - :RefDynamic => Dict(:opex_var => str3, :directions => str4), - ), - :variables => Dict( # variables from the JuMP model - :stor_discharge_use => str5, - :trans_cap_rem => str6, - ), - ) - gui2 = GUI( - case; - path_to_descriptive_names = path_to_descriptive_names, - descriptive_names_dict = descriptive_names_dict, - ) - descriptive_names = EMGUI.get_var(gui2, :descriptive_names) - @test descriptive_names[:structures][:RefStatic][:trans_cap] == str1 - @test descriptive_names[:structures][:RefStatic][:opex_fixed] == str2 - @test descriptive_names[:structures][:RefDynamic][:opex_var] == str3 - @test descriptive_names[:structures][:RefDynamic][:directions] == str4 - @test descriptive_names[:variables][:stor_discharge_use] == str5 - @test descriptive_names[:variables][:trans_cap_rem] == str6 - EMGUI.close(gui2) - end - - @testset "Test inheritance of descriptive names" begin - path_to_descriptive_names = joinpath(pkgdir(EMGUI), "src", "descriptive_names.yml") - descriptive_names_raw = - YAML.load_file(path_to_descriptive_names; dicttype = Dict{Symbol,Any}) - str1 = "Relative fixed operating expense per installed capacity" - str2 = "Initial stored energy in the dam" - gui3 = GUI( - case; - path_to_descriptive_names = path_to_descriptive_names, - ) - - @test descriptive_names_raw[:structures][:Node][:opex_fixed] == str1 - @test :StorCapOpexFixed ∉ keys(descriptive_names_raw[:structures]) - @test :RefNetworkNode ∉ keys(descriptive_names_raw[:structures]) - - @test descriptive_names_raw[:structures][:HydroStorage][:level_init] == str2 - @test :HydroStor ∉ keys(descriptive_names_raw[:structures]) - @test :PumpedHydroStor ∉ keys(descriptive_names_raw[:structures]) - - descriptive_names = EMGUI.get_var(gui3, :descriptive_names) - @test descriptive_names[:structures][:StorCapOpexFixed][:opex_fixed] == str1 - @test descriptive_names[:structures][:RefNetworkNode][:opex_fixed] == str1 - - @test descriptive_names[:structures][:HydroStor][:level_init] == str2 - @test descriptive_names[:structures][:PumpedHydroStor][:level_init] == str2 - EMGUI.close(gui3) - end end # Test specific GUI functionalities From bf8ea91de31d896de0fac2cff09bff6b0bb2cf9d Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Mon, 17 Nov 2025 10:15:24 +0100 Subject: [PATCH 19/23] simplify descriptive names even more --- src/descriptive_names.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/descriptive_names.yml b/src/descriptive_names.yml index b1fbdd0..05a34de 100644 --- a/src/descriptive_names.yml +++ b/src/descriptive_names.yml @@ -84,7 +84,7 @@ structures: HydroPump: cap: "Installed pumping capacity" - CycleLife: + AbstractBatteryLife: stack_cost: "Relative cost for replacing a battery stack" # EnergyModelsHeat @@ -118,10 +118,6 @@ structures: up: "Maximum positive rate of change of a node" down: "Maximum negative rate of change of a node" - Reformer: - opex_var: "Variable operating expense per capacity usage" - opex_fixed: "Fixed operating expense per installed capacity" - # EnergyModelsCO2 CO2Source: opex_var: "Variable operating expense per energy unit produced" From 4297473d7b0ab83378b822f132664ae8adeb35a1 Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Mon, 17 Nov 2025 10:15:58 +0100 Subject: [PATCH 20/23] Change from reading installed packages to loaded packages --- src/utils_GUI/GUI_utils.jl | 7 +++---- src/utils_gen/structures_utils.jl | 7 +++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/utils_GUI/GUI_utils.jl b/src/utils_GUI/GUI_utils.jl index 7a4ffd4..047785d 100644 --- a/src/utils_GUI/GUI_utils.jl +++ b/src/utils_GUI/GUI_utils.jl @@ -625,12 +625,11 @@ function update_descriptive_names!(gui::GUI) joinpath(@__DIR__, "..", "descriptive_names.yml"); dicttype = Dict{Symbol,Any}, ) - # Get a dictionary of installed packages - installed_packages = installed() + # Get a dictionary of loaded packages + loaded_packages = loaded() # Filter packages with names matching the pattern "EnergyModels*" - emx_packages = filter(pkg -> occursin(r"EnergyModels", pkg), keys(installed_packages)) - + emx_packages = filter(pkg -> occursin(r"EnergyModels", pkg), loaded_packages) # apply inheritances for fetching descriptive names # create a dictionary were the keys are all the types defined in emx_packages and the values are the types they inherit from emx_supertypes_dict = get_supertypes(emx_packages) diff --git a/src/utils_gen/structures_utils.jl b/src/utils_gen/structures_utils.jl index 1dc6a84..a61000f 100644 --- a/src/utils_gen/structures_utils.jl +++ b/src/utils_gen/structures_utils.jl @@ -14,6 +14,13 @@ function installed() return installs end +""" + function loaded() + +Get a list of loaded packages. +""" +loaded() = filter((x) -> typeof(eval(x)) <: Module, names(Main,imported=true)) + """ place_nodes_in_circle(total_nodes::Int64, current_node::Int64, r::Float32, xₒ::Float32, yₒ::Float32) From 9767bc3bc1c29c96767419e2ba53f397702c28cf Mon Sep 17 00:00:00 2001 From: dqpinel Date: Mon, 17 Nov 2025 10:16:49 +0100 Subject: [PATCH 21/23] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jon Vegard Venås --- src/utils_gen/utils.jl | 50 ++++++++---------------------------------- 1 file changed, 9 insertions(+), 41 deletions(-) diff --git a/src/utils_gen/utils.jl b/src/utils_gen/utils.jl index e70d378..f6c1705 100644 --- a/src/utils_gen/utils.jl +++ b/src/utils_gen/utils.jl @@ -321,25 +321,10 @@ function get_types(modul::Module) return types end -function get_types(moduls::Vector{Module}) - types=[] - for modul ∈ moduls - append!(types, get_types(modul)) - end - return types -end - -function get_types(pkg::Union{String,Symbol}) - return get_types(getfield(Main, Symbol(pkg))) -end - -function get_types(pkgs::Union{Vector{<:Union{String,Symbol}},Set{<:Union{String,Symbol}}}) - types = [] - for pkg ∈ pkgs - append!(types, get_types(pkg)) - end - return types -end +get_types(modules::Vector{Module}) = [get_types(modul) for modul ∈ modules] +get_types(pkg::Union{String,Symbol}) = get_types(getfield(Main, Symbol(pkg))) +get_types(pkgs::Union{Vector{<:Union{String,Symbol}},Set{<:Union{String,Symbol}}}) = + get_types.(pkgs) """ get_supertypes(input) -> Dict{Symbol, Vector{Type}} @@ -385,27 +370,11 @@ function get_supertypes(modul::Module) return types end -function get_supertypes(moduls::Vector{Module}) - types=Dict() - for modul ∈ moduls - merge!(types, get_supertypes(modul)) - end - return types -end - -function get_supertypes(pkg::Union{String,Symbol}) - return get_supertypes(getfield(Main, Symbol(pkg))) -end - -function get_supertypes( - pkgs::Union{Vector{<:Union{String,Symbol}},Set{<:Union{String,Symbol}}}, -) - types = Dict() - for pkg ∈ pkgs - merge!(types, get_supertypes(pkg)) - end - return types -end +get_supertypes(moduls::Vector{Module}) = + merge!(Dict(), (get_supertypes(m) for m ∈ moduls)...) +get_supertypes(pkg::Union{String,Symbol}) = get_supertypes(getfield(Main, Symbol(pkg))) +get_supertypes(pkgs::Union{Vector{<:Union{String,Symbol}},Set{<:Union{String,Symbol}}}) = + merge!(Dict(), (get_supertypes(pkg) for pkg ∈ pkgs)...) """ has_fields(type::Type) -> Bool @@ -460,7 +429,6 @@ function update_tree!(current_lvl, tmp_type::Type) if !haskey(current_lvl, tmp_type) current_lvl[tmp_type] = Dict{Type,Union{Dict,Nothing}}() end - return end """ From e04b8ede25143f960c9e466f875d18f22eba9f4e Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Mon, 17 Nov 2025 10:29:50 +0100 Subject: [PATCH 22/23] julia formatter --- src/utils_gen/structures_utils.jl | 2 +- test/test_descriptive_names.jl | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/utils_gen/structures_utils.jl b/src/utils_gen/structures_utils.jl index a61000f..1cdca05 100644 --- a/src/utils_gen/structures_utils.jl +++ b/src/utils_gen/structures_utils.jl @@ -19,7 +19,7 @@ end Get a list of loaded packages. """ -loaded() = filter((x) -> typeof(eval(x)) <: Module, names(Main,imported=true)) +loaded() = filter((x) -> typeof(eval(x)) <: Module, names(Main, imported = true)) """ place_nodes_in_circle(total_nodes::Int64, current_node::Int64, r::Float32, xₒ::Float32, yₒ::Float32) diff --git a/test/test_descriptive_names.jl b/test/test_descriptive_names.jl index bd4bdc5..fc9eb68 100644 --- a/test/test_descriptive_names.jl +++ b/test/test_descriptive_names.jl @@ -2,7 +2,6 @@ case, model, m, gui = run_case() # Test specific miscellaneous descriptive names @testset "Test descriptive names" verbose = true begin - @testset "Test customizing descriptive names" begin path_to_descriptive_names = joinpath(pkgdir(EMGUI), "src", "descriptive_names.yml") str1 = "" From c3dbf2aecdf6df0d4ab27b79bc1d140b06f9217b Mon Sep 17 00:00:00 2001 From: Dimitri Pinel Date: Tue, 18 Nov 2025 09:49:17 +0100 Subject: [PATCH 23/23] change implementation of loaded and close gui in descriptive names test --- src/utils_gen/structures_utils.jl | 2 +- test/test_descriptive_names.jl | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils_gen/structures_utils.jl b/src/utils_gen/structures_utils.jl index 1cdca05..baa45f4 100644 --- a/src/utils_gen/structures_utils.jl +++ b/src/utils_gen/structures_utils.jl @@ -19,7 +19,7 @@ end Get a list of loaded packages. """ -loaded() = filter((x) -> typeof(eval(x)) <: Module, names(Main, imported = true)) +loaded() = [String(n) for n ∈ names(Main, imported = true) if getfield(Main, n) isa Module] """ place_nodes_in_circle(total_nodes::Int64, current_node::Int64, r::Float32, xₒ::Float32, yₒ::Float32) diff --git a/test/test_descriptive_names.jl b/test/test_descriptive_names.jl index fc9eb68..d8ac05d 100644 --- a/test/test_descriptive_names.jl +++ b/test/test_descriptive_names.jl @@ -63,3 +63,4 @@ case, model, m, gui = run_case() EMGUI.close(gui3) end end +EMGUI.close(gui)