From 81407cf3c148d377454324dc14ce1dafc7d81d55 Mon Sep 17 00:00:00 2001 From: "Anthony D. Blaom" Date: Tue, 3 Feb 2026 09:30:38 +1300 Subject: [PATCH 1/7] extend JSON = "0.21,1" --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 203dd20..6e73871 100644 --- a/Project.toml +++ b/Project.toml @@ -15,7 +15,7 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" [compat] Base64 = "1.0" HTTP = "1.0" -JSON = "0.21" +JSON = "0.21,1" ShowCases = "0.1" URIs = "1.0" julia = "1.0" From 3e53f4c3fed61f0d71d7cf5bd8583a906c037699 Mon Sep 17 00:00:00 2001 From: "Anthony D. Blaom" Date: Tue, 3 Feb 2026 10:08:35 +1300 Subject: [PATCH 2/7] address a JSON breakage --- src/types/run.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/run.jl b/src/types/run.jl index 38143a6..5eeabd0 100644 --- a/src/types/run.jl +++ b/src/types/run.jl @@ -139,6 +139,6 @@ struct Run inputs::RunInputs outputs::RunOutputs end -Run(data::Dict{String,Any}) = Run(RunInfo(data["info"]), RunData(data["data"]), +Run(data::AbstractDict{String}) = Run(RunInfo(data["info"]), RunData(data["data"]), RunInputs(data["inputs"]), RunOutputs(data["outputs"])) Base.show(io::IO, t::Run) = show(io, ShowCase(t, new_lines=true)) From b56f9dd0b9615da3aec688c64b222927880159ae Mon Sep 17 00:00:00 2001 From: "Anthony D. Blaom" Date: Wed, 4 Feb 2026 12:08:53 +1300 Subject: [PATCH 3/7] improve err mssg in testing for unset MLJFLOW_TRACKING_URI --- test/runtests.jl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index 1a0d314..4400ddc 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,5 +1,9 @@ if ~haskey(ENV, "MLFLOW_TRACKING_URI") - error("WARNING: MLFLOW_TRACKING_URI is not set. To run this tests, you need to set the URI of your MLFlow server API") + error( + "WARNING: MLFLOW_TRACKING_URI is not set. To run tests, "* + "you need to set thito the URI of your MLFlow server API. "* + "It's value will look something like \"http://localhost:5000/api\". " + ) end include("base.jl") From af2b468b623f92515d83b4ab9a286157bd342c7e Mon Sep 17 00:00:00 2001 From: "Anthony D. Blaom" Date: Wed, 4 Feb 2026 12:47:22 +1300 Subject: [PATCH 4/7] fix more JSON breakages tidy up --- src/types/dataset.jl | 4 ++-- src/types/experiment.jl | 4 ++-- src/types/mlflow.jl | 8 ++++---- src/types/model.jl | 2 +- src/types/registered_model.jl | 6 +++--- src/types/run.jl | 12 ++++++------ src/types/tag.jl | 2 +- src/types/user.jl | 2 +- src/utils.jl | 2 +- test/runtests.jl | 5 +++-- 10 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/types/dataset.jl b/src/types/dataset.jl index 5ff967a..cdc5ed1 100644 --- a/src/types/dataset.jl +++ b/src/types/dataset.jl @@ -20,7 +20,7 @@ struct Dataset schema::Union{String,Nothing} profile::Union{String,Nothing} end -Dataset(data::Dict{String,Any}) = Dataset(data["name"], data["digest"], +Dataset(data::AbstractDict{String}) = Dataset(data["name"], data["digest"], data["source_type"], data["source"], get(data, "schema", nothing), get(data, "profile", nothing)) Base.show(io::IO, t::Dataset) = show(io, ShowCase(t, new_lines=true)) @@ -38,6 +38,6 @@ struct DatasetInput tags::Array{Tag} dataset::Dataset end -DatasetInput(data::Dict{String,Any}) = DatasetInput( +DatasetInput(data::AbstractDict{String}) = DatasetInput( [Tag(tag) for tag in get(data, "tags", [])], Dataset(data["dataset"])) Base.show(io::IO, t::DatasetInput) = show(io, ShowCase(t, new_lines=true)) diff --git a/src/types/experiment.jl b/src/types/experiment.jl index a4a4e5e..f3fdf31 100644 --- a/src/types/experiment.jl +++ b/src/types/experiment.jl @@ -20,7 +20,7 @@ struct Experiment creation_time::Int64 tags::Array{Tag} end -Experiment(data::Dict{String,Any}) = Experiment(data["experiment_id"], data["name"], +Experiment(data::AbstractDict{String}) = Experiment(data["experiment_id"], data["name"], data["artifact_location"], data["lifecycle_stage"], data["last_update_time"], data["creation_time"], [Tag(tag) for tag in get(data, "tags", [])]) Base.show(io::IO, t::Experiment) = show(io, ShowCase(t, new_lines=true)) @@ -38,6 +38,6 @@ struct ExperimentPermission user_id::String permission::Permission.PermissionEnum end -ExperimentPermission(data::Dict{String,Any}) = ExperimentPermission(data["experiment_id"], +ExperimentPermission(data::AbstractDict{String}) = ExperimentPermission(data["experiment_id"], data["user_id"] |> string, Permission.parse(data["permission"])) Base.show(io::IO, t::ExperimentPermission) = show(io, ShowCase(t, new_lines=true)) diff --git a/src/types/mlflow.jl b/src/types/mlflow.jl index 9848047..65f7c96 100644 --- a/src/types/mlflow.jl +++ b/src/types/mlflow.jl @@ -6,7 +6,7 @@ Base type which defines location and version for MLFlow API service. # Fields - `apiroot::String`: API root URL, e.g. `http://localhost:5000/api` - `apiversion::Union{Integer, AbstractFloat}`: used API version, e.g. `2.0` -- `headers::Dict`: HTTP headers to be provided with the REST API requests. +- `headers::AbstractDict`: HTTP headers to be provided with the REST API requests. - `username::Union{Nothing, String}`: username for basic authentication. - `password::Union{Nothing, String}`: password for basic authentication. @@ -34,7 +34,7 @@ mlf = MLFlow(remote_url, headers=Dict("Authorization" => "Bearer ModelVersionStatus.parse, diff --git a/src/types/registered_model.jl b/src/types/registered_model.jl index a046756..df32dc1 100644 --- a/src/types/registered_model.jl +++ b/src/types/registered_model.jl @@ -11,7 +11,7 @@ struct RegisteredModelAlias alias::String version::String end -RegisteredModelAlias(data::Dict{String,Any}) = RegisteredModelAlias(data["alias"], +RegisteredModelAlias(data::AbstractDict{String}) = RegisteredModelAlias(data["alias"], data["version"]) Base.show(io::IO, t::RegisteredModelAlias) = show(io, ShowCase(t, new_lines=true)) @@ -45,7 +45,7 @@ struct RegisteredModel deployment_job_id::Union{String,Nothing} deployment_job_state::Union{State.StateEnum,Nothing} end -RegisteredModel(data::Dict{String,Any}) = RegisteredModel(data["name"], +RegisteredModel(data::AbstractDict{String}) = RegisteredModel(data["name"], data["creation_timestamp"], data["last_updated_timestamp"], get(data, "user_id", nothing), get(data, "description", nothing), [ModelVersion(version) for version in get(data, "latest_versions", [])], @@ -68,6 +68,6 @@ struct RegisteredModelPermission user_id::String permission::Permission.PermissionEnum end -RegisteredModelPermission(data::Dict{String,Any}) = RegisteredModelPermission(data["name"], +RegisteredModelPermission(data::AbstractDict{String}) = RegisteredModelPermission(data["name"], data["user_id"] |> string, Permission.parse(data["permission"])) Base.show(io::IO, t::RegisteredModelPermission) = show(io, ShowCase(t, new_lines=true)) diff --git a/src/types/run.jl b/src/types/run.jl index 5eeabd0..4403b41 100644 --- a/src/types/run.jl +++ b/src/types/run.jl @@ -15,7 +15,7 @@ struct Metric <: LoggingData timestamp::Int64 step::Union{Int64,Nothing} end -Metric(data::Dict{String,Any}) = Metric(data["key"], data["value"], data["timestamp"], +Metric(data::AbstractDict{String}) = Metric(data["key"], data["value"], data["timestamp"], data["step"]) Base.show(io::IO, t::Metric) = show(io, ShowCase(t, new_lines=true)) @@ -32,7 +32,7 @@ struct Param <: LoggingData key::String value::String end -Param(data::Dict{String,Any}) = Param(data["key"], data["value"]) +Param(data::AbstractDict{String}) = Param(data["key"], data["value"]) Base.show(io::IO, t::Param) = show(io, ShowCase(t, new_lines=true)) """ @@ -64,7 +64,7 @@ struct RunInfo artifact_uri::String lifecycle_stage::String end -RunInfo(data::Dict{String,Any}) = RunInfo(data["run_id"], data["run_name"], +RunInfo(data::AbstractDict{String}) = RunInfo(data["run_id"], data["run_name"], data["experiment_id"], RunStatus.parse(data["status"]), data["start_time"], get(data, "end_time", nothing), data["artifact_uri"], data["lifecycle_stage"]) Base.show(io::IO, t::RunInfo) = show(io, ShowCase(t, new_lines=true)) @@ -84,7 +84,7 @@ struct RunData params::Array{Param} tags::Array{Tag} end -RunData(data::Dict{String,Any}) = RunData( +RunData(data::AbstractDict{String}) = RunData( [Metric(metric) for metric in get(data, "metrics", [])], [Param(param) for param in get(data, "params", [])], [Tag(tag) for tag in get(data, "tags", [])]) @@ -102,7 +102,7 @@ struct RunInputs dataset_inputs::Array{DatasetInput} model_inputs::Array{ModelInput} end -RunInputs(data::Dict{String,Any}) = RunInputs( +RunInputs(data::AbstractDict{String}) = RunInputs( [DatasetInput(dataset_input) for dataset_input in get(data, "dataset_inputs", [])], [ModelInput(model_input) for model_input in get(data, "model_inputs", [])]) Base.show(io::IO, t::RunInputs) = show(io, ShowCase(t, new_lines=true)) @@ -118,7 +118,7 @@ Outputs of a [`Run`](@ref). struct RunOutputs model_outputs::Array{ModelOutput} end -RunOutputs(data::Dict{String,Any}) = RunOutputs( +RunOutputs(data::AbstractDict{String}) = RunOutputs( [ModelOutput(model_output) for model_output in get(data, "model_outputs", [])]) Base.show(io::IO, t::RunOutputs) = show(io, ShowCase(t, new_lines=true)) diff --git a/src/types/tag.jl b/src/types/tag.jl index 5eae9af..6ff976b 100644 --- a/src/types/tag.jl +++ b/src/types/tag.jl @@ -11,5 +11,5 @@ struct Tag <: LoggingData key::String value::String end -Tag(data::Dict{String,Any})::Tag = Tag(data["key"], data["value"] |> string) +Tag(data::AbstractDict{String})::Tag = Tag(data["key"], data["value"] |> string) Base.show(io::IO, t::Tag) = show(io, ShowCase(t, new_lines=true)) diff --git a/src/types/user.jl b/src/types/user.jl index 038ffae..0148292 100644 --- a/src/types/user.jl +++ b/src/types/user.jl @@ -17,7 +17,7 @@ struct User experiment_permissions::Array{ExperimentPermission} registered_model_permissions::Array{RegisteredModelPermission} end -User(data::Dict{String,Any}) = User(data["id"] |> string, data["username"], data["is_admin"], +User(data::AbstractDict{String}) = User(data["id"] |> string, data["username"], data["is_admin"], [ExperimentPermission(permission) for permission in get(data, "experiment_permissions", [])], [RegisteredModelPermission(permission) for permission in get(data, "registered_model_permissions", [])]) Base.show(io::IO, t::User) = show(io, ShowCase(t, new_lines=true)) diff --git a/src/utils.jl b/src/utils.jl index 7543b4c..22ff298 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -4,7 +4,7 @@ const MLFlowUpsertData{T} = Union{Array{T},Array{<:Dict{String,<:Any}}, Array{<:Tuple{String,<:NumberOrString}}} function dict_to_T_array(::Type{T}, - dict::Dict{String,<:NumberOrString}) where {T<:LoggingData} + dict::AbstractDict{String,<:NumberOrString}) where {T<:LoggingData} entities = T[] for (key, value) in dict if T <: Metric diff --git a/test/runtests.jl b/test/runtests.jl index 4400ddc..7174e1d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,8 +1,9 @@ if ~haskey(ENV, "MLFLOW_TRACKING_URI") error( "WARNING: MLFLOW_TRACKING_URI is not set. To run tests, "* - "you need to set thito the URI of your MLFlow server API. "* - "It's value will look something like \"http://localhost:5000/api\". " + "you need to set this to the URI of your MLFlow server API. "* + "Setting this in Julia will look something like\n"* + "`ENV[\"MLFLOW_TRACKING_URI\"] = \"http://127.0.0.1:5000/api\"` " ) end From 73a5e023f07b43fc59a563fb5a18448a9615f1e2 Mon Sep 17 00:00:00 2001 From: "Anthony D. Blaom" Date: Wed, 4 Feb 2026 13:15:15 +1300 Subject: [PATCH 5/7] add julia 1.11 to CI --- .github/workflows/CI.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 8321a06..21d6753 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -15,6 +15,7 @@ jobs: matrix: version: - '1.10' + - '1.11' - '1' # automatically expands to the latest stable 1.x release of Julia. os: - ubuntu-latest From d5c42f36aafb03c85025d1c423bd1a1384da0081 Mon Sep 17 00:00:00 2001 From: "Anthony D. Blaom" Date: Wed, 4 Feb 2026 13:42:48 +1300 Subject: [PATCH 6/7] update readme to warn users against using MLflow > 3.2.0 --- Project.toml | 2 +- README.md | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index 6e73871..9cf8a4b 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MLFlowClient" uuid = "64a0f543-368b-4a9a-827a-e71edb2a0b83" authors = ["@deyandyankov, @pebeto, and contributors"] -version = "0.7.0" +version = "0.7.1" [deps] Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" diff --git a/README.md b/README.md index 78f9e16..6aa5067 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,9 @@ [![Build Status](https://github.com/JuliaAI/MLFlowClient.jl/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/JuliaAI/MLFlowClient.jl/actions/workflows/CI.yml?query=branch%3Amain) [![Coverage](https://codecov.io/gh/JuliaAI/MLFlowClient.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/JuliaAI/MLFlowClient.jl) -Julia client for [MLFlow](https://www.mlflow.org/) `3.2.0` (but should work with other versions as well). +Julia client for [MLFlow](https://www.mlflow.org/) `3.2.0`. Use with later versions at +your own risk. For example, there is [this known +issue](https://github.com/JuliaIO/JSON.jl/issues/432). - [x] Supports tracking of metrics, parameters, tags, artifacts, and models. - [x] Compatible with latest MLFlow server capabilities. From 9b97bf46f28869818564b3ae314538912028e103 Mon Sep 17 00:00:00 2001 From: "Anthony D. Blaom" Date: Wed, 4 Feb 2026 14:03:48 +1300 Subject: [PATCH 7/7] fix link in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6aa5067..6ebcd0d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Julia client for [MLFlow](https://www.mlflow.org/) `3.2.0`. Use with later versions at your own risk. For example, there is [this known -issue](https://github.com/JuliaIO/JSON.jl/issues/432). +issue](https://github.com/JuliaAI/MLFlowClient.jl/issues/76). - [x] Supports tracking of metrics, parameters, tags, artifacts, and models. - [x] Compatible with latest MLFlow server capabilities.