Reverse dependencies of a package?

Are there existing tools for evaluating the reverse dependencies of a package? That is, for determining the packages that depend directly or indirectly on a particular package?

It occurred to me that, if not, this might be an occasion for me to learn a bit more about the Registries used with Pkg3. How would I begin exploring the TOML capabilities if I decided to try to parse a Registry?

1 Like

Pkg.dependents will give you the direct dependencies at least. Shouldnโ€™t be hard to call it recursively if needed.

5 Likes

Thanks. It seems that I should have done a bit more research before asking the question.:grimacing:

https://juliaobserver.com will also give you this information.

2 Likes

This showed up in my Google search today. I donโ€™t think the answers here still work, so I feel compelled to post, with apology, a kludge that does work. Perhaps someone will also post a more elegant solution which makes use of the dependency graph that I believe Pkg maintains in the first place.

import Pkg
ctx = Pkg.Types.Context()

latest_version(ctx, uuid) = maximum(keys(Pkg.Operations.load_versions(Pkg.Types.registered_paths(ctx.env, uuid)[])))

function latest_pkgspec(ctx, name)
  uuid = Pkg.Types.registered_uuid(ctx.env, name)
  Pkg.Types.PackageSpec(name, uuid, latest_version(ctx, uuid))
end

latest_deps(pkg_name) = Pkg.Operations.load_deps(ctx, latest_pkgspec(ctx, pkg_name))
latest_deps("Plots") # trigger populating of ctx.env

function reverse_deps(ctx, pkg_name_query)
  all_names = map(
    x->if length(x) == 1; x[]; else; nothing; end,
    values(ctx.env.names))
  all_names = filter(!isnothing, all_names)
  [pkg_name for pkg_name in all_names if pkg_name_query in keys(latest_deps(pkg_name))]
end

reverse_deps(ctx, "BinDeps")

Thanks for this snippet. Just a small note โ€” in julia 1.4 I had to adjust this to use ctx rather than ctx.env.

1 Like

Updated to run w/ 1.5/1.6 below. I say to run because the output is wrong. Pkg.Operations.load_all_deps does not seem to be the correct function to get all dependencies for a package (assuming thatโ€™s what Pkg.Operations.load_deps did - it no longer exists). Rather, I believe load_all_deps returns all installed packages in the current environment.

julia> length(latest_deps("Revise"))
83
grep "\[\[" ~/.julia/environments/v1.6/Manifest.toml | wc -l
      83

Is there a function to return all dependencies based on a given package name or spec, ideally even if it is not installed?


import Pkg
ctx = Pkg.Types.Context()

latest_version(ctx, uuid) = maximum(keys(Pkg.Operations.load_versions(ctx, Pkg.Types.registered_paths(ctx, uuid)[])))

function latest_pkgspec(ctx, name)
  uuid = Pkg.Types.registered_uuid(ctx, name)
  Pkg.Types.PackageSpec(name, uuid, latest_version(ctx, uuid))
end

latest_deps(pkg_name) = map(x->x.name, Pkg.Operations.load_all_deps(ctx, [latest_pkgspec(ctx, pkg_name)]))
latest_deps("Plots") # trigger populating of ctx.env

function reverse_deps(ctx, pkg_name_query)
  all_names = map(
    x->if length(x) == 1; x[]; else; nothing; end,
    values(ctx.env.names))
  all_names = filter(!isnothing, all_names)
  [pkg_name for pkg_name in all_names if pkg_name_query in latest_deps(pkg_name)]
end

For anyone who found this topic through Google you can now (1.9) do

