From 3c428d36d8d109207ac1c0722fb9970e97eb7d1d Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Wed, 13 Aug 2025 16:43:57 +0530 Subject: [PATCH 1/5] chore: add at-metadata support for systems --- src/systems/model_parsing.jl | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/systems/model_parsing.jl b/src/systems/model_parsing.jl index 61edc394b2..8e9415761b 100644 --- a/src/systems/model_parsing.jl +++ b/src/systems/model_parsing.jl @@ -55,7 +55,8 @@ function _model_macro(mod, fullname::Union{Expr, Symbol}, expr, isconnector) dict = Dict{Symbol, Any}( :defaults => Dict{Symbol, Any}(), :kwargs => Dict{Symbol, Dict}(), - :structural_parameters => Dict{Symbol, Dict}() + :structural_parameters => Dict{Symbol, Dict}(), + :metadata => Dict{Symbol, Any}() ) comps = Union{Symbol, Expr}[] ext = [] @@ -678,6 +679,8 @@ function parse_model!(exprs, comps, ext, eqs, icon, vs, ps, sps, c_evts, d_evts, parse_costs!(costs, dict, body) elseif mname == Symbol("@consolidate") parse_consolidate!(body, dict) + elseif mname == Symbol("@metadata") + parse_metadata_block!(body, dict, mod) else error("$mname is not handled.") end @@ -1254,6 +1257,24 @@ function parse_description!(body, dict) end end +function parse_metadata_block!(body, dict, mod) + Base.remove_linenums!(body) + for arg in body.args + MLStyle.@match arg begin + Expr(:(=), a, b) => begin + @show esc(b) + # dict[:metadata][a] = get_var(mod, b) + dict[:metadata][a] = Core.eval(mod, b) + end + Expr(:call, :(=>), a, b) => begin + # dict[:metadata][a] = get_var(mod, b) + dict[:metadata][a] = Core.eval(mod, b) + end + _ => error("Invalid metadata entry: $arg. Expected key = value or key => value format.") + end + end +end + ### Parsing Components: function component_args!(a, b, varexpr, kwargs; index_name = nothing) From 3329f26264c542750569daabbade11bd65e9f31e Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Wed, 13 Aug 2025 16:50:25 +0530 Subject: [PATCH 2/5] chore: rm unused lines --- src/systems/model_parsing.jl | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/systems/model_parsing.jl b/src/systems/model_parsing.jl index 8e9415761b..9389da412d 100644 --- a/src/systems/model_parsing.jl +++ b/src/systems/model_parsing.jl @@ -1262,13 +1262,10 @@ function parse_metadata_block!(body, dict, mod) for arg in body.args MLStyle.@match arg begin Expr(:(=), a, b) => begin - @show esc(b) - # dict[:metadata][a] = get_var(mod, b) - dict[:metadata][a] = Core.eval(mod, b) + dict[:metadata][a] = get_var(mod, b) end Expr(:call, :(=>), a, b) => begin - # dict[:metadata][a] = get_var(mod, b) - dict[:metadata][a] = Core.eval(mod, b) + dict[:metadata][a] = get_var(mod, b) end _ => error("Invalid metadata entry: $arg. Expected key = value or key => value format.") end From 521d58a47b02d8424f1b0e4aa43471bf4e14343a Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Thu, 21 Aug 2025 20:39:14 +0530 Subject: [PATCH 3/5] chore: add setmetadata to exprs while returning --- src/systems/model_parsing.jl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/systems/model_parsing.jl b/src/systems/model_parsing.jl index 9389da412d..699cfee8fd 100644 --- a/src/systems/model_parsing.jl +++ b/src/systems/model_parsing.jl @@ -128,6 +128,7 @@ function _model_macro(mod, fullname::Union{Expr, Symbol}, expr, isconnector) consolidate = get(dict, :consolidate, default_consolidate) description = get(dict, :description, "") + model_meta = get(dict, :metadata, Dict{Symbol, Any}()) @inline pop_structure_dict!.( Ref(dict), [:defaults, :kwargs, :structural_parameters]) @@ -146,6 +147,14 @@ function _model_macro(mod, fullname::Union{Expr, Symbol}, expr, isconnector) isconnector && push!(exprs.args, :($Setfield.@set!(var"#___sys___".connector_type=$connector_type(var"#___sys___")))) + meta_exprs = quote + for (k, v) in $model_meta + var"#___sys___" = setmetadata(var"#___sys___", $get_var($mod, k), v) + end + end + push!(exprs.args, meta_exprs) + push!(exprs.args, :(var"#___sys___")) + f = if length(where_types) == 0 :($(Symbol(:__, name, :__))(; name, $(kwargs...)) = $exprs) else From e588a254ad5a08d1a71c979ccdd46fd124e5c285 Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Thu, 21 Aug 2025 20:39:39 +0530 Subject: [PATCH 4/5] test: metadata accessible from model --- test/model_parsing.jl | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/test/model_parsing.jl b/test/model_parsing.jl index c48628b007..b63577df15 100644 --- a/test/model_parsing.jl +++ b/test/model_parsing.jl @@ -1045,3 +1045,41 @@ end @test Example.structure[:constraints] == ["(EvalAt(0.3))(x) ~ 3", "y ≲ 4"] @test Example.structure[:costs] == ["x + y", "(EvalAt(1))(y) ^ 2"] end + +@testset "Model Level Metadata" begin + struct Author end + struct MyVersion end + struct License end + struct Category end + struct Tags end + + @mtkmodel TestMetadataModel begin + @metadata begin + Author = "Test Author" + MyVersion = "1.0.0" + License = "MIT" + Category => "example" + Tags = ["test", "demo", "metadata"] + end + + @parameters begin + k = 1.0, [description = "Gain parameter"] + end + + @variables begin + x(t), [description = "State variable"] + y(t), [description = "Output variable"] + end + + @equations begin + D(x) ~ -k * x + y ~ x + end + end + @named test_model = TestMetadataModel() + + struct UnknownMetaKey end + @test ModelingToolkit.getmetadata(test_model, Author, nothing) == "Test Author" + @test ModelingToolkit.getmetadata(test_model, MyVersion, nothing) == "1.0.0" + @test ModelingToolkit.getmetadata(test_model, UnknownMetaKey, nothing) === nothing +end From 1a46ff6acbf77434633cf59a8a463f9f3ab915f6 Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Mon, 25 Aug 2025 18:53:58 +0530 Subject: [PATCH 5/5] test: check return types for metadata --- test/model_parsing.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/model_parsing.jl b/test/model_parsing.jl index b63577df15..05f539d3de 100644 --- a/test/model_parsing.jl +++ b/test/model_parsing.jl @@ -1052,6 +1052,8 @@ end struct License end struct Category end struct Tags end + struct MyBool end + struct NewInt end @mtkmodel TestMetadataModel begin @metadata begin @@ -1060,6 +1062,8 @@ end License = "MIT" Category => "example" Tags = ["test", "demo", "metadata"] + MyBool => false + NewInt => 1 end @parameters begin @@ -1082,4 +1086,6 @@ end @test ModelingToolkit.getmetadata(test_model, Author, nothing) == "Test Author" @test ModelingToolkit.getmetadata(test_model, MyVersion, nothing) == "1.0.0" @test ModelingToolkit.getmetadata(test_model, UnknownMetaKey, nothing) === nothing + @test ModelingToolkit.getmetadata(test_model, MyBool, nothing) === false + @test ModelingToolkit.getmetadata(test_model, NewInt, nothing) === 1 end