64 lines
2.5 KiB
Python
64 lines
2.5 KiB
Python
"""
|
|
Draw it the way its structure asks to be drawn.
|
|
|
|
`ops.classify` reads the structure and names an emitter; this runs it. The whole
|
|
point is that nobody should have to know that a schema wants cards and a module
|
|
graph wants ranks — or discover it from a 235:1 image.
|
|
|
|
When the answer is "this is not a diagram", it says so and produces the index,
|
|
because that *is* the right artifact for a flat list of peers.
|
|
|
|
## One function, three callers
|
|
|
|
This branch — erd, or index, or dot through Graphviz — used to be written out
|
|
three times: in the `auto` command, in the `site` command choosing its picture,
|
|
and in the book choosing its graph step. Three copies of "which drawing does this
|
|
graph want" is three chances for them to disagree about the answer, so it lives
|
|
here and returns content rather than writing it. Where the file goes, and what
|
|
to call it, is the caller's business.
|
|
"""
|
|
|
|
from ..ops import classify
|
|
|
|
# What each emitter produces, so a caller can name the file without knowing
|
|
# which emitter ran.
|
|
SUFFIX = {"erd": ".svg", "dot": ".svg", "index": ".md"}
|
|
|
|
|
|
def draw(ir: dict, style, *, force: str | None = None) -> dict:
|
|
"""The drawing this graph asks for, as content.
|
|
|
|
Returns::
|
|
|
|
{"verdict": <classify's verdict>,
|
|
"emitter": "erd" | "dot" | "index",
|
|
"suffix": ".svg" | ".md",
|
|
"content": str | bytes | None, # None when it could not be drawn
|
|
"why": why this emitter, or why nothing was drawn}
|
|
|
|
Never raises for a missing Graphviz. A layered graph on a machine without
|
|
`dot` is a normal state — the book records the step as skipped and the site
|
|
goes text-only — so it is reported in `why` with `content` None.
|
|
"""
|
|
verdict = classify(ir)
|
|
chosen = force or verdict["emitter"]
|
|
out = {"verdict": verdict, "emitter": chosen, "suffix": SUFFIX.get(chosen, ".svg"),
|
|
"content": None, "why": verdict["why"]}
|
|
|
|
if chosen == "erd":
|
|
from .erd import emit
|
|
out["content"] = emit(ir, style)
|
|
elif chosen == "index":
|
|
from .index import to_markdown
|
|
out["content"] = to_markdown(ir)
|
|
elif chosen == "dot":
|
|
from .dot import emit, have_graphviz, render
|
|
if not have_graphviz():
|
|
out["why"] = "Graphviz is not installed — nothing drawn (apt install graphviz)"
|
|
else:
|
|
opts = verdict.get("options") or {}
|
|
out["content"] = render(emit(ir, style, rankdir=opts.get("rankdir")))
|
|
else:
|
|
raise ValueError(f"no emitter {chosen!r} — have: erd, dot, index")
|
|
return out
|