Package pretty tree

Hello,

So I may be wrong, but I have been looking and asking around, and I found no package that builds a pretty tree of a package content.

Something like this:

ClimaLand
├─ Artifacts
├─ Bucket
├─ Canopy
│  └─ PlantHydraulics
├─ Diagnostics
├─ Domains
├─ Parameters
├─ Pond
├─ Snow
└─ Soil
   ├─ Biogeochemistry
   └─ Runoff

that display the package main Module and submodules
and hopefully it’d be even better if you’d see functions and struct exported from the module, in different colors (e.g., red for functions, blue for struct), with the possibility to expand or collapse…

To get a list of the modules of the package ClimaLand I did:

function get_module_hierarchy(mod::Module, prefix="")
    result = String[]
    mod_name = string(nameof(mod))
    full_prefix = isempty(prefix) ? mod_name : "$prefix.$mod_name"
    
    for name in names(mod, all=true)
        if !startswith(string(name), "#")
            obj = getproperty(mod, name)
            if obj isa Module && obj != mod
                full_name = "$full_prefix.$name"
                push!(result, full_name)
                append!(result, get_module_hierarchy(obj, full_prefix))
            end
        end
    end
    return sort(result)
end

and to build the tree:

using AbstractTrees
# Define a simple tree node type
struct ModuleNode
    name::String
    children::Vector{ModuleNode}
end
# Implement the required methods for AbstractTrees
AbstractTrees.children(node::ModuleNode) = node.children
AbstractTrees.printnode(io::IO, node::ModuleNode) = print(io, node.name)
# Create your tree structure
climatree = ModuleNode("ClimaLand", [
    ModuleNode("Artifacts", []),
    ModuleNode("Bucket", []),
    ModuleNode("Canopy", [
        ModuleNode("PlantHydraulics", [])
    ]),
    ModuleNode("Diagnostics", []),
    ModuleNode("Domains", []),
    ModuleNode("Parameters", []),
    ModuleNode("Pond", []),
    ModuleNode("Snow", []),
    ModuleNode("Soil", [
        ModuleNode("Biogeochemistry", []),
        ModuleNode("Runoff", [])
    ])
])

But I wish there was a package that you just do e.g., PackageTree(nameofpackage)

and you’d have a beautiful tree… If it doesn’t exist, I am surprised, I think it would be amazing to have it in docs etc.

1 Like

PkgDependency.jl provides a tree of dependencies, which is the not the same concept, but very useful. Sharing it here for future readers.

1 Like

That is neat.
To me such tree (dependencies or submodules + exported abstractions of a package) is so essential that it belongs in Main.
I am surprised it doesn’t exist yet. But sounds like a good package writing opportunity.

the closest we have is names() which is great but not complete

Maybe that’s something that could be part of @tecosaur’s About.jl?

2 Likes

About.jl seems very nice and it would indeed be a great fit!

I think the current display for about(::Module) should be pretty close to what you mention wanting, it displays submodules, macros, types, functions, variables in different colours, and tells you what’s exported/public.

It would mention the submodules, but they’re neither exported nor public.

5 Likes

Would it be possible/beneficial to compose About.jl with MethodAnalysis.jl?
Home · MethodAnalysis.jl (timholy.github.io)

1 Like

This is great!

We are not exporting submodules because they have a lot of functions and struct and we don’t want to crowd the namespace (does that make sense?) but a user can still do import ClimaLand.Soil.Biogeochemistry, for example.

But to be honest, we haven’t thought much about the structure, what to export or not, etc. There’s work to do.

But I think if a functionality like about or a tree of a package was more in our mind during development, we would’ve paid more attention to it. My point is, in general, such functionality could help tidy development and discoverability (again, does that make sense?)

I’d love to add in the first two pages of our docs a table or tree of our package that give a broad vision of the structure / organization of the package, maybe with or without exported modules/functions/structs as an option, and maybe with foldables (but I understand folding may not be ideal in the REPL).

We should keep this discussion going! And I am happy to contribute to an effort.

Looks like child_modules is pretty close to what I wanted!

I agree child_modules + about would be close to deliver everything

@tecosaur did you do anything special to have types printed in different colors? (maybe this not the latest release?) when I use about(::Module) I get the same output, but submodules, macros, types, functions, … are all printed in the same color.

For me this is a difference between using Julia 1.10 (no colors) and 1.11 (colors).

1 Like