From 943c590b81e9cf581ab2af95beff3f05b44fcbfc Mon Sep 17 00:00:00 2001 From: Simone Carlo Surace Date: Thu, 30 Oct 2025 17:19:03 +0100 Subject: [PATCH 1/3] Move JLD2.jl dependency to a package extension --- Project.toml | 12 +++++-- ext/MetaGraphsJLD2Ext.jl | 74 +++++++++++++++++++++++++++++++++++++++ src/MetaGraphs.jl | 1 - src/persistence.jl | 75 ++++++---------------------------------- test/runtests.jl | 2 ++ 5 files changed, 96 insertions(+), 68 deletions(-) create mode 100644 ext/MetaGraphsJLD2Ext.jl diff --git a/Project.toml b/Project.toml index 656bea6..6356475 100644 --- a/Project.toml +++ b/Project.toml @@ -1,12 +1,17 @@ name = "MetaGraphs" uuid = "626554b9-1ddb-594c-aa3c-2596fe9399a5" -version = "0.8.1" +version = "0.9.0" [deps] Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" -JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +[weakdeps] +JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" + +[extensions] +MetaGraphsJLD2Ext = ["Graphs", "JLD2"] + [compat] Graphs = "1.4" JLD2 = "0.1.11, 0.2, 0.3, 0.4, 0.5, 0.6" @@ -14,7 +19,8 @@ julia = "1" [extras] Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" +JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Test", "Base64"] +test = ["Test", "Base64", "JLD2"] diff --git a/ext/MetaGraphsJLD2Ext.jl b/ext/MetaGraphsJLD2Ext.jl new file mode 100644 index 0000000..8f5d5fd --- /dev/null +++ b/ext/MetaGraphsJLD2Ext.jl @@ -0,0 +1,74 @@ +module MetaGraphsJLD2Ext + +using Graphs +using JLD2 +using MetaGraphs + +function MetaGraphs.loadmg(fn::AbstractString) + @load fn g + return g +end + +function MetaGraphs.savemg(fn::AbstractString, g::AbstractMetaGraph) + @save fn g + return 1 +end + +# escaping unescaped quotation marks +# i.e. replacing `"`` with `\"` while leaving `\"` as is +escape_quotes(s::AbstractString) = replace(s, r"([^\\])\"" => s"\1\\\\\"") + +# According to the DOT language specification https://graphviz.org/doc/info/lang.html +# we can quote everyhthing that's not an XML/HTML literal +function quote_prop(p::AbstractString) + if occursin(r"<+.*>+$", p) + # The label is an HTML string, no additional quotes here. + return p + else + return "\"" * escape_quotes(p) * "\"" + end +end +# if the property value is _not_ a string it cannot be XML/HTML literal, so just put it in quotes +quote_prop(p::Any) = "\"" * escape_quotes(string(p)) * "\"" +# NOTE: down there I only quote property _values_. DOT allows quoting property _names_ too +# I don't do that as long as names are Symbols and can't have spaces and commas and stuff. +# That will break if someone uses a DOT keyword as a property name, as they must be quoted. + +function MetaGraphs.savedot(io::IO, g::AbstractMetaGraph) + if is_directed(g) + write(io, "digraph G {\n") + dash = "->" + else + write(io, "graph G {\n") + dash = "--" + end + + for p in props(g) + write(io, "$(p[1])=$(quote_prop(p[2]));\n") + end + + for v in vertices(g) + write(io, "$v") + if length(props(g, v)) > 0 + write(io, " [ ") + + for p in props(g, v) + write(io, "$(p[1])=$(quote_prop(p[2])), ") + end + + write(io, "];") + end + write(io, "\n") + end + + for e in edges(g) + write(io, "$(src(e)) $dash $(dst(e)) [ ") + for p in props(g,e) + write(io, "$(p[1])=$(quote_prop(p[2])), ") + end + write(io, "]\n") + end + write(io, "}\n") +end + +end \ No newline at end of file diff --git a/src/MetaGraphs.jl b/src/MetaGraphs.jl index 06c3b3a..1be7b54 100644 --- a/src/MetaGraphs.jl +++ b/src/MetaGraphs.jl @@ -1,6 +1,5 @@ module MetaGraphs using Graphs -using JLD2 import Base: eltype, show, ==, Pair, diff --git a/src/persistence.jl b/src/persistence.jl index 7f25788..cb4f495 100644 --- a/src/persistence.jl +++ b/src/persistence.jl @@ -3,76 +3,23 @@ struct MGFormat <: AbstractGraphFormat end struct DOTFormat <: AbstractGraphFormat end -function loadmg(fn::AbstractString) - @load fn g - return g +function loadmg(args...) + error("In order to load static graphs from binary files, you need to load the JLD2.jl \ + package") end -function savemg(fn::AbstractString, g::AbstractMetaGraph) - @save fn g - return 1 +function savemg(args...) + error("In order to save static graphs to binary files, you need to load the JLD2.jl \ + package") end -loadgraph(fn::AbstractString, gname::String, ::MGFormat) = loadmg(fn) -savegraph(fn::AbstractString, g::AbstractMetaGraph) = savemg(fn, g) - -# escaping unescaped quotation marks -# i.e. replacing `"`` with `\"` while leaving `\"` as is -escape_quotes(s::AbstractString) = replace(s, r"([^\\])\"" => s"\1\\\\\"") - -# According to the DOT language specification https://graphviz.org/doc/info/lang.html -# we can quote everyhthing that's not an XML/HTML literal -function quote_prop(p::AbstractString) - if occursin(r"<+.*>+$", p) - # The label is an HTML string, no additional quotes here. - return p - else - return "\"" * escape_quotes(p) * "\"" - end +function savedot(args...) + error("In order to save static graphs to binary files, you need to load the JLD2.jl \ + package") end -# if the property value is _not_ a string it cannot be XML/HTML literal, so just put it in quotes -quote_prop(p::Any) = "\"" * escape_quotes(string(p)) * "\"" -# NOTE: down there I only quote property _values_. DOT allows quoting property _names_ too -# I don't do that as long as names are Symbols and can't have spaces and commas and stuff. -# That will break if someone uses a DOT keyword as a property name, as they must be quoted. - -function savedot(io::IO, g::AbstractMetaGraph) - - if is_directed(g) - write(io, "digraph G {\n") - dash = "->" - else - write(io, "graph G {\n") - dash = "--" - end - - for p in props(g) - write(io, "$(p[1])=$(quote_prop(p[2]));\n") - end - - for v in vertices(g) - write(io, "$v") - if length(props(g, v)) > 0 - write(io, " [ ") - for p in props(g, v) - write(io, "$(p[1])=$(quote_prop(p[2])), ") - end - - write(io, "];") - end - write(io, "\n") - end - - for e in edges(g) - write(io, "$(src(e)) $dash $(dst(e)) [ ") - for p in props(g,e) - write(io, "$(p[1])=$(quote_prop(p[2])), ") - end - write(io, "]\n") - end - write(io, "}\n") -end +loadgraph(fn::AbstractString, ::String, ::MGFormat) = loadmg(fn) +savegraph(fn::AbstractString, g::AbstractMetaGraph) = savemg(fn, g) function savegraph(fn::AbstractString, g::AbstractMetaGraph, ::DOTFormat) open(fn, "w") do fp diff --git a/test/runtests.jl b/test/runtests.jl index d562e53..2afed68 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,5 +1,7 @@ using Graphs using MetaGraphs + +using JLD2 using Test import Graphs.SimpleGraphs: SimpleGraph, SimpleDiGraph From 9ea2746c67544a526596d1d2fb3e5c98d2d86777 Mon Sep 17 00:00:00 2001 From: Simone Carlo Surace Date: Sat, 1 Nov 2025 11:31:32 +0100 Subject: [PATCH 2/3] Set compat and CI to Julia LTS version --- .github/workflows/ci.yml | 2 +- Project.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d41252..e9a4317 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: - version: '1' os: ubuntu-latest arch: x64 - - version: '1.5' + - version: '1.10' os: ubuntu-latest arch: x64 - version: 'nightly' diff --git a/Project.toml b/Project.toml index 6356475..eedf346 100644 --- a/Project.toml +++ b/Project.toml @@ -15,7 +15,7 @@ MetaGraphsJLD2Ext = ["Graphs", "JLD2"] [compat] Graphs = "1.4" JLD2 = "0.1.11, 0.2, 0.3, 0.4, 0.5, 0.6" -julia = "1" +julia = "1.10" [extras] Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" From ea2141eb10cfff7169f48331343391374d347c1f Mon Sep 17 00:00:00 2001 From: Simone Carlo Surace Date: Sat, 1 Nov 2025 11:35:15 +0100 Subject: [PATCH 3/3] Use error hint instead of explicit error The latter will lead to invalidations when JLD2 is loaded --- src/MetaGraphs.jl | 16 ++++++++++++++++ src/persistence.jl | 17 +++-------------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/MetaGraphs.jl b/src/MetaGraphs.jl index 1be7b54..0d7c04a 100644 --- a/src/MetaGraphs.jl +++ b/src/MetaGraphs.jl @@ -581,4 +581,20 @@ include("metadigraph.jl") include("metagraph.jl") include("persistence.jl") include("overrides.jl") + +function __init__() + # Register error hint for the `loadmg`, `savemg`, and `savedot` functions + if isdefined(Base.Experimental, :register_error_hint) + Base.Experimental.register_error_hint(MethodError) do io, exc, _, _ + if exc.f === loadsg + print(io, "\n\nIn order to load meta graphs from binary files, you need \ + to load the JLD2.jl package.") + elseif exc.f === savesg + print(io,"\n\nIn order to save meta graphs to binary files, you need to \ + load the JLD2.jl package.") + end + end + end +end + end # module diff --git a/src/persistence.jl b/src/persistence.jl index cb4f495..23e21fc 100644 --- a/src/persistence.jl +++ b/src/persistence.jl @@ -3,20 +3,9 @@ struct MGFormat <: AbstractGraphFormat end struct DOTFormat <: AbstractGraphFormat end -function loadmg(args...) - error("In order to load static graphs from binary files, you need to load the JLD2.jl \ - package") -end - -function savemg(args...) - error("In order to save static graphs to binary files, you need to load the JLD2.jl \ - package") -end - -function savedot(args...) - error("In order to save static graphs to binary files, you need to load the JLD2.jl \ - package") -end +function loadmg end +function savemg end +function savedot end loadgraph(fn::AbstractString, ::String, ::MGFormat) = loadmg(fn) savegraph(fn::AbstractString, g::AbstractMetaGraph) = savemg(fn, g)