ジュリアでインストールされたパッケージのリストを取得する方法
概要
Julia を再インストールすることが多いスタイルほどパッケージを新しく入れ直す必要があり面倒なことが増える。そこでインストール済みパッケージの一覧を見て、その中で抜けているパッケージを自動でインストールしてくれるヘッダを作ると便利だが、問題はそのパッケージ一覧を取得するのが容易でないことだ。
コード
Pkg.installed()
using Pkg
Pkg.installed()
keys(Pkg.installed())
julia> Pkg.installed()
┌ Warning: Pkg.installed() is deprecated
└ @ Pkg ...\Pkg.jl:829
Dict{String, VersionNumber} with 26 entries:
"CSV" => v"0.10.15"
"PlotlyKaleido" => v"2.3.0"
"Random" => v"1.11.0"
⋮ => ⋮
最もきれいに現在インストールされているパッケージの一覧を名前とバージョンの辞書形式で返すが、警告にあるようにまもなく廃止される関数だ。単に keys で辞書のキーだけ取り出せばよいので、以下で説明する方法に比べて圧倒的に便利だ。自分だけで使うプログラムなら思う存分使い、実際に廃止されたときに別の代替に切り替えればよい。
Pkg.dependencies()
Pkg.dependencies()
getproperty.(collect(values(Pkg.dependencies())), :name)
julia> Pkg.dependencies()
Dict{Base.UUID, Pkg.API.PackageInfo} with 315 entries:
UUID("a4ae2306-e953-59d6-aa16-d00cac43593b") => PackageInfo("libaom_jll", v"3.12.1+0", "4bba74fa59ab0755…
UUID("0c81fc1b-5583-44fc-8770-48be1e1cca08") => PackageInfo("InputBuffers", v"1.1.1", "e5392ea00942566b6…
UUID("7c1d4256-1411-5781-91ec-d7bc3513ac07") => PackageInfo("DynamicPolynomials", v"0.6.3", "ca693f8707a…
UUID("53ae85a6-f571-4167-b2af-e1d143709226") => PackageInfo("SciMLStructures", v"1.7.0", "566c4ed301ccb2…
⋮ => ⋮
パッケージの依存関係をすべて把握できるパッケージ情報の辞書を返す。values で値を取り出したあと getproperty で :name 属性だけ取り出せばパッケージ名の配列が得られる。問題はこのパッケージ一覧が依存関係を網羅しているにもかかわらず、本当にユーザがインストールしたパッケージの一覧を返すのではなく、Julia の環境で Manifest.toml を参照するため実際と一致しないことだ。
Pkg.status()
Pkg.status()
buf = IOBuffer()
Pkg.status(; io=buf)
output = String(take!(buf))
_output = strip.(getproperty.(collect(eachmatch(r"] .+ v", output)), :match), Ref([' ', ']', 'v']))
julia> Pkg.status()
Status `C:\Users\rmsms\.julia\environments\v1.12\Project.toml`
[336ed68f] CSV v0.10.15
[861a8166] Combinatorics v1.0.3
[a93c6f00] DataFrames v1.8.0
[7806a523] DecisionTree v0.12.4
[b4f34e82] Distances v0.10.12
⌃ [7a1cc6ca] FFTW v1.9.0
[38e38edf] GLM v1.9.0
[86223c79] Graphs v1.13.1
[033835bb] JLD2 v0.6.2
[b964fa9f] LaTeXStrings v1.4.0
[470638dc] NoiseRobustDifferentiation v0.2.4
[e9f21f70] OpenAI v0.12.0
[9b87118b] PackageCompiler v2.2.2
[a03496cd] PlotlyBase v0.8.21
[f2990250] PlotlyKaleido v2.3.0
⌃ [91a5bcdd] Plots v1.40.19
⌃ [08abe8d2] PrettyTables v3.0.8
[92933f4c] ProgressMeter v1.11.0
[2913bbd2] StatsBase v0.34.6
[69024149] StringEncodings v0.3.7
⌃ [0c5d862f] Symbolics v6.54.0
[fdbf4ff8] XLSX v0.10.4
[ade2ca70] Dates v1.11.0
[37e2e46d] LinearAlgebra v1.12.0
[9a3f8284] Random v1.11.0
[2f01184e] SparseArrays v1.12.0
Info Packages marked with ⌃ have new versions available and may be upgradable.
最後の方法として見つけたのは、REPL で Pkg.status() が出力するパッケージ一覧を文字列として奪取することだ。IOBuffer を使って Pkg.status() の出力をバッファに入れ、take! で文字列に変換したあと、正規表現 r"] .+ v" でパッケージ名とバージョンがある行をすべて取得する。その後 getproperty で :match 属性だけ取り出し、strip で前後の空白と ]、v 文字を削除すればきれいにパッケージ名の配列が得られる。
やや複雑だが原理を理解して一行ずつ追えばそれほど難しい技巧ではなく、少なくともこの記事執筆時点では副作用が最も少なくきれいな方法だ。
以下はこの処理を簡単に使えるように installed という関数として書いたものだ。
function installed()
Pkg.status()
buf = IOBuffer()
Pkg.status(; io=buf)
output = String(take!(buf))
return strip.(getproperty.(collect(eachmatch(r"] .+ v", output)), :match), Ref([' ', ']', 'v']))
end
環境
- OS: Windows
- julia: v1.20.0