help?> Pkg.dependencies
  Pkg.dependencies()::Dict{UUID, PackageInfo}

  This feature is considered experimental.

  Query the dependency graph of the active project. The result is a Dict that maps a package UUID to a PackageInfo struct representing the dependency (a package).

  PackageInfo fields
  โ‰กโ‰กโ‰กโ‰กโ‰กโ‰กโ‰กโ‰กโ‰กโ‰กโ‰กโ‰กโ‰กโ‰กโ‰กโ‰กโ‰กโ‰กโ‰กโ‰ก

  Field                Description
  โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“ โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“โ€“
  name                 The name of the package
  version              The version of the package (this is Nothing for stdlibs)
  tree_hash            A file hash of the package directory tree
  is_direct_dep        The package is a direct dependency
  is_pinned            Whether a package is pinned
  is_tracking_path     Whether a package is tracking a path
  is_tracking_repo     Whether a package is tracking a repository
  is_tracking_registry Whether a package is being tracked by registry i.e. not by path nor by repository
  git_revision         The git revision when tracking by repository
  git_source           The git source when tracking by repository
  source               The directory containing the source code for that package
  dependencies         The dependencies of that package as a vector of UUIDs

1 Like

Wait, doesnโ€™t this just give the dependencies of the currently active project? If I understood the question correctly, itโ€™s about finding the packages that depend on a given package. So, e.g. finding all the packages that use Plots or something like that.

Ah, yeah I misread.

This might do the trick for direct deps:

import Pkg
ctx = Pkg.Types.Context();

function reverse_deps(name)
    nuuid = Pkg.Types.registered_uuid(ctx.registries, name)
    dd = Dict{String,Base.UUID}()
    isnothing(nuuid) && "$name not known"
    for reg in Pkg.Registry.reachable_registries()
        for (uuid, regpkg) in reg
            pkg = Pkg.Registry.registry_info(regpkg)
            deps = reduce(merge, values(pkg.deps), init=Dict{String,Base.UUID}())
            x = get(deps, name, nothing)
            if !isnothing(x) && x == nuuid
                dd[regpkg.name] = uuid
            end

        end
    end
    dd
end

