From 16e2dcb9ece81d8ff967edee713ac8887b349519 Mon Sep 17 00:00:00 2001 From: deyandyankov Date: Fri, 19 Nov 2021 12:27:53 +0000 Subject: [PATCH 1/9] #7 - getorcreateexperiment method. --- docs/src/reference.md | 1 + src/MLFlowClient.jl | 1 + src/experiments.jl | 59 +++++++++++++++++++++++++++++++++++++++---- test/runtests.jl | 20 ++++++++++++--- 4 files changed, 73 insertions(+), 8 deletions(-) diff --git a/docs/src/reference.md b/docs/src/reference.md index 5392cdb..4af2ed3 100644 --- a/docs/src/reference.md +++ b/docs/src/reference.md @@ -21,6 +21,7 @@ MLFlowRunStatus ```@docs createexperiment getexperiment +getorcreateexperiment listexperiments deleteexperiment ``` diff --git a/src/MLFlowClient.jl b/src/MLFlowClient.jl index 510df23..a1a5043 100644 --- a/src/MLFlowClient.jl +++ b/src/MLFlowClient.jl @@ -34,6 +34,7 @@ include("experiments.jl") export createexperiment, getexperiment, + getorcreateexperiment, deleteexperiment, listexperiments diff --git a/src/experiments.jl b/src/experiments.jl index f99b45a..7a2325f 100644 --- a/src/experiments.jl +++ b/src/experiments.jl @@ -10,7 +10,7 @@ Creates an MLFlow experiment. - `tags`: a Dictionary of key-values which tag the experiment. # Returns -Experiment identifier (integer). +An object of type [`MLFlowExperiment`](@ref). """ function createexperiment(mlf::MLFlow; name=missing, artifact_location=missing, tags=missing) @@ -19,7 +19,8 @@ function createexperiment(mlf::MLFlow; name=missing, artifact_location=missing, name = string(UUIDs.uuid4()) end result = mlfpost(mlf, endpoint; name=name, artifact_location=artifact_location, tags=tags) - parse(Int, result["experiment_id"]) + experiment_id = parse(Int, result["experiment_id"]) + getexperiment(mlf, experiment_id) end """ @@ -82,18 +83,66 @@ function _getexperimentbyname(mlf::MLFlow, experiment_name::String) end """ - deleteexperiment(mlf::MLFlow, experiment_id) + getorcreateexperiment(mlf::MLFlow, experiment_name::String) + +Gets an experiment if one alrady exists, or creates a new one. + +# Arguments +- `mlf`: [`MLFlow`](@ref) configuration. +- `experiment_name`: Experiment name. + +# Returns +An instance of type [`MLFlowExperiment`](@ref) + +""" +function getorcreateexperiment(mlf::MLFlow, experiment_name::String) + exp = getexperiment(mlf, experiment_name) + if ismissing(exp) + exp = createexperiment(mlf, name=experiment_name) + end + exp +end + +""" + deleteexperiment(mlf::MLFlow, experiment_id::Integer) Deletes an MLFlow experiment. # Arguments - `mlf`: [`MLFlow`](@ref) configuration. - `experiment_id`: experiment identifier. + +# Returns + +`true` if successful. Otherwise, raises exception. """ -function deleteexperiment(mlf::MLFlow, experiment_id) +function deleteexperiment(mlf::MLFlow, experiment_id::Integer) endpoint = "experiments/delete" - mlfpost(mlf, endpoint; experiment_id=experiment_id) + try + result = mlfpost(mlf, endpoint; experiment_id=experiment_id) + catch e + if isa(e, HTTP.ExceptionRequest.StatusError) && e.status == 404 + # experiment already deleted + return true + end + throw(e) + end + true end +""" + deleteexperiment(mlf::MLFlow, experiment::MLFlowExperiment) + +Deletes an MLFlow experiment. + +# Arguments +- `mlf`: [`MLFlow`](@ref) configuration. +- `experiment`: an object of type [`MLFlowExperiment`](@ref) + +Dispatches to `deleteexperiment(mlf::MLFlow, experiment_id::Integer)`. + +""" +deleteexperiment(mlf::MLFlow, experiment::MLFlowExperiment) = + deleteexperiment(mlf, experiment.experiment_id) """ listexperiments(mlf::MLFlow) diff --git a/test/runtests.jl b/test/runtests.jl index b624966..4f10c5c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -27,9 +27,8 @@ end @test ismissing(getexperiment(mlf, "$(UUIDs.uuid4()) - $(UUIDs.uuid4())")) - experiment_id = createexperiment(mlf; name=expname, tags=exptags) - experiment = getexperiment(mlf, experiment_id) - @test experiment.experiment_id == experiment_id + experiment = createexperiment(mlf; name=expname, tags=exptags) + experiment_id = experiment.experiment_id experimentbyname = getexperiment(mlf, expname) @test experimentbyname.name == experiment.name @@ -92,3 +91,18 @@ end @test experiment.experiment_id == experiment_id @test experiment.lifecycle_stage == "deleted" end + +@testset "getorcreateexperiment" begin + mlflowbaseuri = "http://localhost:5000" + mlf = MLFlow(mlflowbaseuri) + !mlflow_server_is_running(mlf) && return nothing + + expname = "getorcreate-$(UUIDs.uuid4())" + expname = "getorcreate" + e = getorcreateexperiment(mlf, expname) + @test isa(e, MLFlowExperiment) + ee = getorcreateexperiment(mlf, expname) + @test isa(ee, MLFlowExperiment) + @test e === ee + deleteexperiment(mlf, ee) +end From b900fd2d441b945ab0bbcb1f0753b6027aac12e7 Mon Sep 17 00:00:00 2001 From: deyandyankov Date: Fri, 19 Nov 2021 12:43:09 +0000 Subject: [PATCH 2/9] Improve coverage --- test/runtests.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index 4f10c5c..0ca4eaa 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -104,5 +104,6 @@ end ee = getorcreateexperiment(mlf, expname) @test isa(ee, MLFlowExperiment) @test e === ee - deleteexperiment(mlf, ee) + @test deleteexperiment(mlf, ee) + @test deleteexperiment(mlf, ee) end From 0884ad51d7f5da7b79d8f1ea20b7f04b88cb1b2c Mon Sep 17 00:00:00 2001 From: deyandyankov Date: Fri, 19 Nov 2021 13:19:25 +0000 Subject: [PATCH 3/9] createrun() dispatch and MLFlow() defaults. --- src/runs.jl | 7 +++++++ src/types.jl | 5 ++++- test/runtests.jl | 29 +++++++++++++++++++---------- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/runs.jl b/src/runs.jl index 8d2a89f..21cf4a6 100644 --- a/src/runs.jl +++ b/src/runs.jl @@ -22,6 +22,13 @@ function createrun(mlf::MLFlow, experiment_id; start_time=missing, tags=missing) result = mlfpost(mlf, endpoint; experiment_id=experiment_id, start_time=string(start_time), tags=tags) MLFlowRun(result["run"]["info"], result["run"]["data"]) end +""" + createrun(mlf::MLFlow, experiment::MLFlowExperiment; start_time=missing, tags=missing) + +Dispatches to `createrun(mlf::MLFlow, experiment_id; start_time=start_time, tags=tags)` +""" +createrun(mlf::MLFlow, experiment::MLFlowExperiment; start_time=missing, tags=missing) = + createrun(mlf, experiment.experiment_id; start_time=start_time, tags=tags) """ getrun(mlf::MLFlow, run_id) diff --git a/src/types.jl b/src/types.jl index 878d42e..78c2acd 100644 --- a/src/types.jl +++ b/src/types.jl @@ -10,9 +10,11 @@ Base type which defines location and version for MLFlow API service. # Constructors - `MLFlow(baseuri; apiversion=2.0)` +- `MLFlow()` - defaults to `MLFlow("http://localhost:5000")` + # Examples ``` julia-repl -julia> mlf = MLFlow("http://localhost:5000") +julia> mlf = MLFlow() MLFlow("http://localhost:5000", 2.0) ``` @@ -22,6 +24,7 @@ struct MLFlow apiversion MLFlow(baseuri; apiversion=2.0) = new(baseuri, apiversion) end +MLFlow() = MLFlow("http://localhost:5000") """ MLFlowExperiment diff --git a/test/runtests.jl b/test/runtests.jl index 0ca4eaa..c67a2e7 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -12,15 +12,15 @@ function mlflow_server_is_running(mlf::MLFlow) end end -@testset "MLFlowClient.jl" begin - mlflowbaseuri = "http://localhost:5000" - mlf = MLFlow(mlflowbaseuri) - @test mlf.baseuri == mlflowbaseuri +@testset "MLFlow" begin + mlf = MLFlow() + @test mlf.baseuri == "http://localhost:5000" @test mlf.apiversion == 2.0 +end - if !mlflow_server_is_running(mlf) - return nothing - end +@testset "MLFlowClient.jl" begin + mlf = MLFlow() + !mlflow_server_is_running(mlf) && return nothing exptags = [:key => "val"] expname = "expname-$(UUIDs.uuid4())" @@ -92,12 +92,21 @@ end @test experiment.lifecycle_stage == "deleted" end -@testset "getorcreateexperiment" begin - mlflowbaseuri = "http://localhost:5000" - mlf = MLFlow(mlflowbaseuri) +@testset "createrun" begin + mlf = MLFlow() !mlflow_server_is_running(mlf) && return nothing expname = "getorcreate-$(UUIDs.uuid4())" + e = getorcreateexperiment(mlf, expname) + r = createrun(mlf, e.experiment_id) + @test isa(r, MLFlowRun) + rr = createrun(mlf, e) + @test isa(rr, MLFlowRun) +end +@testset "getorcreateexperiment" begin + mlf = MLFlow() + !mlflow_server_is_running(mlf) && return nothing + expname = "getorcreate" e = getorcreateexperiment(mlf, expname) @test isa(e, MLFlowExperiment) From 8cfc1b5af387d0e0178357ebd3999a1184080412 Mon Sep 17 00:00:00 2001 From: deyandyankov Date: Fri, 19 Nov 2021 13:20:33 +0000 Subject: [PATCH 4/9] more idiomatic testing conditions --- test/runtests.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index c67a2e7..15025c2 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -20,7 +20,7 @@ end @testset "MLFlowClient.jl" begin mlf = MLFlow() - !mlflow_server_is_running(mlf) && return nothing + mlflow_server_is_running(mlf) || return nothing exptags = [:key => "val"] expname = "expname-$(UUIDs.uuid4())" @@ -94,7 +94,7 @@ end @testset "createrun" begin mlf = MLFlow() - !mlflow_server_is_running(mlf) && return nothing + mlflow_server_is_running(mlf) || return nothing expname = "getorcreate-$(UUIDs.uuid4())" e = getorcreateexperiment(mlf, expname) @@ -105,7 +105,7 @@ end end @testset "getorcreateexperiment" begin mlf = MLFlow() - !mlflow_server_is_running(mlf) && return nothing + mlflow_server_is_running(mlf) || return nothing expname = "getorcreate" e = getorcreateexperiment(mlf, expname) From 3fbdf6fbb0649a8c3ec10da2ab5e8c8494ac0aa6 Mon Sep 17 00:00:00 2001 From: deyandyankov Date: Fri, 19 Nov 2021 19:42:48 +0000 Subject: [PATCH 5/9] skip tests if MLFlow not running, using a macro --- test/runtests.jl | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 15025c2..59d8e76 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -4,7 +4,6 @@ using UUIDs function mlflow_server_is_running(mlf::MLFlow) try - @info "Querying mlflow server at $mlf" response = MLFlowClient.mlfget(mlf, "experiments/list") return isa(response, Dict) catch e @@ -12,6 +11,16 @@ function mlflow_server_is_running(mlf::MLFlow) end end +# creates an instance of mlf +# skips test if mlflow is not available on default location, http://localhost:5000 +macro ensuremlf() + e = quote + mlf = MLFlow() + mlflow_server_is_running(mlf) || return nothing + end + eval(e) +end + @testset "MLFlow" begin mlf = MLFlow() @test mlf.baseuri == "http://localhost:5000" @@ -19,8 +28,7 @@ end end @testset "MLFlowClient.jl" begin - mlf = MLFlow() - mlflow_server_is_running(mlf) || return nothing + @ensuremlf exptags = [:key => "val"] expname = "expname-$(UUIDs.uuid4())" @@ -93,8 +101,7 @@ end end @testset "createrun" begin - mlf = MLFlow() - mlflow_server_is_running(mlf) || return nothing + @ensuremlf expname = "getorcreate-$(UUIDs.uuid4())" e = getorcreateexperiment(mlf, expname) @@ -103,10 +110,9 @@ end rr = createrun(mlf, e) @test isa(rr, MLFlowRun) end -@testset "getorcreateexperiment" begin - mlf = MLFlow() - mlflow_server_is_running(mlf) || return nothing +@testset "getorcreateexperiment" begin + @ensuremlf expname = "getorcreate" e = getorcreateexperiment(mlf, expname) @test isa(e, MLFlowExperiment) From 4b4bed6879644a73c33dd5591a286c078445b662 Mon Sep 17 00:00:00 2001 From: deyandyankov Date: Fri, 19 Nov 2021 22:02:05 +0000 Subject: [PATCH 6/9] logartifact now stores bytes objects; some test refactoring. --- Project.toml | 2 ++ src/MLFlowClient.jl | 1 + src/logging.jl | 59 ++++++++++++++++++++++++++++++++---- src/runs.jl | 5 ++++ test/runtests.jl | 73 +++++++++++++++++++++++++++++---------------- 5 files changed, 108 insertions(+), 32 deletions(-) diff --git a/Project.toml b/Project.toml index b5204e7..e5a4834 100644 --- a/Project.toml +++ b/Project.toml @@ -5,12 +5,14 @@ version = "0.1.0" [deps] Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" +FilePathsBase = "48062228-2e41-5def-b9a4-89aafe57970f" HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" URIs = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" [compat] +FilePathsBase = "0.9" HTTP = "0.9" JSON = "0.21" URIs = "1" diff --git a/src/MLFlowClient.jl b/src/MLFlowClient.jl index a1a5043..7e54e67 100644 --- a/src/MLFlowClient.jl +++ b/src/MLFlowClient.jl @@ -17,6 +17,7 @@ using UUIDs using HTTP using URIs using JSON +using FilePathsBase: AbstractPath include("types.jl") export diff --git a/src/logging.jl b/src/logging.jl index 62673c3..16ff6fd 100644 --- a/src/logging.jl +++ b/src/logging.jl @@ -62,7 +62,7 @@ end """ - logartifact(mlf::MLFlow, run, filename) + logartifact(mlf::MLFlow, run, basefilename, data) Stores an artifact (file) in the run's artifact location. @@ -73,13 +73,60 @@ Stores an artifact (file) in the run's artifact location. # Arguments - `mlf::MLFlow`: [`MLFlow`](@ref) onfiguration. Currently not used, but when this method is extended to support `S3`, information from `mlf` will be needed. - `run`: one of [`MLFlowRun`](@ref), [`MLFlowRunInfo`](@ref) or `String`. -- `filename`: path to the artifact that needs to be sent to `MLFlow`. +- `basefilename`: name of the file to be written. +- `data`: artifact content, an object that can be written directly to a file handle. + +# Throws +- an `ErrorException` if an exception occurs during writing artifact. + +# Returns + +path of the artifact that was created. """ -function logartifact(mlf::MLFlow, run_id::String, filename) +function logartifact(mlf::MLFlow, run_id::AbstractString, basefilename::AbstractString, data) mlflowrun = getrun(mlf, run_id) artifact_uri = mlflowrun.info.artifact_uri mkpath(artifact_uri) - cp(filename, joinpath(artifact_uri, basename(filename))) + filepath = joinpath(artifact_uri, basefilename) + try + f = open(filepath, "w") + write(f, data) + close(f) + catch e + error("Unable to create artifact $(filepath): $e") + end + filepath +end +logartifact(mlf::MLFlow, run::MLFlowRun, basefilename::AbstractString, data) = + logartifact(mlf, run.info, basefilename, data) +logartifact(mlf::MLFlow, run_info::MLFlowRunInfo, basefilename::AbstractString, data) = + logartifact(mlf, run_info.run_id, basefilename, data) + +""" + logartifact(mlf::MLFlow, run, filepath) + +Stores an artifact (file) in the run's artifact location. +The name of the artifact is calculated using `basename(filepath)`. + +Dispatches on `logartifact(mlf::MLFlow, run, basefilename, data)` where `data` is the contents of `filepath`. + +# Throws +- an `ErrorException` if `filepath` does not exist. +- an exception if such occurs while trying to read the contents of `filepath`. + +""" +function logartifact(mlf::MLFlow, run_id::AbstractString, filepath::Union{AbstractPath,AbstractString}) + isfile(filepath) || error("File $filepath does not exist.") + try + f = open(filepath, "r") + data = read(f) + close(f) + return logartifact(mlf, run_id, basename(filepath), data) + catch e + throw(e) + end end -logartifact(mlf::MLFlow, run::MLFlowRun, filename) = logartifact(mlf, run.info, filename) -logartifact(mlf::MLFlow, run_info::MLFlowRunInfo, filename) = logartifact(mlf, run_info.run_id, filename) +logartifact(mlf::MLFlow, run::MLFlowRun, filepath::Union{AbstractPath,AbstractString}) = + logartifact(mlf, run.info, filepath) +logartifact(mlf::MLFlow, run_info::MLFlowRunInfo, filepath::Union{AbstractPath,AbstractString}) = + logartifact(mlf, run_info.run_id, filepath) diff --git a/src/runs.jl b/src/runs.jl index 21cf4a6..167376e 100644 --- a/src/runs.jl +++ b/src/runs.jl @@ -94,10 +94,15 @@ Deletes an experiment's run. # Arguments - `mlf`: [`MLFlow`](@ref) configuration. - `run`: one of [`MLFlowRun`](@ref), [`MLFlowRunInfo`](@ref), or `String`. + +# Returns +`true` if successful. + """ function deleterun(mlf::MLFlow, run_id::String) endpoint = "runs/delete" mlfpost(mlf, endpoint; run_id=run_id) + true end deleterun(mlf::MLFlow, run_info::MLFlowRunInfo) = deleterun(mlf, run_info.run_id) deleterun(mlf::MLFlow, run::MLFlowRun) = deleterun(mlf, run.info) diff --git a/test/runtests.jl b/test/runtests.jl index 59d8e76..9e78a8c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -25,10 +25,50 @@ end mlf = MLFlow() @test mlf.baseuri == "http://localhost:5000" @test mlf.apiversion == 2.0 + mlf = MLFlow("https://localhost:5001", apiversion=3.0) + @test mlf.baseuri == "https://localhost:5001" + @test mlf.apiversion == 3.0 +end + +@testset "createexperiment" begin + @ensuremlf + exp = createexperiment(mlf) + @test isa(exp, MLFlowExperiment) + @test deleteexperiment(mlf, exp) + experiment = getexperiment(mlf, exp.experiment_id) + @test experiment.experiment_id == exp.experiment_id + @test experiment.lifecycle_stage == "deleted" +end + +@testset "createrun" begin + @ensuremlf + expname = "getorcreate-$(UUIDs.uuid4())" + e = getorcreateexperiment(mlf, expname) + r = createrun(mlf, e.experiment_id) + @test isa(r, MLFlowRun) + @test deleterun(mlf, r) + rr = createrun(mlf, e) + @test isa(rr, MLFlowRun) + @test deleterun(mlf, rr) + @test deleteexperiment(mlf, e) +end + +@testset "getorcreateexperiment" begin + @ensuremlf + expname = "getorcreate" + e = getorcreateexperiment(mlf, expname) + @test isa(e, MLFlowExperiment) + ee = getorcreateexperiment(mlf, expname) + @test isa(ee, MLFlowExperiment) + @test e === ee + @test deleteexperiment(mlf, ee) + @test deleteexperiment(mlf, ee) end @testset "MLFlowClient.jl" begin @ensuremlf + exp = createexperiment(mlf) + @test isa(exp, MLFlowExperiment) exptags = [:key => "val"] expname = "expname-$(UUIDs.uuid4())" @@ -63,9 +103,14 @@ end f = open(tmpfiletoupload, "w") write(f, "samplecontents") close(f) - logartifact(mlf, retrieved_run, tmpfiletoupload) + artifactpath = logartifact(mlf, retrieved_run, tmpfiletoupload) + @test isfile(artifactpath) + @test_throws SystemError logartifact(mlf, retrieved_run, "/etc/shadow") rm(tmpfiletoupload) + artifactpath = logartifact(mlf, retrieved_run, "randbytes.bin", b"some rand bytes here") + @test isfile(artifactpath) + running_run = updaterun(mlf, exprunid, "RUNNING") @test running_run.info.experiment_id == experiment_id @test running_run.info.status == MLFlowRunStatus("RUNNING") @@ -94,31 +139,7 @@ end deleterun(mlf, exprunid) deleterun(mlf, exprun2) - deleteexperiment(mlf, experiment_id) - experiment = getexperiment(mlf, experiment_id) - @test experiment.experiment_id == experiment_id - @test experiment.lifecycle_stage == "deleted" + deleteexperiment(mlf, exp) end -@testset "createrun" begin - @ensuremlf - - expname = "getorcreate-$(UUIDs.uuid4())" - e = getorcreateexperiment(mlf, expname) - r = createrun(mlf, e.experiment_id) - @test isa(r, MLFlowRun) - rr = createrun(mlf, e) - @test isa(rr, MLFlowRun) -end -@testset "getorcreateexperiment" begin - @ensuremlf - expname = "getorcreate" - e = getorcreateexperiment(mlf, expname) - @test isa(e, MLFlowExperiment) - ee = getorcreateexperiment(mlf, expname) - @test isa(ee, MLFlowExperiment) - @test e === ee - @test deleteexperiment(mlf, ee) - @test deleteexperiment(mlf, ee) -end From 62637583a6887d648ca79b673ee5f4f5bb64c36f Mon Sep 17 00:00:00 2001 From: deyandyankov Date: Fri, 19 Nov 2021 22:12:51 +0000 Subject: [PATCH 7/9] close handle if it is open --- src/logging.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/logging.jl b/src/logging.jl index 16ff6fd..74b207e 100644 --- a/src/logging.jl +++ b/src/logging.jl @@ -124,6 +124,10 @@ function logartifact(mlf::MLFlow, run_id::AbstractString, filepath::Union{Abstra return logartifact(mlf, run_id, basename(filepath), data) catch e throw(e) + finally + if @isdefined f + close(f) + end end end logartifact(mlf::MLFlow, run::MLFlowRun, filepath::Union{AbstractPath,AbstractString}) = From c3bbf6bda61260ba9738bab60453b11d61ae4c0a Mon Sep 17 00:00:00 2001 From: deyandyankov Date: Sat, 20 Nov 2021 15:09:16 +0000 Subject: [PATCH 8/9] Bump version. Minor documentation updates. search runs by dict of params. --- .gitignore | 2 +- Project.toml | 2 +- docs/src/index.md | 10 +-- docs/src/reference.md | 11 ++++ src/MLFlowClient.jl | 8 ++- src/runs.jl | 17 ++++- src/types.jl | 146 +++++++++++++++++------------------------- src/utils.jl | 28 +++++++- test/runtests.jl | 38 +++++++++++ 9 files changed, 161 insertions(+), 101 deletions(-) diff --git a/.gitignore b/.gitignore index b8f9c24..d6a66f4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ *.jl.*.cov *.jl.cov *.jl.mem -/Manifest.toml +Manifest.toml /docs/build/ mlruns diff --git a/Project.toml b/Project.toml index e5a4834..79ee376 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "MLFlowClient" uuid = "64a0f543-368b-4a9a-827a-e71edb2a0b83" authors = ["@deyandyankov and contributors"] -version = "0.1.0" +version = "0.2.0" [deps] Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" diff --git a/docs/src/index.md b/docs/src/index.md index 3f4d22d..64ca8a7 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -4,13 +4,9 @@ CurrentModule = MLFlowClient # MLFlowClient -[MLFlowClient](https://github.com/JuliaAI/MLFlowClient.jl) is a [Julia](https://julialang.org/) package for working with [MLFlow](https://mlflow.org/) using the REST [API v2.0](https://www.mlflow.org/docs/latest/rest-api.html). - -`MLFlowClient` allows you to create and manage `MLFlow` experiments, runs, and log metrics and artifacts. If you are not familiar with `MLFlow` and its concepts, please refer to [MLFlow documentation](https://mlflow.org/docs/latest/index.html). - -## Limitations -- no authentication support. -- when storing artifacts, the assumption is that MLFlow and this library run on the same server. Artifacts are stored using plain filesystem operations. Therefore, `/mlruns` or the specified `artifact_location` must be accessible to both the MLFlow server (read), and this library (write). +```@docs +MLFlowClient +``` ## Installation diff --git a/docs/src/reference.md b/docs/src/reference.md index 4af2ed3..ab8fe72 100644 --- a/docs/src/reference.md +++ b/docs/src/reference.md @@ -6,6 +6,8 @@ CurrentModule = MLFlowClient # Types +TODO: Document accessors. + ```@docs MLFlow MLFlowExperiment @@ -43,3 +45,12 @@ logparam logmetric logartifact ``` + +# Utilities + +```@docs +mlfget +mlfpost +uri +generatefilterfromparams +``` diff --git a/src/MLFlowClient.jl b/src/MLFlowClient.jl index 7e54e67..3f0fa6c 100644 --- a/src/MLFlowClient.jl +++ b/src/MLFlowClient.jl @@ -25,11 +25,17 @@ export MLFlowExperiment, MLFlowRunStatus, MLFlowRunInfo, + get_run_id, MLFlowRunData, + get_params, MLFlowRunDataMetric, - MLFlowRun + MLFlowRun, + get_info, + get_data include("utils.jl") +export + generatefilterfromparams include("experiments.jl") export diff --git a/src/runs.jl b/src/runs.jl index 167376e..ed31224 100644 --- a/src/runs.jl +++ b/src/runs.jl @@ -118,6 +118,7 @@ Searches for runs in an experiment. # Keywords - `filter::String`: filter as defined in [MLFlow documentation](https://mlflow.org/docs/latest/rest-api.html#search-runs) +- `filter_params::AbstractDict{K,V}`: if provided, `filter` is automatically generated based on `filter_params` using [`generatefilterfromparams`](@ref). One can only provide either `filter` or `filter_params`, but not both. - `run_view_type::String`: one of `ACTIVE_ONLY`, `DELETED_ONLY`, or `ALL`. - `max_results::Integer`: 50,000 by default. - `order_by::String`: as defined in [MLFlow documentation](https://mlflow.org/docs/latest/rest-api.html#search-runs) @@ -129,13 +130,23 @@ Searches for runs in an experiment. """ function searchruns(mlf::MLFlow, experiment_ids::AbstractVector{<:Integer}; filter::String="", + filter_params::AbstractDict{K,V}=Dict{}(), run_view_type::String="ACTIVE_ONLY", max_results::Int64=50000, order_by::AbstractVector{<:String}=["attribute.start_time"], page_token::String="" - ) + ) where {K,V} endpoint = "runs/search" run_view_type ∈ ["ACTIVE_ONLY", "DELETED_ONLY", "ALL"] || error("Unsupported run_view_type = $run_view_type") + + if length(filter_params) > 0 && length(filter) > 0 + error("Can only use either filter or filter_params, but not both at the same time.") + end + + if length(filter_params) > 0 + filter = generatefilterfromparams(filter_params) + end + kwargs = ( experiment_ids=experiment_ids, filter=filter, @@ -169,3 +180,7 @@ function searchruns(mlf::MLFlow, experiment_ids::AbstractVector{<:Integer}; end searchruns(mlf::MLFlow, experiment_id::Integer; kwargs...) = searchruns(mlf, [experiment_id]; kwargs...) +searchruns(mlf::MLFlow, exp::MLFlowExperiment; kwargs...) = + searchruns(mlf, exp.experiment_id; kwargs...) +searchruns(mlf::MLFlow, exps::AbstractVector{MLFlowExperiment}; kwargs...) = + searchruns(mlf, [getfield.(exps, :experiment_id)]; kwargs...) diff --git a/src/types.jl b/src/types.jl index 78c2acd..5d75a6e 100644 --- a/src/types.jl +++ b/src/types.jl @@ -13,18 +13,18 @@ Base type which defines location and version for MLFlow API service. - `MLFlow()` - defaults to `MLFlow("http://localhost:5000")` # Examples -``` julia-repl -julia> mlf = MLFlow() -MLFlow("http://localhost:5000", 2.0) + +```@example +mlf = MLFlow() ``` """ struct MLFlow baseuri::String apiversion - MLFlow(baseuri; apiversion=2.0) = new(baseuri, apiversion) end -MLFlow() = MLFlow("http://localhost:5000") +MLFlow(baseuri; apiversion=2.0) = MLFlow(baseuri, apiversion) +MLFlow() = MLFlow("http://localhost:5000", 2.0) """ MLFlowExperiment @@ -50,18 +50,14 @@ struct MLFlowExperiment experiment_id::Integer tags::Any artifact_location::String - - MLFlowExperiment(name, lifecycle_stage, experiment_id, tags, artifact_location) = - new(name, lifecycle_stage, experiment_id, tags, artifact_location) - - function MLFlowExperiment(exp::Dict{String,Any}) - name = get(exp, "name", missing) - lifecycle_stage = get(exp, "lifecycle_stage", missing) - experiment_id = parse(Int, get(exp, "experiment_id", missing)) - tags = get(exp, "tags", missing) - artifact_location = get(exp, "artifact_location", missing) - MLFlowExperiment(name, lifecycle_stage, experiment_id, tags, artifact_location) - end +end +function MLFlowExperiment(exp::Dict{String,Any}) + name = get(exp, "name", missing) + lifecycle_stage = get(exp, "lifecycle_stage", missing) + experiment_id = parse(Int, get(exp, "experiment_id", missing)) + tags = get(exp, "tags", missing) + artifact_location = get(exp, "artifact_location", missing) + MLFlowExperiment(name, lifecycle_stage, experiment_id, tags, artifact_location) end @@ -79,7 +75,6 @@ Represents the status of an MLFlow Run. """ struct MLFlowRunStatus status::String - function MLFlowRunStatus(status::String) acceptable_statuses = ["RUNNING", "SCHEDULED", "FINISHED", "FAILED", "KILLED"] status ∈ acceptable_statuses || error("Invalid status $status - choose one of $acceptable_statuses") @@ -114,39 +109,24 @@ struct MLFlowRunInfo end_time::Union{Int64,Missing} artifact_uri::String lifecycle_stage::String - - function MLFlowRunInfo(run_id, experiment_id, status, start_time, end_time, artifact_uri, lifecycle_stage) - new(run_id, experiment_id, status, start_time, end_time, artifact_uri, lifecycle_stage) - end - - function MLFlowRunInfo(info::Dict{String,Any}) - run_id = get(info, "run_id", missing) - experiment_id = get(info, "experiment_id", missing) - status = get(info, "status", missing) - start_time = get(info, "start_time", missing) - end_time = get(info, "end_time", missing) - artifact_uri = get(info, "artifact_uri", "") - lifecycle_stage = get(info, "lifecycle_stage", "") - - if !ismissing(experiment_id) - experiment_id = parse(Int64, experiment_id) - end - - if !ismissing(status) - status = MLFlowRunStatus(status) - end - - if !ismissing(start_time) - start_time = parse(Int64, start_time) - end - - if !ismissing(end_time) - end_time = parse(Int64, end_time) - end - - MLFlowRunInfo(run_id, experiment_id, status, start_time, end_time, artifact_uri, lifecycle_stage) - end end +function MLFlowRunInfo(info::Dict{String,Any}) + run_id = get(info, "run_id", missing) + experiment_id = get(info, "experiment_id", missing) + status = get(info, "status", missing) + start_time = get(info, "start_time", missing) + end_time = get(info, "end_time", missing) + artifact_uri = get(info, "artifact_uri", "") + lifecycle_stage = get(info, "lifecycle_stage", "") + + experiment_id = ismissing(experiment_id) ? experiment_id : parse(Int64, experiment_id) + status = ismissing(status) ? status : MLFlowRunStatus(status) + start_time = ismissing(start_time) ? start_time : parse(Int64, start_time) + end_time = ismissing(end_time) ? end_time : parse(Int64, end_time) + + MLFlowRunInfo(run_id, experiment_id, status, start_time, end_time, artifact_uri, lifecycle_stage) +end +get_run_id(runinfo::MLFlowRunInfo) = runinfo.run_id """ MLFlowRunDataMetric @@ -169,13 +149,13 @@ struct MLFlowRunDataMetric value::Float64 step::Int64 timestamp::Int64 - function MLFlowRunDataMetric(d::Dict{String,Any}) - key = d["key"] - value = d["value"] - step = parse(Int64, d["step"]) - timestamp = parse(Int64, d["timestamp"]) - new(key, value, step, timestamp) - end +end +function MLFlowRunDataMetric(d::Dict{String,Any}) + key = d["key"] + value = d["value"] + step = parse(Int64, d["step"]) + timestamp = parse(Int64, d["timestamp"]) + MLFlowRunDataMetric(key, value, step, timestamp) end @@ -198,20 +178,21 @@ struct MLFlowRunData metrics::Vector{MLFlowRunDataMetric} params::Union{Dict{String,String},Missing} tags - function MLFlowRunData(data::Dict{String,Any}) - metrics = haskey(data, "metrics") ? MLFlowRunDataMetric.(data["metrics"]) : MLFlowRunDataMetric[] - if haskey(data, "params") - params = Dict{String,String}() - for p in data["params"] - params[p["key"]] = p["value"] - end - else - params = Dict{String,String}() +end +function MLFlowRunData(data::Dict{String,Any}) + metrics = haskey(data, "metrics") ? MLFlowRunDataMetric.(data["metrics"]) : MLFlowRunDataMetric[] + if haskey(data, "params") + params = Dict{String,String}() + for p in data["params"] + params[p["key"]] = p["value"] end - tags = haskey(data, "tags") ? data["tags"] : missing - new(metrics, params, tags) + else + params = Dict{String,String}() end + tags = haskey(data, "tags") ? data["tags"] : missing + MLFlowRunData(metrics, params, tags) end +get_params(rundata::MLFlowRunData) = rundata.params """ MLFlowRun @@ -233,23 +214,14 @@ Represents an MLFlow run. struct MLFlowRun info::Union{MLFlowRunInfo,Missing} data::Union{MLFlowRunData,Missing} - - function MLFlowRun(rundata::MLFlowRunData) - info = missing - new(info, rundata) - end - function MLFlowRun(runinfo::MLFlowRunInfo) - data = missing - new(runinfo, data) - end - function MLFlowRun(info::Dict{String,Any}) - info = MLFlowRunInfo(info) - data = missing - new(info, data) - end - function MLFlowRun(info::Dict{String,Any}, data::Dict{String,Any}) - info = MLFlowRunInfo(info) - data = MLFlowRunData(data) - new(info, data) - end end +MLFlowRun(rundata::MLFlowRunData) = + MLFlowRun(missing, rundata) +MLFlowRun(runinfo::MLFlowRunInfo) = + MLFlowRun(runinfo, missing) +MLFlowRun(info::Dict{String,Any}) = + MLFlowRun(MLFlowRunInfo(info), missing) +MLFlowRun(info::Dict{String,Any}, data::Dict{String,Any}) = + MLFlowRun(MLFlowRunInfo(info), MLFlowRunData(data)) +get_info(run::MLFlowRun) = run.info +get_data(run::MLFlowRun) = run.data diff --git a/src/utils.jl b/src/utils.jl index 77db582..9a27870 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -4,9 +4,8 @@ Retrieves an URI based on `mlf`, `endpoint`, and, optionally, `query`. # Examples -``` julia-repl -julia> MLFlowClient.uri(mlf, "experiments/get", Dict(:experiment_id=>10)) -URI("http://localhost/api/2.0/mlflow/experiments/get?experiment_id=10") +```@example +MLFlowClient.uri(mlf, "experiments/get", Dict(:experiment_id=>10)) ``` """ function uri(mlf::MLFlow, endpoint="", query=missing) @@ -48,3 +47,26 @@ function mlfpost(mlf, endpoint; kwargs...) end end +""" + generatefilterfromparams(filter_params::AbstractDict{K,V}) where {K,V} + +Generates a `filter` string from `filter_params` dictionary. + +# Arguments +- `filter_params`: dictionary to use for filter generation. + +# Returns +A string that can be passed as `filter` to [`searchruns`](@ref). + +# Examples + +```@example +generatefilterfromparams(Dict("paramkey1" => "paramvalue1", "paramkey2" => "paramvalue2")) +``` +""" +function generatefilterfromparams(filter_params::AbstractDict{K,V}) where {K,V} + length(filter_params) > 0 || return "" + # NOTE: may have issues with escaping. + filters = ["param.\"$(k)\" = \"$(v)\"" for(k, v) ∈ filter_params ] + join(filters, " and ") +end diff --git a/test/runtests.jl b/test/runtests.jl index 9e78a8c..62718db 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,6 +1,7 @@ using MLFlowClient using Test using UUIDs +using Dates function mlflow_server_is_running(mlf::MLFlow) try @@ -65,6 +66,43 @@ end @test deleteexperiment(mlf, ee) end +@testset "generatefilterfromparama" begin + filter_params = Dict("k1" => "v1") + filter = generatefilterfromparams(filter_params) + @test filter == "param.\"k1\" = \"v1\"" + filter_params = Dict("k1" => "v1", "started" => Date("2020-01-01")) + filter = generatefilterfromparams(filter_params) + @test occursin("param.\"k1\" = \"v1\"", filter) + @test occursin("param.\"started\" = \"2020-01-01\"", filter) + @test occursin(" and ", filter) +end + +@testset "searchruns" begin + @ensuremlf + exp = createexperiment(mlf) + expid = exp.experiment_id + exprun = createrun(mlf, exp) + @test exprun.info.experiment_id == expid + @test exprun.info.lifecycle_stage == "active" + @test exprun.info.status == MLFlowRunStatus("RUNNING") + exprunid = exprun.info.run_id + + runparams = Dict( + "k1" => "v1", + "started" => Date("2020-01-01") + ) + logparam(mlf, exprun, runparams) + + findrun = searchruns(mlf, exp; filter_params=runparams) + @test length(findrun) == 1 + r = only(findrun) + @test get_run_id(get_info(r)) == exprun.info.run_id + @test sort(collect(keys(get_params(get_data(r))))) == sort(string.(keys(runparams))) + @test sort(collect(values(get_params(get_data(r))))) == sort(string.(values(runparams))) + + @test deleteexperiment(mlf, exp) +end + @testset "MLFlowClient.jl" begin @ensuremlf exp = createexperiment(mlf) From 85aa6fa1d2ac6feb78fea31f68280b05868de6b0 Mon Sep 17 00:00:00 2001 From: deyandyankov Date: Sat, 20 Nov 2021 15:09:46 +0000 Subject: [PATCH 9/9] delete examples/Manifest.toml --- examples/Manifest.toml | 879 ----------------------------------------- 1 file changed, 879 deletions(-) delete mode 100644 examples/Manifest.toml diff --git a/examples/Manifest.toml b/examples/Manifest.toml deleted file mode 100644 index b1e9790..0000000 --- a/examples/Manifest.toml +++ /dev/null @@ -1,879 +0,0 @@ -# This file is machine-generated - editing it directly is not advised - -julia_version = "1.7.0-rc2" -manifest_format = "2.0" - -[[deps.ANSIColoredPrinters]] -git-tree-sha1 = "574baf8110975760d391c710b6341da1afa48d8c" -uuid = "a4c015fc-c6ff-483c-b24f-f7ea428134e9" -version = "0.0.1" - -[[deps.Adapt]] -deps = ["LinearAlgebra"] -git-tree-sha1 = "84918055d15b3114ede17ac6a7182f68870c16f7" -uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" -version = "3.3.1" - -[[deps.ArgTools]] -uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" - -[[deps.Artifacts]] -uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" - -[[deps.Base64]] -uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" - -[[deps.Bzip2_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2" -uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" -version = "1.0.8+0" - -[[deps.Cairo_jll]] -deps = ["Artifacts", "Bzip2_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"] -git-tree-sha1 = "f2202b55d816427cd385a9a4f3ffb226bee80f99" -uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a" -version = "1.16.1+0" - -[[deps.ChainRulesCore]] -deps = ["Compat", "LinearAlgebra", "SparseArrays"] -git-tree-sha1 = "f885e7e7c124f8c92650d61b9477b9ac2ee607dd" -uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" -version = "1.11.1" - -[[deps.ChangesOfVariables]] -deps = ["LinearAlgebra", "Test"] -git-tree-sha1 = "9a1d594397670492219635b35a3d830b04730d62" -uuid = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" -version = "0.1.1" - -[[deps.ColorSchemes]] -deps = ["ColorTypes", "Colors", "FixedPointNumbers", "Random"] -git-tree-sha1 = "a851fec56cb73cfdf43762999ec72eff5b86882a" -uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" -version = "3.15.0" - -[[deps.ColorTypes]] -deps = ["FixedPointNumbers", "Random"] -git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597" -uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" -version = "0.11.0" - -[[deps.Colors]] -deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] -git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40" -uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" -version = "0.12.8" - -[[deps.Compat]] -deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"] -git-tree-sha1 = "dce3e3fea680869eaa0b774b2e8343e9ff442313" -uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" -version = "3.40.0" - -[[deps.CompilerSupportLibraries_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" - -[[deps.Contour]] -deps = ["StaticArrays"] -git-tree-sha1 = "9f02045d934dc030edad45944ea80dbd1f0ebea7" -uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" -version = "0.5.7" - -[[deps.DataAPI]] -git-tree-sha1 = "cc70b17275652eb47bc9e5f81635981f13cea5c8" -uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" -version = "1.9.0" - -[[deps.DataStructures]] -deps = ["Compat", "InteractiveUtils", "OrderedCollections"] -git-tree-sha1 = "7d9d316f04214f7efdbb6398d545446e246eff02" -uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" -version = "0.18.10" - -[[deps.DataValueInterfaces]] -git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" -uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" -version = "1.0.0" - -[[deps.Dates]] -deps = ["Printf"] -uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" - -[[deps.DelimitedFiles]] -deps = ["Mmap"] -uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" - -[[deps.Distributed]] -deps = ["Random", "Serialization", "Sockets"] -uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" - -[[deps.DocStringExtensions]] -deps = ["LibGit2"] -git-tree-sha1 = "b19534d1895d702889b219c382a6e18010797f0b" -uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -version = "0.8.6" - -[[deps.Documenter]] -deps = ["ANSIColoredPrinters", "Base64", "Dates", "DocStringExtensions", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "REPL", "Test", "Unicode"] -git-tree-sha1 = "f425293f7e0acaf9144de6d731772de156676233" -uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" -version = "0.27.10" - -[[deps.Downloads]] -deps = ["ArgTools", "LibCURL", "NetworkOptions"] -uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" - -[[deps.EarCut_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "3f3a2501fa7236e9b911e0f7a588c657e822bb6d" -uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5" -version = "2.2.3+0" - -[[deps.Expat_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "b3bfd02e98aedfa5cf885665493c5598c350cd2f" -uuid = "2e619515-83b5-522b-bb60-26c02a35a201" -version = "2.2.10+0" - -[[deps.FFMPEG]] -deps = ["FFMPEG_jll"] -git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8" -uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" -version = "0.4.1" - -[[deps.FFMPEG_jll]] -deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "Pkg", "Zlib_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"] -git-tree-sha1 = "d8a578692e3077ac998b50c0217dfd67f21d1e5f" -uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" -version = "4.4.0+0" - -[[deps.FixedPointNumbers]] -deps = ["Statistics"] -git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" -uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" -version = "0.8.4" - -[[deps.Fontconfig_jll]] -deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"] -git-tree-sha1 = "21efd19106a55620a188615da6d3d06cd7f6ee03" -uuid = "a3f928ae-7b40-5064-980b-68af3947d34b" -version = "2.13.93+0" - -[[deps.Formatting]] -deps = ["Printf"] -git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8" -uuid = "59287772-0a20-5a39-b81b-1366585eb4c0" -version = "0.4.2" - -[[deps.FreeType2_jll]] -deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] -git-tree-sha1 = "87eb71354d8ec1a96d4a7636bd57a7347dde3ef9" -uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7" -version = "2.10.4+0" - -[[deps.FriBidi_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91" -uuid = "559328eb-81f9-559d-9380-de523a88c83c" -version = "1.0.10+0" - -[[deps.GLFW_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Pkg", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll"] -git-tree-sha1 = "0c603255764a1fa0b61752d2bec14cfbd18f7fe8" -uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89" -version = "3.3.5+1" - -[[deps.GR]] -deps = ["Base64", "DelimitedFiles", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Printf", "Random", "Serialization", "Sockets", "Test", "UUIDs"] -git-tree-sha1 = "30f2b340c2fff8410d89bfcdc9c0a6dd661ac5f7" -uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" -version = "0.62.1" - -[[deps.GR_jll]] -deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Pkg", "Qt5Base_jll", "Zlib_jll", "libpng_jll"] -git-tree-sha1 = "fd75fa3a2080109a2c0ec9864a6e14c60cca3866" -uuid = "d2c73de3-f751-5644-a686-071e5b155ba9" -version = "0.62.0+0" - -[[deps.GeometryBasics]] -deps = ["EarCut_jll", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"] -git-tree-sha1 = "58bcdf5ebc057b085e58d95c138725628dd7453c" -uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326" -version = "0.4.1" - -[[deps.Gettext_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"] -git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046" -uuid = "78b55507-aeef-58d4-861c-77aaff3498b1" -version = "0.21.0+0" - -[[deps.Glib_jll]] -deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE_jll", "Pkg", "Zlib_jll"] -git-tree-sha1 = "7bf67e9a481712b3dbe9cb3dac852dc4b1162e02" -uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" -version = "2.68.3+0" - -[[deps.Graphite2_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011" -uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472" -version = "1.3.14+0" - -[[deps.Grisu]] -git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2" -uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe" -version = "1.0.2" - -[[deps.HTTP]] -deps = ["Base64", "Dates", "IniFile", "Logging", "MbedTLS", "NetworkOptions", "Sockets", "URIs"] -git-tree-sha1 = "14eece7a3308b4d8be910e265c724a6ba51a9798" -uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" -version = "0.9.16" - -[[deps.HarfBuzz_jll]] -deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"] -git-tree-sha1 = "8a954fed8ac097d5be04921d595f741115c1b2ad" -uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566" -version = "2.8.1+0" - -[[deps.IOCapture]] -deps = ["Logging", "Random"] -git-tree-sha1 = "f7be53659ab06ddc986428d3a9dcc95f6fa6705a" -uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" -version = "0.2.2" - -[[deps.IniFile]] -deps = ["Test"] -git-tree-sha1 = "098e4d2c533924c921f9f9847274f2ad89e018b8" -uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f" -version = "0.5.0" - -[[deps.InteractiveUtils]] -deps = ["Markdown"] -uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" - -[[deps.InverseFunctions]] -deps = ["Test"] -git-tree-sha1 = "a7254c0acd8e62f1ac75ad24d5db43f5f19f3c65" -uuid = "3587e190-3f89-42d0-90ee-14403ec27112" -version = "0.1.2" - -[[deps.IrrationalConstants]] -git-tree-sha1 = "7fd44fd4ff43fc60815f8e764c0f352b83c49151" -uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" -version = "0.1.1" - -[[deps.IterTools]] -git-tree-sha1 = "05110a2ab1fc5f932622ffea2a003221f4782c18" -uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e" -version = "1.3.0" - -[[deps.IteratorInterfaceExtensions]] -git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" -uuid = "82899510-4779-5014-852e-03e436cf321d" -version = "1.0.0" - -[[deps.JLLWrappers]] -deps = ["Preferences"] -git-tree-sha1 = "642a199af8b68253517b80bd3bfd17eb4e84df6e" -uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" -version = "1.3.0" - -[[deps.JSON]] -deps = ["Dates", "Mmap", "Parsers", "Unicode"] -git-tree-sha1 = "8076680b162ada2a031f707ac7b4953e30667a37" -uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -version = "0.21.2" - -[[deps.JpegTurbo_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "d735490ac75c5cb9f1b00d8b5509c11984dc6943" -uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8" -version = "2.1.0+0" - -[[deps.LAME_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c" -uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d" -version = "3.100.1+0" - -[[deps.LZO_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6" -uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac" -version = "2.10.1+0" - -[[deps.LaTeXStrings]] -git-tree-sha1 = "f2355693d6778a178ade15952b7ac47a4ff97996" -uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" -version = "1.3.0" - -[[deps.Latexify]] -deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "Printf", "Requires"] -git-tree-sha1 = "a8f4f279b6fa3c3c4f1adadd78a621b13a506bce" -uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" -version = "0.15.9" - -[[deps.LibCURL]] -deps = ["LibCURL_jll", "MozillaCACerts_jll"] -uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" - -[[deps.LibCURL_jll]] -deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] -uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" - -[[deps.LibGit2]] -deps = ["Base64", "NetworkOptions", "Printf", "SHA"] -uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" - -[[deps.LibSSH2_jll]] -deps = ["Artifacts", "Libdl", "MbedTLS_jll"] -uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" - -[[deps.Libdl]] -uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" - -[[deps.Libffi_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "761a393aeccd6aa92ec3515e428c26bf99575b3b" -uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490" -version = "3.2.2+0" - -[[deps.Libgcrypt_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"] -git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae" -uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4" -version = "1.8.7+0" - -[[deps.Libglvnd_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll", "Xorg_libXext_jll"] -git-tree-sha1 = "7739f837d6447403596a75d19ed01fd08d6f56bf" -uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29" -version = "1.3.0+3" - -[[deps.Libgpg_error_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9" -uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8" -version = "1.42.0+0" - -[[deps.Libiconv_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "42b62845d70a619f063a7da093d995ec8e15e778" -uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" -version = "1.16.1+1" - -[[deps.Libmount_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73" -uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9" -version = "2.35.0+0" - -[[deps.Libtiff_jll]] -deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"] -git-tree-sha1 = "340e257aada13f95f98ee352d316c3bed37c8ab9" -uuid = "89763e89-9b03-5906-acba-b20f662cd828" -version = "4.3.0+0" - -[[deps.Libuuid_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066" -uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" -version = "2.36.0+0" - -[[deps.LinearAlgebra]] -deps = ["Libdl", "libblastrampoline_jll"] -uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" - -[[deps.LogExpFunctions]] -deps = ["ChainRulesCore", "ChangesOfVariables", "DocStringExtensions", "InverseFunctions", "IrrationalConstants", "LinearAlgebra"] -git-tree-sha1 = "be9eef9f9d78cecb6f262f3c10da151a6c5ab827" -uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" -version = "0.3.5" - -[[deps.Logging]] -uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" - -[[deps.MLFlowClientREST]] -deps = ["Dates", "Documenter", "HTTP", "JSON", "URIs", "UUIDs"] -path = "/home/azo/.julia/dev/MLFlowClientREST" -uuid = "64a0f543-368b-4a9a-827a-e71edb2a0b83" -version = "0.1.0" - -[[deps.MacroTools]] -deps = ["Markdown", "Random"] -git-tree-sha1 = "3d3e902b31198a27340d0bf00d6ac452866021cf" -uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" -version = "0.5.9" - -[[deps.Markdown]] -deps = ["Base64"] -uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" - -[[deps.MbedTLS]] -deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"] -git-tree-sha1 = "1c38e51c3d08ef2278062ebceade0e46cefc96fe" -uuid = "739be429-bea8-5141-9913-cc70e7f3736d" -version = "1.0.3" - -[[deps.MbedTLS_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" - -[[deps.Measures]] -git-tree-sha1 = "e498ddeee6f9fdb4551ce855a46f54dbd900245f" -uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e" -version = "0.3.1" - -[[deps.Missings]] -deps = ["DataAPI"] -git-tree-sha1 = "bf210ce90b6c9eed32d25dbcae1ebc565df2687f" -uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" -version = "1.0.2" - -[[deps.Mmap]] -uuid = "a63ad114-7e13-5084-954f-fe012c677804" - -[[deps.MozillaCACerts_jll]] -uuid = "14a3606d-f60d-562e-9121-12d972cd8159" - -[[deps.NaNMath]] -git-tree-sha1 = "bfe47e760d60b82b66b61d2d44128b62e3a369fb" -uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" -version = "0.3.5" - -[[deps.NetworkOptions]] -uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" - -[[deps.Ogg_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "7937eda4681660b4d6aeeecc2f7e1c81c8ee4e2f" -uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" -version = "1.3.5+0" - -[[deps.OpenBLAS_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] -uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" - -[[deps.OpenSSL_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "15003dcb7d8db3c6c857fda14891a539a8f2705a" -uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" -version = "1.1.10+0" - -[[deps.Opus_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720" -uuid = "91d4177d-7536-5919-b921-800302f37372" -version = "1.3.2+0" - -[[deps.OrderedCollections]] -git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c" -uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" -version = "1.4.1" - -[[deps.PCRE_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "b2a7af664e098055a7529ad1a900ded962bca488" -uuid = "2f80f16e-611a-54ab-bc61-aa92de5b98fc" -version = "8.44.0+0" - -[[deps.Parsers]] -deps = ["Dates"] -git-tree-sha1 = "ae4bbcadb2906ccc085cf52ac286dc1377dceccc" -uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "2.1.2" - -[[deps.Pixman_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "b4f5d02549a10e20780a24fce72bea96b6329e29" -uuid = "30392449-352a-5448-841d-b1acce4e97dc" -version = "0.40.1+0" - -[[deps.Pkg]] -deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] -uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" - -[[deps.PlotThemes]] -deps = ["PlotUtils", "Requires", "Statistics"] -git-tree-sha1 = "a3a964ce9dc7898193536002a6dd892b1b5a6f1d" -uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" -version = "2.0.1" - -[[deps.PlotUtils]] -deps = ["ColorSchemes", "Colors", "Dates", "Printf", "Random", "Reexport", "Statistics"] -git-tree-sha1 = "b084324b4af5a438cd63619fd006614b3b20b87b" -uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" -version = "1.0.15" - -[[deps.Plots]] -deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "GeometryBasics", "JSON", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "PlotThemes", "PlotUtils", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs", "UnicodeFun"] -git-tree-sha1 = "7dc03c2b145168f5854085a16d054429d612b637" -uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" -version = "1.23.5" - -[[deps.Preferences]] -deps = ["TOML"] -git-tree-sha1 = "00cfd92944ca9c760982747e9a1d0d5d86ab1e5a" -uuid = "21216c6a-2e73-6563-6e65-726566657250" -version = "1.2.2" - -[[deps.Printf]] -deps = ["Unicode"] -uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" - -[[deps.Qt5Base_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "xkbcommon_jll"] -git-tree-sha1 = "ad368663a5e20dbb8d6dc2fddeefe4dae0781ae8" -uuid = "ea2cea3b-5b76-57ae-a6ef-0a8af62496e1" -version = "5.15.3+0" - -[[deps.REPL]] -deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] -uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" - -[[deps.Random]] -deps = ["SHA", "Serialization"] -uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" - -[[deps.RecipesBase]] -git-tree-sha1 = "44a75aa7a527910ee3d1751d1f0e4148698add9e" -uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" -version = "1.1.2" - -[[deps.RecipesPipeline]] -deps = ["Dates", "NaNMath", "PlotUtils", "RecipesBase"] -git-tree-sha1 = "7ad0dfa8d03b7bcf8c597f59f5292801730c55b8" -uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c" -version = "0.4.1" - -[[deps.Reexport]] -git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" -uuid = "189a3867-3050-52da-a836-e630ba90ab69" -version = "1.2.2" - -[[deps.Requires]] -deps = ["UUIDs"] -git-tree-sha1 = "4036a3bd08ac7e968e27c203d45f5fff15020621" -uuid = "ae029012-a4dd-5104-9daa-d747884805df" -version = "1.1.3" - -[[deps.SHA]] -uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" - -[[deps.Scratch]] -deps = ["Dates"] -git-tree-sha1 = "0b4b7f1393cff97c33891da2a0bf69c6ed241fda" -uuid = "6c6a2e73-6563-6170-7368-637461726353" -version = "1.1.0" - -[[deps.Serialization]] -uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" - -[[deps.SharedArrays]] -deps = ["Distributed", "Mmap", "Random", "Serialization"] -uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" - -[[deps.Showoff]] -deps = ["Dates", "Grisu"] -git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de" -uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f" -version = "1.0.3" - -[[deps.Sockets]] -uuid = "6462fe0b-24de-5631-8697-dd941f90decc" - -[[deps.SortingAlgorithms]] -deps = ["DataStructures"] -git-tree-sha1 = "b3363d7460f7d098ca0912c69b082f75625d7508" -uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" -version = "1.0.1" - -[[deps.SparseArrays]] -deps = ["LinearAlgebra", "Random"] -uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" - -[[deps.StaticArrays]] -deps = ["LinearAlgebra", "Random", "Statistics"] -git-tree-sha1 = "3c76dde64d03699e074ac02eb2e8ba8254d428da" -uuid = "90137ffa-7385-5640-81b9-e52037218182" -version = "1.2.13" - -[[deps.Statistics]] -deps = ["LinearAlgebra", "SparseArrays"] -uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" - -[[deps.StatsAPI]] -git-tree-sha1 = "1958272568dc176a1d881acb797beb909c785510" -uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" -version = "1.0.0" - -[[deps.StatsBase]] -deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] -git-tree-sha1 = "eb35dcc66558b2dda84079b9a1be17557d32091a" -uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" -version = "0.33.12" - -[[deps.StructArrays]] -deps = ["Adapt", "DataAPI", "StaticArrays", "Tables"] -git-tree-sha1 = "2ce41e0d042c60ecd131e9fb7154a3bfadbf50d3" -uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" -version = "0.6.3" - -[[deps.TOML]] -deps = ["Dates"] -uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" - -[[deps.TableTraits]] -deps = ["IteratorInterfaceExtensions"] -git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39" -uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" -version = "1.0.1" - -[[deps.Tables]] -deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "TableTraits", "Test"] -git-tree-sha1 = "fed34d0e71b91734bf0a7e10eb1bb05296ddbcd0" -uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" -version = "1.6.0" - -[[deps.Tar]] -deps = ["ArgTools", "SHA"] -uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" - -[[deps.Test]] -deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] -uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[[deps.URIs]] -git-tree-sha1 = "97bbe755a53fe859669cd907f2d96aee8d2c1355" -uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" -version = "1.3.0" - -[[deps.UUIDs]] -deps = ["Random", "SHA"] -uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" - -[[deps.Unicode]] -uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" - -[[deps.UnicodeFun]] -deps = ["REPL"] -git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf" -uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1" -version = "0.4.1" - -[[deps.Wayland_jll]] -deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"] -git-tree-sha1 = "3e61f0b86f90dacb0bc0e73a0c5a83f6a8636e23" -uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89" -version = "1.19.0+0" - -[[deps.Wayland_protocols_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll"] -git-tree-sha1 = "2839f1c1296940218e35df0bbb220f2a79686670" -uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91" -version = "1.18.0+4" - -[[deps.XML2_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"] -git-tree-sha1 = "1acf5bdf07aa0907e0a37d3718bb88d4b687b74a" -uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" -version = "2.9.12+0" - -[[deps.XSLT_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"] -git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a" -uuid = "aed1982a-8fda-507f-9586-7b0439959a61" -version = "1.1.34+0" - -[[deps.Xorg_libX11_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll", "Xorg_xtrans_jll"] -git-tree-sha1 = "5be649d550f3f4b95308bf0183b82e2582876527" -uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc" -version = "1.6.9+4" - -[[deps.Xorg_libXau_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "4e490d5c960c314f33885790ed410ff3a94ce67e" -uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec" -version = "1.0.9+4" - -[[deps.Xorg_libXcursor_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"] -git-tree-sha1 = "12e0eb3bc634fa2080c1c37fccf56f7c22989afd" -uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724" -version = "1.2.0+4" - -[[deps.Xorg_libXdmcp_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "4fe47bd2247248125c428978740e18a681372dd4" -uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05" -version = "1.1.3+4" - -[[deps.Xorg_libXext_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] -git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3" -uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3" -version = "1.3.4+4" - -[[deps.Xorg_libXfixes_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] -git-tree-sha1 = "0e0dc7431e7a0587559f9294aeec269471c991a4" -uuid = "d091e8ba-531a-589c-9de9-94069b037ed8" -version = "5.0.3+4" - -[[deps.Xorg_libXi_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXfixes_jll"] -git-tree-sha1 = "89b52bc2160aadc84d707093930ef0bffa641246" -uuid = "a51aa0fd-4e3c-5386-b890-e753decda492" -version = "1.7.10+4" - -[[deps.Xorg_libXinerama_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll"] -git-tree-sha1 = "26be8b1c342929259317d8b9f7b53bf2bb73b123" -uuid = "d1454406-59df-5ea1-beac-c340f2130bc3" -version = "1.1.4+4" - -[[deps.Xorg_libXrandr_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll"] -git-tree-sha1 = "34cea83cb726fb58f325887bf0612c6b3fb17631" -uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484" -version = "1.5.2+4" - -[[deps.Xorg_libXrender_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] -git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96" -uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa" -version = "0.9.10+4" - -[[deps.Xorg_libpthread_stubs_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "6783737e45d3c59a4a4c4091f5f88cdcf0908cbb" -uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74" -version = "0.1.0+3" - -[[deps.Xorg_libxcb_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"] -git-tree-sha1 = "daf17f441228e7a3833846cd048892861cff16d6" -uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b" -version = "1.13.0+3" - -[[deps.Xorg_libxkbfile_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] -git-tree-sha1 = "926af861744212db0eb001d9e40b5d16292080b2" -uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a" -version = "1.1.0+4" - -[[deps.Xorg_xcb_util_image_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] -git-tree-sha1 = "0fab0a40349ba1cba2c1da699243396ff8e94b97" -uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b" -version = "0.4.0+1" - -[[deps.Xorg_xcb_util_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll"] -git-tree-sha1 = "e7fd7b2881fa2eaa72717420894d3938177862d1" -uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5" -version = "0.4.0+1" - -[[deps.Xorg_xcb_util_keysyms_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] -git-tree-sha1 = "d1151e2c45a544f32441a567d1690e701ec89b00" -uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7" -version = "0.4.0+1" - -[[deps.Xorg_xcb_util_renderutil_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] -git-tree-sha1 = "dfd7a8f38d4613b6a575253b3174dd991ca6183e" -uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e" -version = "0.3.9+1" - -[[deps.Xorg_xcb_util_wm_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] -git-tree-sha1 = "e78d10aab01a4a154142c5006ed44fd9e8e31b67" -uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361" -version = "0.4.1+1" - -[[deps.Xorg_xkbcomp_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxkbfile_jll"] -git-tree-sha1 = "4bcbf660f6c2e714f87e960a171b119d06ee163b" -uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4" -version = "1.4.2+4" - -[[deps.Xorg_xkeyboard_config_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xkbcomp_jll"] -git-tree-sha1 = "5c8424f8a67c3f2209646d4425f3d415fee5931d" -uuid = "33bec58e-1273-512f-9401-5d533626f822" -version = "2.27.0+4" - -[[deps.Xorg_xtrans_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "79c31e7844f6ecf779705fbc12146eb190b7d845" -uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10" -version = "1.4.0+3" - -[[deps.Zlib_jll]] -deps = ["Libdl"] -uuid = "83775a58-1f1d-513f-b197-d71354ab007a" - -[[deps.Zstd_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "cc4bf3fdde8b7e3e9fa0351bdeedba1cf3b7f6e6" -uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" -version = "1.5.0+0" - -[[deps.libass_jll]] -deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] -git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47" -uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0" -version = "0.15.1+0" - -[[deps.libblastrampoline_jll]] -deps = ["Artifacts", "Libdl", "OpenBLAS_jll"] -uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" - -[[deps.libfdk_aac_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55" -uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280" -version = "2.0.2+0" - -[[deps.libpng_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] -git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c" -uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f" -version = "1.6.38+0" - -[[deps.libvorbis_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"] -git-tree-sha1 = "c45f4e40e7aafe9d086379e5578947ec8b95a8fb" -uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a" -version = "1.3.7+0" - -[[deps.nghttp2_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" - -[[deps.p7zip_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" - -[[deps.x264_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2" -uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a" -version = "2021.5.5+0" - -[[deps.x265_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9" -uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76" -version = "3.5.0+0" - -[[deps.xkbcommon_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"] -git-tree-sha1 = "ece2350174195bb31de1a63bea3a41ae1aa593b6" -uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd" -version = "0.9.1+5"