julia> reverse_deps("Plots")
Dict{String, Base.UUID} with 386 entries:
  "Kinetic"                          => UUID("82403725-3cee-4f7c-b214-1ce71af4a797")
  "SchumakerSpline"                  => UUID("65e68595-3a03-5ff5-a6a2-f05fa774f32e")
  "PicoQuant"                        => UUID("2db47837-5a65-4a20-8d0f-8ec2491baa53")
  "CellularPotts"                    => UUID("11b7dee7-cd95-48a5-a457-717aae94d0bd")
  "StockFlow"                        => UUID("58c4a0e8-2944-4d18-9fa2-e17726aee9e5")
  "Dyn3d"                            => UUID("d8047ffa-7f43-11e9-2204-adfbb6974ec5")
  "AirfoilGmsh"                      => UUID("e68ec710-8e48-43c5-af1a-c38c4248fd7b")
  "FlightGNC"                        => UUID("f141b7d0-6781-47a7-9266-a0707263841d")
  "AgentsPlots"                      => UUID("7820620d-95fb-4739-93b3-b0a14dd83f9a")
  "ItsLive"                          => UUID("774cd0c4-ba78-41e4-92fb-f5f90e3791d1")
  "BifurcationKit"                   => UUID("0f109fa4-8a5d-4b75-95aa-f515264e7665")
  "Population"                       => UUID("11b83ad2-e65e-47ba-870b-1ff818f3e30a")
  "LaplaceRedux"                     => UUID("c52c1a26-f7c5-402b-80be-ba1e638ad478")
  "ScenTreesMakie"                   => UUID("9bd120df-771c-42ec-88b3-c561e7179d1b")
  "AbstractPDEInterfaces"            => UUID("db474457-f03d-4fd7-b196-5f323c96c803")
  "SemanticModels"                   => UUID("f5ac2a72-33c7-5caf-b863-f02fefdcf428")
  "VisClaw"                          => UUID("d5c85fe6-8620-4d3a-96f0-ac478d4f5d38")
  "AtariAlgos"                       => UUID("faabce77-3242-5060-abab-4a4767a0df42")
  "Smg2s"                            => UUID("36e52ba8-0d61-4da2-bc57-6d85c7a279e7")
  "FundamentalsNumericalComputation" => UUID("e48b7b93-d2a8-4750-aba7-f743ccd5256c")
  "Soss"                             => UUID("8ce77f84-9b61-11e8-39ff-d17a774bf41c")
  "DFTK"                             => UUID("acf6eb54-70d9-11e9-0013-234b7a5f5337")
  "CycleSolver"                      => UUID("3b43121a-1122-4a83-b2b6-7ec1eb6161aa")
  "CausalForest"                     => UUID("31bdf679-24a7-499a-9be9-b214c66174ea")
  "LineIntegralConvolution"          => UUID("954431ae-a746-4b0b-bf75-a8381ca95b21")
  "TreesHeaps"                       => UUID("11f3e0e9-035a-4796-9f15-e39fd2303e8e")
  "Huginn"                           => UUID("9cb796e9-d0ea-421b-b37d-eb97bc1add55")
  "AlgebraicDynamics"                => UUID("5fd6ff03-a254-427e-8840-ba658f502e32")
  "PosteriorPlots"                   => UUID("196f2941-2d58-45ba-9f13-43a2532b2fa8")
  "Bioinformatics"                   => UUID("c429c406-9079-5a14-8339-dedc8835de90")
  "SSMPlots"                         => UUID("b9734e3f-1fb5-4b0f-895a-a4ed7ba034cc")
  "VoronoiFVM"                       => UUID("82b139dc-5afc-11e9-35da-9b9bdfd336f3")
  "LazySets"                         => UUID("b4f0291d-fe17-52bc-9479-3d1a343d9043")
  "IndirectTrajOpt"                  => UUID("99e47ffd-a99c-4d17-8b51-d4481b168213")
  "Skyler"                           => UUID("804faec8-72f5-11ea-307d-47b816e9b733")
  "MOSLab"                           => UUID("646a8480-3455-4dcb-93e7-a10dc646a0af")
  "Trixi2Img"                        => UUID("821991e7-028e-4e54-884c-f74f8833bc95")
  "MonotoneSplines"                  => UUID("92812004-5f8d-4354-96af-0c8b7c0637d0")
  "BoseWormPIMC"                     => UUID("bd945c55-3bff-4c7d-84e7-fefb69b5105e")
  "ConScape"                         => UUID("2ba2d6f2-f651-5162-bda8-601e45ce5244")
  "Clines"                           => UUID("b03ef683-e087-4e84-9649-40693305c655")
  "AlphaZero"                        => UUID("8ed9eb0b-7496-408d-8c8b-2119aeea02cd")
  "Solaris"                          => UUID("c31bc6c7-79d6-424e-a85f-5b42ee086500")
  "KnetMetrics"                      => UUID("33081891-0f5e-47f5-81c7-76d5d1fed490")
  "Bingomatic"                       => UUID("5d0f211d-823e-4d77-a844-586f1e6d1e5a")
  "ConservationLawsParticles"        => UUID("dbb53eb6-f4e4-11e9-1aca-071dd871ed0a")
  "RvSpectMLPlots"                   => UUID("6ad363e8-653f-4efd-a04b-f033e69a984c")
  "ClimaCore"                        => UUID("d414da3d-4745-48bb-8d80-42e94e092884")
  "TightBindingToolkit"              => UUID("2233325a-6eb3-486f-aff0-670e0939fa7e")
  "LassoPlot"                        => UUID("21d151f5-1f6d-55ec-8524-1c9aee35b0a4")
  "FixedPointToolkit"                => UUID("081f7a28-ac82-48c1-a10e-fa8b3349a52a")
  "BifurcationInference"             => UUID("7fe238d6-d31e-4646-aa16-9d8429fd6da8")
  โ‹ฎ                                  => โ‹ฎ
2 Likes