add project, change cli file names, use config
This commit is contained in:
1
soleprint/atlas2/docgen/.gitignore
vendored
1
soleprint/atlas2/docgen/.gitignore
vendored
@@ -2,3 +2,4 @@
|
||||
out/
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.venv/
|
||||
|
||||
@@ -1,31 +1,33 @@
|
||||
# docgen — code to diagram, and to everything else the IR can feed.
|
||||
#
|
||||
# Derived from where this file sits, so the folder can be copied anywhere and
|
||||
# renamed and still work. The logic lives in the Python, never here.
|
||||
# renamed and still work. The logic lives in the Python, never here: every target
|
||||
# is one line calling `python3 -m docgen <command>`.
|
||||
#
|
||||
# make sync create .venv with every optional group (uv)
|
||||
# make book SRC=../station the whole operation, measured at both ends
|
||||
# make run CONFIG=docgen.toml every book a run file lists
|
||||
# make check prove docgen, on a tree it builds itself
|
||||
# make check BOOK=out/book/x prove one book — its own level
|
||||
# make ir SRC=../station extract -> out/ir.json (one step, on its own)
|
||||
# make graph out/ir.json -> out/graph.svg
|
||||
# make index out/ir.json -> out/index.md
|
||||
# make self docgen's book of itself, then check it
|
||||
# make doctor what this machine has
|
||||
#
|
||||
# Every target below is one step of a book and still works alone — that is the
|
||||
# property the book spine exists to preserve, not to replace.
|
||||
# Every step target still works alone — that is the property the book spine
|
||||
# exists to preserve, not to replace. The steps compose by hand too:
|
||||
#
|
||||
# The pipeline is three commands and they compose, which is the point:
|
||||
#
|
||||
# python3 -m docgen.extractors.python --root SRC -o ir.json
|
||||
# python3 -m docgen.ops ir.json --overview -o view.json
|
||||
# python3 -m docgen.emitters dot view.json -o graph.svg --theme dark
|
||||
# python3 -m docgen extract python --root SRC -o ir.json
|
||||
# python3 -m docgen view ir.json --overview -o view.json
|
||||
# python3 -m docgen emit dot view.json -o graph.svg --theme dark
|
||||
|
||||
HERE := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
|
||||
PKG := $(notdir $(HERE))
|
||||
PARENT := $(patsubst %/,%,$(dir $(HERE)))
|
||||
PY ?= python3
|
||||
RUN := PYTHONPATH=$(PARENT) $(PY) -m
|
||||
VENV_PY := $(HERE)/.venv/bin/python
|
||||
# The synced environment when there is one (`make sync`), the system Python when
|
||||
# there is not — so `make check` still works with nothing installed at all.
|
||||
PY ?= $(if $(wildcard $(VENV_PY)),$(VENV_PY),python3)
|
||||
CLI := PYTHONPATH=$(PARENT) $(PY) -m $(PKG)
|
||||
|
||||
OUT ?= $(HERE)/out
|
||||
SRC ?=
|
||||
@@ -34,20 +36,25 @@ OPENAPI ?=
|
||||
HAR ?=
|
||||
STYLE ?= lucid
|
||||
THEME ?=
|
||||
DEPTH ?= 2
|
||||
SCALE ?= 0.55
|
||||
BOOK ?=
|
||||
SLUG ?=
|
||||
# NOT `LANG`: that is the shell's locale variable, so `?=` inherits
|
||||
# en_US.UTF-8 from the environment and --lang rejects it.
|
||||
# en_US.UTF-8 from the environment and --reader rejects it.
|
||||
READER ?= python
|
||||
OVERLAY ?=
|
||||
CONFIG ?= docgen.toml
|
||||
ONLY ?=
|
||||
CHECK ?=
|
||||
|
||||
comma := ,
|
||||
THEME_ARG := $(if $(THEME),--theme $(THEME))
|
||||
STYLE_ARGS := --style $(STYLE) $(THEME_ARG)
|
||||
SLUG_ARG := $(if $(SLUG),--slug $(SLUG))
|
||||
OVER_ARG := $(if $(OVERLAY),--overlay $(OVERLAY))
|
||||
ONLY_ARGS := $(foreach n,$(subst $(comma), ,$(ONLY)),--only $(n))
|
||||
|
||||
.PHONY: help book check ir db code graph index site minimap explore docs view self doctor clean
|
||||
.PHONY: help sync lock book run check ir db code view graph index site minimap explore docs self doctor clean
|
||||
|
||||
help: ## List every target
|
||||
@echo "docgen — static analysis of a tree, and the artifacts that fall out of it"
|
||||
@@ -61,62 +68,81 @@ help: ## List every target
|
||||
@echo " BOOK=/path where a book goes, and which book to check"
|
||||
@echo " READER=python|code ast, or tree-sitter SLUG=name what to call the book"
|
||||
@echo " OVERLAY=overlay.json hand-written notebook additions, re-applied every build"
|
||||
@echo " DEPTH=2 how deep to draw"
|
||||
@echo " CONFIG=docgen.toml a run file ONLY=a,b just these books"
|
||||
@echo " CHECK=1 with run: each book's own level after building it"
|
||||
@echo
|
||||
@echo " Three levels of test, by what they assert about:"
|
||||
@echo " make doctor the machine. Never fails."
|
||||
@echo " make check docgen. Exits 1."
|
||||
@echo " make check BOOK=<dir> that book. Exits 1."
|
||||
|
||||
check: ## Prove docgen (or one book, with BOOK=<dir>)
|
||||
@if [ -n "$(BOOK)" ]; then \
|
||||
$(RUN) $(PKG).book.checks "$(BOOK)"; \
|
||||
else \
|
||||
$(PY) $(HERE)/selftest.py; \
|
||||
fi
|
||||
sync: ## Create .venv with every optional group, from uv.lock
|
||||
@command -v uv >/dev/null || { echo "Error: uv is not installed — docgen still runs on the system python3" >&2; exit 1; }
|
||||
@cd $(HERE) && uv sync --all-groups
|
||||
|
||||
lock: ## Re-resolve uv.lock after editing pyproject.toml
|
||||
@cd $(HERE) && uv lock
|
||||
|
||||
book: ## SRC (or SCHEMA/OPENAPI/HAR) -> one operation, measured at both ends
|
||||
@test -n "$(SRC)$(SCHEMA)$(OPENAPI)$(HAR)" \
|
||||
|| { echo "Error: set SRC=/path/to/tree (or SCHEMA=, OPENAPI=, HAR=)" >&2; exit 1; }
|
||||
@$(RUN) $(PKG).book \
|
||||
$(if $(SRC),--root "$(SRC)" --lang $(READER)) \
|
||||
@$(CLI) book \
|
||||
$(if $(SRC),--root "$(SRC)" --reader $(READER)) \
|
||||
$(if $(SCHEMA),--schema "$(SCHEMA)") \
|
||||
$(if $(OPENAPI),--openapi "$(OPENAPI)") \
|
||||
$(if $(HAR),--har "$(HAR)") \
|
||||
-o "$(if $(BOOK),$(BOOK),$(OUT)/book)" \
|
||||
--style $(STYLE) $(THEME_ARG) $(SLUG_ARG) $(OVER_ARG)
|
||||
$(STYLE_ARGS) $(SLUG_ARG) $(OVER_ARG)
|
||||
|
||||
run: ## CONFIG (a run file) -> every book it lists; ONLY=a,b for some
|
||||
@$(CLI) run "$(CONFIG)" $(ONLY_ARGS) $(if $(CHECK),--check)
|
||||
|
||||
check: ## Prove docgen (or one book, with BOOK=<dir>)
|
||||
@$(CLI) check $(if $(BOOK),"$(BOOK)")
|
||||
|
||||
ir: ## Extract SRC into OUT/ir.json
|
||||
@test -n "$(SRC)" || { echo "Error: set SRC=/path/to/tree" >&2; exit 1; }
|
||||
@mkdir -p $(OUT)
|
||||
@$(RUN) $(PKG).extractors.python --root "$(SRC)" -o $(OUT)/ir.json
|
||||
@$(RUN) $(PKG).ir $(OUT)/ir.json
|
||||
@$(CLI) extract python --root "$(SRC)" -o $(OUT)/ir.json
|
||||
@$(CLI) validate $(OUT)/ir.json
|
||||
|
||||
code: ## Extract C#/TypeScript from SRC (needs the `code` group)
|
||||
@test -n "$(SRC)" || { echo "Error: set SRC=/path/to/tree" >&2; exit 1; }
|
||||
@$(CLI) extract code --root "$(SRC)" -o $(OUT)/ir.json
|
||||
@$(CLI) validate $(OUT)/ir.json
|
||||
|
||||
db: ## Extract a graphgen-compatible SCHEMA into OUT/ir.json
|
||||
@test -n "$(SCHEMA)" || { echo "Error: set SCHEMA=/path/to/schema.json" >&2; exit 1; }
|
||||
@mkdir -p $(OUT)
|
||||
@$(RUN) $(PKG).extractors --schema "$(SCHEMA)" -o $(OUT)/ir.json
|
||||
@$(RUN) $(PKG).ir $(OUT)/ir.json
|
||||
@$(CLI) extract db --schema "$(SCHEMA)" -o $(OUT)/ir.json
|
||||
@$(CLI) validate $(OUT)/ir.json
|
||||
|
||||
view: ## OUT/ir.json -> OUT/view.json, the default view for its source type
|
||||
@$(RUN) $(PKG).ops $(OUT)/ir.json --overview -o $(OUT)/view.json
|
||||
@$(CLI) view $(OUT)/ir.json --overview -o $(OUT)/view.json
|
||||
|
||||
graph: view ## OUT/view.json -> whatever its structure asks for
|
||||
@$(RUN) $(PKG).emitters auto $(OUT)/view.json -o $(OUT) \
|
||||
--style $(STYLE) $(THEME_ARG)
|
||||
@$(CLI) emit auto $(OUT)/view.json -o $(OUT) $(STYLE_ARGS)
|
||||
|
||||
index: ## OUT/ir.json -> OUT/index.md and OUT/sidebar.json
|
||||
@$(CLI) emit index $(OUT)/ir.json -o $(OUT)/index.md
|
||||
@$(CLI) emit index $(OUT)/ir.json -o $(OUT)/sidebar.json
|
||||
|
||||
site: view ## OUT/view.json -> a self-contained docs site in OUT/site
|
||||
@$(RUN) $(PKG).emitters site $(OUT)/view.json -o $(OUT)/site \
|
||||
--style $(STYLE) $(THEME_ARG)
|
||||
@$(CLI) emit site $(OUT)/view.json -o $(OUT)/site $(STYLE_ARGS)
|
||||
@echo " open $(OUT)/site/index.html"
|
||||
|
||||
minimap: ## OUT/ir.json -> OUT/minimap.svg — what is where, read from the colours
|
||||
@$(CLI) emit minimap $(OUT)/ir.json -o $(OUT)/minimap.svg $(STYLE_ARGS) --scale $(SCALE)
|
||||
|
||||
explore: ## OUT/ir.json -> OUT/explore/ — navigate on one side, explore on the other
|
||||
@$(CLI) emit explore $(OUT)/ir.json -o $(OUT)/explore $(STYLE_ARGS) --scale $(SCALE)
|
||||
@echo " open $(OUT)/explore/explore.html"
|
||||
|
||||
docs: ## Regenerate the figures in docs/ — docgen documented by docgen
|
||||
@mkdir -p docs/img
|
||||
@$(RUN) $(PKG).extractors.python --root $(HERE) -o /tmp/$(PKG)-docs.json >/dev/null
|
||||
@$(RUN) $(PKG).ops /tmp/$(PKG)-docs.json --overview -o /tmp/$(PKG)-docs-view.json >/dev/null
|
||||
@$(RUN) $(PKG).emitters dot /tmp/$(PKG)-docs-view.json -o docs/img/architecture.svg -q
|
||||
@$(RUN) $(PKG).emitters minimap /tmp/$(PKG)-docs.json -o docs/img/minimap.svg --scale 0.5 --width 860
|
||||
@$(RUN) $(PKG).emitters erd $(OUT)/ir.json -o docs/img/erd.svg 2>/dev/null \
|
||||
@mkdir -p $(HERE)/docs/img
|
||||
@$(CLI) extract python --root $(HERE) -o /tmp/$(PKG)-docs.json >/dev/null
|
||||
@$(CLI) view /tmp/$(PKG)-docs.json --overview -o /tmp/$(PKG)-docs-view.json >/dev/null
|
||||
@$(CLI) emit dot /tmp/$(PKG)-docs-view.json -o $(HERE)/docs/img/architecture.svg -q
|
||||
@$(CLI) emit minimap /tmp/$(PKG)-docs.json -o $(HERE)/docs/img/minimap.svg --scale 0.5 --width 860
|
||||
@$(CLI) emit erd $(OUT)/ir.json -o $(HERE)/docs/img/erd.svg 2>/dev/null \
|
||||
|| echo " (erd figure kept — needs a schema IR at $(OUT)/ir.json to refresh)"
|
||||
@PYTHONPATH=$(PARENT) $(PY) -c "from $(PKG).emitters.site import VIEWER, _slots, _fill; \
|
||||
from $(PKG).style import Style; import pathlib; \
|
||||
@@ -124,25 +150,6 @@ pathlib.Path('$(HERE)/docs/viewer.html').write_text( \
|
||||
_fill(VIEWER.replace('__TITLE__', 'docgen docs'), _slots(Style.load('lucid'))))"
|
||||
@echo " open $(HERE)/docs/index.html"
|
||||
|
||||
explore: ## OUT/ir.json -> OUT/explore/ — navigate on one side, explore on the other
|
||||
@$(RUN) $(PKG).emitters explore $(OUT)/ir.json -o $(OUT)/explore \
|
||||
--style $(STYLE) $(THEME_ARG) --scale $(SCALE)
|
||||
@echo " open $(OUT)/explore/explore.html"
|
||||
|
||||
minimap: ## OUT/ir.json -> OUT/minimap.svg — what is where, read from the colours
|
||||
@$(RUN) $(PKG).emitters minimap $(OUT)/ir.json -o $(OUT)/minimap.svg \
|
||||
--style $(STYLE) $(THEME_ARG) --scale $(SCALE)
|
||||
|
||||
code: ## Extract C#/TypeScript from SRC (needs tree-sitter)
|
||||
@test -n "$(SRC)" || { echo "Error: set SRC=/path/to/tree" >&2; exit 1; }
|
||||
@mkdir -p $(OUT)
|
||||
@$(RUN) $(PKG).extractors code --root "$(SRC)" -o $(OUT)/ir.json
|
||||
@$(RUN) $(PKG).ir $(OUT)/ir.json
|
||||
|
||||
index: ## OUT/ir.json -> OUT/index.md and OUT/sidebar.json
|
||||
@$(RUN) $(PKG).emitters index $(OUT)/ir.json -o $(OUT)/index.md
|
||||
@$(RUN) $(PKG).emitters index $(OUT)/ir.json -o $(OUT)/sidebar.json
|
||||
|
||||
self: ## docgen's book of the widest tree it can see, then check it
|
||||
@$(eval SELF_SRC := $(shell PYTHONPATH=$(PARENT) $(PY) -c "from $(PKG) import reference; \
|
||||
r = reference.root(); print(r if r else '$(HERE)')"))
|
||||
@@ -153,18 +160,19 @@ r = reference.root(); print(r if r else '$(HERE)')"))
|
||||
@$(MAKE) --no-print-directory check BOOK=$(OUT)/book/self
|
||||
|
||||
doctor: ## Report whether this machine can run it
|
||||
@printf 'python : '; $(PY) --version 2>&1 || echo MISSING
|
||||
@printf 'python : %s ' '$(PY)'; $(PY) --version 2>&1 || echo MISSING
|
||||
@printf 'uv : '; if ! command -v uv >/dev/null; then echo 'absent — fine; docgen runs on the system python3'; \
|
||||
elif [ -x $(VENV_PY) ]; then echo "$$(uv --version), .venv synced"; \
|
||||
else echo "$$(uv --version), .venv not synced — make sync for the optional groups"; fi
|
||||
@printf 'dot : '; (dot -V 2>&1) || echo 'MISSING — sudo apt install graphviz (only to render)'
|
||||
@printf 'tree-sit : '; $(PY) -c 'import tree_sitter, tree_sitter_c_sharp, tree_sitter_typescript; print("ok — C# and TypeScript available")' 2>/dev/null || echo 'absent — Python only. pip install tree_sitter tree_sitter_c_sharp tree_sitter_typescript'
|
||||
@printf 'networkx : '; $(PY) -c 'import networkx; print(networkx.__version__ + " — for lab/ experiments")' 2>/dev/null || echo 'absent — only used in lab/'
|
||||
@printf 'package : %s (from %s)\n' '$(PKG)' '$(PARENT)'
|
||||
@printf 'tree-sit : '; $(PY) -c 'import tree_sitter, tree_sitter_c_sharp, tree_sitter_typescript; print("ok — C# and TypeScript available")' 2>/dev/null || echo 'absent — Python only. make sync, or the `code` group'
|
||||
@printf 'lxml : '; $(PY) -c 'import lxml; print("ok — theme harvesting available")' 2>/dev/null || echo 'absent — only used to harvest a theme'
|
||||
@printf 'yaml : '; $(PY) -c 'import yaml; print("ok — needed only to read OpenAPI")' 2>/dev/null || echo 'absent — only used by the OpenAPI reader'
|
||||
@printf 'networkx : '; $(PY) -c 'import networkx; print(networkx.__version__ + " — for lab/ experiments")' 2>/dev/null || echo 'absent — only used in lab/'
|
||||
@printf 'reference: '; PYTHONPATH=$(PARENT) $(PY) -c "from $(PKG) import reference; print(reference.describe())"
|
||||
|
||||
@printf 'styles : '; $(RUN) $(PKG).style 2>/dev/null \
|
||||
|| $(RUN) $(PKG) 2>/dev/null \
|
||||
|| PYTHONPATH=$(PARENT) $(PY) -c "from $(PKG).style import Style; print(', '.join(Style.available()))"
|
||||
@PYTHONPATH=$(PARENT) $(PY) -c "import $(PKG).ir, $(PKG).emitters.dot, $(PKG).ops" >/dev/null 2>&1 \
|
||||
@printf 'package : %s (from %s)\n' '$(PKG)' '$(PARENT)'
|
||||
@printf 'styles : '; PYTHONPATH=$(PARENT) $(PY) -c "from $(PKG).style import Style; print(', '.join(Style.available()))"
|
||||
@PYTHONPATH=$(PARENT) $(PY) -c "import $(PKG).ir, $(PKG).emitters.dot, $(PKG).ops, $(PKG).cli" >/dev/null 2>&1 \
|
||||
&& echo 'import : ok' || echo 'import : FAILED — is the folder intact?'
|
||||
|
||||
clean: ## Delete OUT. Nothing else is ever written to
|
||||
|
||||
@@ -14,19 +14,68 @@ extractors/ → graph IR (JSON) → emitters/
|
||||
```
|
||||
|
||||
```bash
|
||||
make sync # optional: .venv with every group, from uv.lock
|
||||
make check # prove it, on a tree it builds itself
|
||||
make self # run the whole thing over soleprint
|
||||
make ir SRC=../../station/tools/histgen
|
||||
make index && make graph
|
||||
make book SRC=/path/to/repo # one whole operation, measured at both ends
|
||||
make run CONFIG=docgen.toml # every book a run file lists
|
||||
make help
|
||||
```
|
||||
|
||||
Or as three composable commands, which is what the Makefile is wrapping:
|
||||
The full documentation is `docs/index.html` — open it in a browser.
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
cli/ the command line — every command, and nothing else
|
||||
book/ an operation: larder measure, steps, web output, run files
|
||||
extractors/ source -> IR, one per source type
|
||||
ir/ the contract: schema.json, the dataclasses, the validator
|
||||
ops/ IR -> a smaller IR
|
||||
emitters/ IR -> an artifact
|
||||
notebook/ the notebook spec, before it is an .ipynb
|
||||
style/ slots, themes, and harvesting a theme from real diagrams
|
||||
fixtures/ docgen's own test inputs
|
||||
lab/ sanctioned experiments; nothing imports it
|
||||
reference.py the one seam to the repo above, for reading OpenAPI
|
||||
```
|
||||
|
||||
Library packages hold **no command-line code** — no argparse, no `__main__.py`,
|
||||
no `cli_dot.py` beside `dot.py`. It all lives in `cli/`, behind one entry point,
|
||||
and the selftest asserts it stays there.
|
||||
|
||||
`pyproject.toml` declares no required dependency: the structural path is the
|
||||
stdlib, Python 3.11+. The optional groups (`code`, `openapi`, `harvest`, `lab`)
|
||||
are pinned in `uv.lock`; `[tool.uv] package = false`, as dataconvert does, since
|
||||
this is a folder run in place rather than something to install.
|
||||
|
||||
## Run files
|
||||
|
||||
```toml
|
||||
# docgen.toml — beside the project it describes; paths relative to this file
|
||||
[defaults]
|
||||
out = "out/book"
|
||||
|
||||
[[book]]
|
||||
name = "station"
|
||||
root = "../soleprint/station"
|
||||
|
||||
[[book]]
|
||||
name = "shop"
|
||||
schema = "schemas/shop.json"
|
||||
```
|
||||
|
||||
`make run CONFIG=docgen.toml [ONLY=station] [CHECK=1]`. One failing book never
|
||||
stops the others; unknown keys are refused; a rebuild replaces the previous
|
||||
build's outputs and never touches a hand-written `checks.py`.
|
||||
`docgen.example.toml` runs against the shipped fixtures.
|
||||
|
||||
Or as three composable commands, which is what the Makefile is wrapping — run
|
||||
from the directory above this one:
|
||||
|
||||
```bash
|
||||
python3 -m docgen.extractors.python --root SRC -o ir.json
|
||||
python3 -m docgen.ops ir.json --drop-stdlib -o view.json
|
||||
python3 -m docgen.emitters dot view.json -o graph.svg --theme dark
|
||||
python3 -m docgen extract python --root SRC -o ir.json
|
||||
python3 -m docgen view ir.json --drop-stdlib -o view.json
|
||||
python3 -m docgen emit dot view.json -o graph.svg --theme dark
|
||||
```
|
||||
|
||||
## DOT collapses three concerns; this separates them
|
||||
@@ -71,7 +120,7 @@ boundary, and it reads the field lists out of `schema.json` so the two cannot
|
||||
drift.
|
||||
|
||||
```bash
|
||||
python3 -m docgen.ir ir.json
|
||||
python3 -m docgen validate ir.json
|
||||
```
|
||||
|
||||
It catches what a schema cannot: an edge naming a node that does not exist, a
|
||||
@@ -124,7 +173,7 @@ belongs to every consumer at once — the index, the diagram and the diff all wa
|
||||
"just this subsystem, two hops out, without the stdlib".
|
||||
|
||||
```bash
|
||||
python3 -m docgen.ops ir.json --drop-stdlib --around docgen.ir --hops 2 -o view.json
|
||||
python3 -m docgen view ir.json --drop-stdlib --around docgen.ir --hops 2 -o view.json
|
||||
```
|
||||
|
||||
`drop_stdlib`, `drop_external`, `only_kinds`, `drop_kinds`, `subtree`,
|
||||
@@ -191,7 +240,9 @@ about either.
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
make check # 59 checks, offline, nothing installed
|
||||
make check # docgen's own suite: 287 after make sync, 272 with nothing
|
||||
make check BOOK=out/book/x # one book's own level — generated and hand-written checks
|
||||
make doctor # the machine; never fails
|
||||
```
|
||||
|
||||
**Golden tests go on the IR, never on the SVG.** Graphviz measures label text
|
||||
@@ -202,7 +253,7 @@ Self-hosting is the honest end-to-end check, and it is where the real bugs came
|
||||
from — two name-resolution faults that no fixture had reached:
|
||||
|
||||
```bash
|
||||
make self # extract soleprint, and read out/index.md
|
||||
make self # docgen's book of the widest tree it can see, then its checks
|
||||
```
|
||||
|
||||
## Where this sits
|
||||
|
||||
8
soleprint/atlas2/docgen/__main__.py
Normal file
8
soleprint/atlas2/docgen/__main__.py
Normal file
@@ -0,0 +1,8 @@
|
||||
""" python3 -m docgen <command> [args] — see cli/__init__.py for the commands."""
|
||||
|
||||
import sys
|
||||
|
||||
from .cli import main
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -1,10 +1,10 @@
|
||||
"""
|
||||
Run a book: larder, the steps, the web output, the book measure.
|
||||
|
||||
python3 -m docgen.book --root ../station -o out/book/station
|
||||
python3 -m docgen book --root ../station -o out/book/station
|
||||
|
||||
Composes functions that already exist. Nothing here parses, lays out or styles
|
||||
anything — `ops.overview`, `emitters.dot`, `emitters.site` and `notebook.spec`
|
||||
anything — `ops.overview`, `emitters.auto.draw`, `emitters.site` and `notebook.spec`
|
||||
do all of it, and this decides the order and writes the ledger. If this file
|
||||
ever starts doing the work, the seam has moved to the wrong place.
|
||||
|
||||
@@ -218,6 +218,41 @@ def _load_cell(step_id: str, artifact: str) -> str:
|
||||
return f'print(load("{artifact}") is not None)'
|
||||
|
||||
|
||||
# What a build writes into a book directory, and therefore what a rebuild may
|
||||
# remove first. Named, never globbed: a book directory also holds the hand-written
|
||||
# `checks.py` and `overlay.json`, and a misconfigured output path could point at
|
||||
# somebody's source tree — so nothing outside this list is ever deleted.
|
||||
GENERATED = ("book.json", "notebook.ipynb", "steps", "site", "explore")
|
||||
|
||||
|
||||
def clear(out) -> list[str]:
|
||||
"""Remove a previous build's outputs from `out`. Returns what was removed.
|
||||
|
||||
Without this, re-running a book leaves the last run's artifacts beside the new
|
||||
ledger: a graph that is now `graph.md` keeps its old `graph.svg`, and the site
|
||||
goes on showing it. The ledger would not list the stale file, so nothing would
|
||||
say it was stale — which is the failure the book measure exists to prevent.
|
||||
|
||||
Only acts on a directory that already holds a `book.json`, i.e. one this code
|
||||
wrote. Anything else is left exactly as found.
|
||||
"""
|
||||
import shutil
|
||||
|
||||
out = Path(out)
|
||||
if not (out / "book.json").is_file():
|
||||
return []
|
||||
removed = []
|
||||
for name in GENERATED:
|
||||
target = out / name
|
||||
if target.is_dir():
|
||||
shutil.rmtree(target)
|
||||
removed.append(name)
|
||||
elif target.is_file():
|
||||
target.unlink()
|
||||
removed.append(name)
|
||||
return removed
|
||||
|
||||
|
||||
def run(kind: str, source, out, *, slug: str | None = None, style: str = "lucid",
|
||||
theme: str | None = None, exclude=(), overlay=None, quiet: bool = False) -> Book:
|
||||
"""The whole book, in one process. Returns it; `book.json` is written."""
|
||||
@@ -227,6 +262,7 @@ def run(kind: str, source, out, *, slug: str | None = None, style: str = "lucid"
|
||||
|
||||
out = Path(out)
|
||||
slug = slug or Path(str(source)).name or "book"
|
||||
clear(out)
|
||||
steps_dir = out / "steps"
|
||||
steps_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
@@ -262,32 +298,26 @@ def run(kind: str, source, out, *, slug: str | None = None, style: str = "lucid"
|
||||
|
||||
style_obj = Style.load(style, theme=theme)
|
||||
|
||||
# The drawing, chosen by structure rather than by the caller. `classify`
|
||||
# already decided; this runs what it named.
|
||||
# The drawing, chosen by structure rather than by the caller — the same
|
||||
# `draw()` the `emit auto` and `emit site` commands use, so the three can
|
||||
# never disagree about what a graph wants.
|
||||
from ..emitters.auto import draw
|
||||
|
||||
drawn = draw(view, style_obj)
|
||||
graph_rel = None
|
||||
if verdict["emitter"] == "erd":
|
||||
from ..emitters.erd import emit as erd_emit
|
||||
p = steps_dir / "graph.svg"
|
||||
p.write_text(erd_emit(view, style_obj))
|
||||
graph_rel, label = "steps/graph.svg", "drawn as an ERD"
|
||||
elif verdict["emitter"] == "index":
|
||||
from ..emitters.index import to_markdown
|
||||
p = steps_dir / "graph.md"
|
||||
p.write_text(to_markdown(view))
|
||||
graph_rel, label = None, "not a diagram — written as a list"
|
||||
labels = {"erd": "drawn as an ERD", "dot": f"drawn as a {verdict['kind']}",
|
||||
"index": "not a diagram — written as a list"}
|
||||
if drawn["content"] is None:
|
||||
book.step("graph", "not drawn", skipped=drawn["why"])
|
||||
else:
|
||||
from ..emitters.dot import emit as dot_emit, render
|
||||
p = steps_dir / "graph.svg"
|
||||
try:
|
||||
p.write_bytes(render(dot_emit(view, style_obj,
|
||||
rankdir=(verdict.get("options") or {}).get("rankdir"))))
|
||||
graph_rel, label = "steps/graph.svg", f"drawn as a {verdict['kind']}"
|
||||
except Exception as e: # noqa: BLE001 - graphviz may not be installed
|
||||
p = None
|
||||
label = f"not drawn — {type(e).__name__}"
|
||||
book.step("graph", label, skipped=str(e)[:200])
|
||||
if p is not None:
|
||||
book.step("graph", label, p, note=verdict["why"])
|
||||
p = steps_dir / f"graph{drawn['suffix']}"
|
||||
if isinstance(drawn["content"], bytes):
|
||||
p.write_bytes(drawn["content"])
|
||||
else:
|
||||
p.write_text(drawn["content"])
|
||||
if drawn["suffix"] == ".svg":
|
||||
graph_rel = f"steps/{p.name}"
|
||||
book.step("graph", labels[drawn["emitter"]], p, note=drawn["why"])
|
||||
|
||||
from ..emitters.index import to_markdown, to_sidebar
|
||||
p = steps_dir / "index.md"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
Does *this* book still hold — the third test level.
|
||||
|
||||
python3 -m docgen.book.checks out/book/station
|
||||
python3 -m docgen check out/book/station
|
||||
|
||||
docgen has three levels of test, and they differ by what they assert *about*.
|
||||
The distinction is rig's, from `rig/ctrl/selftest.sh`, and it is worth keeping
|
||||
@@ -68,7 +68,7 @@ class Loaded:
|
||||
if not path.exists():
|
||||
raise FileNotFoundError(
|
||||
f"{path} does not exist — is {self.dir} a book directory?\n"
|
||||
"Build one with: python3 -m docgen.book --root <src> -o <dir>"
|
||||
"Build one with: python3 -m docgen book --root <src> -o <dir>"
|
||||
)
|
||||
self.data = json.loads(path.read_text())
|
||||
|
||||
@@ -272,34 +272,3 @@ def _run_cells(cells: list, cwd: Path) -> tuple[int, str | None]:
|
||||
finally:
|
||||
os.chdir(previous)
|
||||
return ran, failure
|
||||
|
||||
|
||||
def main(argv=None) -> int:
|
||||
import argparse
|
||||
|
||||
p = argparse.ArgumentParser(
|
||||
prog="python3 -m docgen.book.checks",
|
||||
description="Check one book: the spine's assertions, then its own.",
|
||||
)
|
||||
p.add_argument("book", type=Path, help="A book directory (holding book.json).")
|
||||
p.add_argument("--only", choices=("generated", "custom"),
|
||||
help="Run one level rather than both.")
|
||||
args = p.parse_args(argv)
|
||||
|
||||
try:
|
||||
book = Loaded(args.book)
|
||||
except (FileNotFoundError, json.JSONDecodeError) as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
print(f"{book.dir} — {book.data.get('slug', '?')}")
|
||||
r = Report()
|
||||
if args.only != "custom":
|
||||
generated(book, r)
|
||||
if args.only != "generated":
|
||||
custom(book, r)
|
||||
return r.total()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
||||
327
soleprint/atlas2/docgen/book/config.py
Normal file
327
soleprint/atlas2/docgen/book/config.py
Normal file
@@ -0,0 +1,327 @@
|
||||
"""
|
||||
A run file: every book a project builds, so a rebuild is one command.
|
||||
|
||||
python3 -m docgen run docgen.toml
|
||||
python3 -m docgen run docgen.toml --only station --only shop
|
||||
python3 -m docgen run docgen.toml --list # what would run, resolved
|
||||
|
||||
Books are rebuilt many times — after a merge, before a release, whenever the
|
||||
source moves — and each one is a source, an output directory and a handful of
|
||||
options. Typed out every time, those drift: one run excludes `migrations`, the
|
||||
next forgets. Written down once, the rebuild is exact.
|
||||
|
||||
## The shape
|
||||
|
||||
# docgen.toml
|
||||
reference = "../soleprint" # optional; $DOCGEN_REFERENCE wins if set
|
||||
|
||||
[defaults]
|
||||
out = "out/book" # each book goes to <out>/<name>
|
||||
style = "lucid"
|
||||
theme = "dark"
|
||||
exclude = ["migrations", "tests"]
|
||||
|
||||
[[book]]
|
||||
name = "station"
|
||||
root = "../soleprint/station" # a tree; reader = "python" by default
|
||||
|
||||
[[book]]
|
||||
name = "orders-api"
|
||||
openapi = "specs/orders.yaml"
|
||||
overlay = "overlays/orders.json"
|
||||
out = "/srv/docs/orders" # overrides <defaults.out>/<name>
|
||||
|
||||
Each book names **exactly one** source — `root`, `schema`, `openapi` or `har` —
|
||||
the same choice the `book` command makes you take.
|
||||
|
||||
## Three rules, each one a thing that went wrong somewhere else
|
||||
|
||||
**Paths are relative to the run file, not to wherever you ran the command.** A
|
||||
run file is kept beside the project it describes; if its paths meant different
|
||||
things from different directories, the same file would build different books.
|
||||
|
||||
**A book's value replaces the default, for every key.** Including `exclude`,
|
||||
which is the one where merging looks tempting. One rule nobody has to remember
|
||||
beats a clever one somebody has to look up.
|
||||
|
||||
**Unknown keys are refused, not ignored.** `exlude = [...]` silently doing
|
||||
nothing is how a rebuild quietly starts reading `node_modules`. The style loader
|
||||
takes the same line (requirements R30).
|
||||
|
||||
## Why TOML
|
||||
|
||||
It is read by the stdlib (`tomllib`), it allows comments — and a run file is
|
||||
hand-written, so the reason a book excludes something belongs next to the
|
||||
exclusion — and it is already the format of the `pyproject.toml` beside it. The
|
||||
IR and style files stay JSON, because those are data that tools write; this is
|
||||
configuration that people write.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
import tomllib
|
||||
except ModuleNotFoundError: # pragma: no cover - Python < 3.11
|
||||
tomllib = None
|
||||
|
||||
SOURCES = {"root": "python", "schema": "db", "openapi": "openapi", "har": "usage"}
|
||||
READERS = ("python", "code")
|
||||
|
||||
TOP_KEYS = {"reference", "defaults", "book"}
|
||||
DEFAULT_KEYS = {"out", "style", "theme", "exclude", "reader"}
|
||||
BOOK_KEYS = {"name", "out", "style", "theme", "exclude", "reader", "overlay", *SOURCES}
|
||||
|
||||
# A book name becomes a directory name and a slug, so it is held to what is safe
|
||||
# as both — no separators, nothing that means something to a shell.
|
||||
NAME = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]*$")
|
||||
|
||||
|
||||
class ConfigError(ValueError):
|
||||
"""A run file that cannot be run. Carries every problem, not the first."""
|
||||
|
||||
def __init__(self, path, problems: list[str]):
|
||||
self.path, self.problems = path, problems
|
||||
super().__init__(f"{path}: {len(problems)} problem(s)\n " + "\n ".join(problems))
|
||||
|
||||
|
||||
@dataclass
|
||||
class Entry:
|
||||
"""One book, fully resolved — nothing relative, nothing defaulted later."""
|
||||
|
||||
name: str
|
||||
kind: str # python | code | db | openapi | usage
|
||||
source: Path
|
||||
out: Path
|
||||
style: str = "lucid"
|
||||
theme: str | None = None
|
||||
overlay: Path | None = None
|
||||
exclude: tuple = ()
|
||||
|
||||
def line(self) -> str:
|
||||
return f"{self.name:<18} {self.kind:<8} {self.source} -> {self.out}"
|
||||
|
||||
|
||||
@dataclass
|
||||
class RunFile:
|
||||
path: Path
|
||||
books: list[Entry] = field(default_factory=list)
|
||||
reference: Path | None = None
|
||||
|
||||
def select(self, names) -> list[Entry]:
|
||||
"""The named books, in run-file order. An unknown name is an error."""
|
||||
if not names:
|
||||
return list(self.books)
|
||||
known = {b.name for b in self.books}
|
||||
unknown = [n for n in names if n not in known]
|
||||
if unknown:
|
||||
raise ConfigError(self.path, [
|
||||
f"no book named {n!r} — have: {', '.join(sorted(known))}" for n in unknown
|
||||
])
|
||||
wanted = set(names)
|
||||
return [b for b in self.books if b.name in wanted]
|
||||
|
||||
|
||||
def _path(value, base: Path) -> Path:
|
||||
# Normalised lexically, so `--list` shows `atlas2/out` rather than
|
||||
# `atlas2/docgen/../out`. Not resolved: a symlinked project should be named
|
||||
# the way its owner names it.
|
||||
p = Path(str(value)).expanduser()
|
||||
return Path(os.path.normpath(p if p.is_absolute() else base / p))
|
||||
|
||||
|
||||
def _within(inner: Path, outer: Path) -> bool:
|
||||
inner, outer = inner.resolve(), outer.resolve()
|
||||
return inner == outer or outer in inner.parents
|
||||
|
||||
|
||||
def load(path) -> RunFile:
|
||||
"""Read and resolve a run file. Raises ConfigError listing every problem."""
|
||||
path = Path(path)
|
||||
if tomllib is None:
|
||||
raise ConfigError(path, ["run files need Python 3.11+ (tomllib)"])
|
||||
try:
|
||||
data = tomllib.loads(path.read_text())
|
||||
except OSError as e:
|
||||
raise ConfigError(path, [f"cannot read: {e}"]) from None
|
||||
except tomllib.TOMLDecodeError as e:
|
||||
raise ConfigError(path, [f"not valid TOML: {e}"]) from None
|
||||
|
||||
base = path.resolve().parent
|
||||
problems: list[str] = []
|
||||
|
||||
for key in sorted(set(data) - TOP_KEYS):
|
||||
problems.append(f"unknown top-level key {key!r} — have: {', '.join(sorted(TOP_KEYS))}")
|
||||
|
||||
defaults = data.get("defaults") or {}
|
||||
if not isinstance(defaults, dict):
|
||||
problems.append("[defaults] must be a table")
|
||||
defaults = {}
|
||||
for key in sorted(set(defaults) - DEFAULT_KEYS):
|
||||
problems.append(f"[defaults] has unknown key {key!r} — have: "
|
||||
f"{', '.join(sorted(DEFAULT_KEYS))}")
|
||||
|
||||
reference = None
|
||||
if "reference" in data:
|
||||
reference = _path(data["reference"], base)
|
||||
if not reference.is_dir():
|
||||
problems.append(f"reference {reference} is not a directory")
|
||||
|
||||
raw_books = data.get("book") or []
|
||||
if not isinstance(raw_books, list) or not raw_books:
|
||||
problems.append("no books — add at least one [[book]] table")
|
||||
raw_books = []
|
||||
|
||||
books: list[Entry] = []
|
||||
for i, raw in enumerate(raw_books):
|
||||
where = f"book[{i}]"
|
||||
if not isinstance(raw, dict):
|
||||
problems.append(f"{where} must be a table")
|
||||
continue
|
||||
name = raw.get("name")
|
||||
if isinstance(name, str):
|
||||
where = f"book {name!r}"
|
||||
if not isinstance(name, str) or not NAME.match(name):
|
||||
problems.append(f"{where} needs a name of letters, digits, '.', '_' or '-'")
|
||||
continue
|
||||
|
||||
for key in sorted(set(raw) - BOOK_KEYS):
|
||||
problems.append(f"{where} has unknown key {key!r} — have: "
|
||||
f"{', '.join(sorted(BOOK_KEYS))}")
|
||||
|
||||
named = [k for k in SOURCES if k in raw]
|
||||
if len(named) != 1:
|
||||
problems.append(
|
||||
f"{where} must name exactly one source ({', '.join(SOURCES)}); "
|
||||
f"it names {', '.join(named) if named else 'none'}"
|
||||
)
|
||||
continue
|
||||
source_key = named[0]
|
||||
source = _path(raw[source_key], base)
|
||||
|
||||
def pick(key, default=None):
|
||||
# A book's value replaces the default, for every key.
|
||||
return raw[key] if key in raw else defaults.get(key, default)
|
||||
|
||||
reader = pick("reader", "python")
|
||||
if source_key == "root":
|
||||
if reader not in READERS:
|
||||
problems.append(f"{where}: reader must be one of {READERS}, got {reader!r}")
|
||||
continue
|
||||
kind = reader
|
||||
if not source.is_dir():
|
||||
problems.append(f"{where}: root {source} is not a directory")
|
||||
else:
|
||||
if "reader" in raw:
|
||||
problems.append(f"{where}: reader only applies to root, not {source_key}")
|
||||
kind = SOURCES[source_key]
|
||||
if not source.is_file():
|
||||
problems.append(f"{where}: {source_key} {source} is not a file")
|
||||
|
||||
if "out" in raw:
|
||||
out = _path(raw["out"], base)
|
||||
else:
|
||||
out = _path(defaults.get("out", "out"), base) / name
|
||||
|
||||
overlay = _path(raw["overlay"], base) if "overlay" in raw else None
|
||||
if overlay is not None and not overlay.is_file():
|
||||
problems.append(f"{where}: overlay {overlay} is not a file")
|
||||
|
||||
exclude = pick("exclude", [])
|
||||
if not isinstance(exclude, list) or not all(isinstance(x, str) for x in exclude):
|
||||
problems.append(f"{where}: exclude must be a list of directory names")
|
||||
exclude = []
|
||||
elif source_key != "root":
|
||||
# Only an exclude the book sets itself is a mistake. One inherited
|
||||
# from [defaults] is meant for the trees and simply does not apply —
|
||||
# refusing it would make a shared default impossible to write.
|
||||
if "exclude" in raw:
|
||||
problems.append(f"{where}: exclude only applies to a root, not {source_key}")
|
||||
exclude = []
|
||||
|
||||
# Writing a book inside the tree it reads means the next run reads the
|
||||
# last run's output. That is a rebuild that changes on every rebuild.
|
||||
if source_key == "root" and source.is_dir() and _within(out, source):
|
||||
problems.append(f"{where}: out {out} is inside the tree it reads ({source})")
|
||||
|
||||
books.append(Entry(
|
||||
name=name, kind=kind, source=source, out=out,
|
||||
style=pick("style", "lucid"), theme=pick("theme"),
|
||||
overlay=overlay, exclude=tuple(exclude),
|
||||
))
|
||||
|
||||
seen_names, seen_outs = {}, {}
|
||||
for b in books:
|
||||
if b.name in seen_names:
|
||||
problems.append(f"book {b.name!r} is listed twice")
|
||||
seen_names[b.name] = b
|
||||
key = b.out.resolve()
|
||||
if key in seen_outs:
|
||||
# Two books into one directory: the second clears the first on every
|
||||
# run, and nothing says so.
|
||||
problems.append(f"books {seen_outs[key]!r} and {b.name!r} both write to {b.out}")
|
||||
seen_outs[key] = b.name
|
||||
|
||||
if problems:
|
||||
raise ConfigError(path, problems)
|
||||
return RunFile(path=path, books=books, reference=reference)
|
||||
|
||||
|
||||
def apply_reference(runfile: RunFile) -> str | None:
|
||||
"""Point the one seam at the run file's reference — unless the caller's
|
||||
environment already does. The caller's env beats the file, which is the
|
||||
precedence rig uses for every setting it has.
|
||||
"""
|
||||
from .. import reference as ref
|
||||
|
||||
if runfile.reference is None or os.environ.get(ref.ENV_VAR):
|
||||
return None
|
||||
os.environ[ref.ENV_VAR] = str(runfile.reference)
|
||||
return str(runfile.reference)
|
||||
|
||||
|
||||
def run(runfile: RunFile, names=None, *, check: bool = False, quiet: bool = True):
|
||||
"""Build every selected book, in order. One failure never stops the rest.
|
||||
|
||||
Returns one result per book:
|
||||
{"name", "out", "ok", "error", "lost": [claims], "checks_failed": [names]}
|
||||
"""
|
||||
from . import checks as checks_mod
|
||||
from .build import run as build
|
||||
|
||||
apply_reference(runfile)
|
||||
results = []
|
||||
for entry in runfile.select(names):
|
||||
result = {"name": entry.name, "out": str(entry.out), "ok": False,
|
||||
"error": None, "lost": [], "checks_failed": []}
|
||||
try:
|
||||
overlay = None
|
||||
if entry.overlay is not None:
|
||||
from ..notebook import spec as spec_mod
|
||||
overlay = spec_mod.load(entry.overlay)
|
||||
book = build(entry.kind, entry.source, entry.out, slug=entry.name,
|
||||
style=entry.style, theme=entry.theme, exclude=entry.exclude,
|
||||
overlay=overlay, quiet=quiet)
|
||||
result["lost"] = [r["claim"] for r in book.compare() if not r["ok"]]
|
||||
except Exception as e: # noqa: BLE001 - one bad book must not cost the run
|
||||
result["error"] = f"{type(e).__name__}: {e}"
|
||||
results.append(result)
|
||||
continue
|
||||
|
||||
if check:
|
||||
import contextlib
|
||||
import io
|
||||
|
||||
report = checks_mod.Report()
|
||||
loaded = checks_mod.Loaded(entry.out)
|
||||
sink = io.StringIO() if quiet else None
|
||||
with contextlib.redirect_stdout(sink) if sink else contextlib.nullcontext():
|
||||
checks_mod.generated(loaded, report)
|
||||
checks_mod.custom(loaded, report)
|
||||
result["checks_failed"] = list(report.failed)
|
||||
|
||||
result["ok"] = not result["lost"] and not result["checks_failed"]
|
||||
results.append(result)
|
||||
return results
|
||||
75
soleprint/atlas2/docgen/cli/__init__.py
Normal file
75
soleprint/atlas2/docgen/cli/__init__.py
Normal file
@@ -0,0 +1,75 @@
|
||||
"""
|
||||
The command line — every command docgen has, and nothing else.
|
||||
|
||||
python3 -m docgen <command> [args]
|
||||
|
||||
book one operation, measured at both ends
|
||||
run every book a run file lists
|
||||
check docgen's own suite, or one book's own level
|
||||
extract source -> ir.json
|
||||
validate check an ir.json at the boundary
|
||||
view ir.json -> a narrower ir.json
|
||||
emit ir.json -> an artifact
|
||||
|
||||
## Why all of it lives here
|
||||
|
||||
The packages beside this one — `extractors/`, `ops/`, `emitters/`, `book/` — are
|
||||
library code, and they hold no command-line code at all: no argparse, no
|
||||
`__main__.py`, no `cli_dot.py` sitting next to `dot.py`. Two kinds of file in one
|
||||
folder makes every folder answer two questions, and the command-line half is the
|
||||
part that grows copies — each old `cli_*` re-implemented "read the IR, validate
|
||||
it, load the style" by hand.
|
||||
|
||||
So the split is by kind rather than by feature: library in the packages, the
|
||||
command line here, and `selftest.py` asserts that nothing outside this package
|
||||
imports `argparse`, so it stays that way without anyone remembering to.
|
||||
|
||||
Plain argparse and no scaffold, on purpose. docgen is copied out of the repo as a
|
||||
folder, and a shared CLI helper that lives in some other tool would tie the copy
|
||||
back to the repo.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
# command -> (module in this package, one-line description)
|
||||
COMMANDS = {
|
||||
"book": ("book", "one operation, measured at both ends"),
|
||||
"run": ("run", "every book a run file lists"),
|
||||
"check": ("check", "docgen's own suite, or one book's own level"),
|
||||
"extract": ("extract", "source -> ir.json"),
|
||||
"validate": ("validate", "check an ir.json at the boundary"),
|
||||
"view": ("view", "ir.json -> a narrower ir.json"),
|
||||
"emit": ("emit", "ir.json -> an artifact"),
|
||||
}
|
||||
|
||||
|
||||
def usage() -> str:
|
||||
from .common import PROG
|
||||
|
||||
lines = [f"usage: {PROG} <command> [args]", ""]
|
||||
lines += [f" {name:<9} {desc}" for name, (_, desc) in COMMANDS.items()]
|
||||
lines += ["", f" {PROG} <command> --help for a command's options"]
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def main(argv=None) -> int:
|
||||
from importlib import import_module
|
||||
|
||||
from .common import Abort
|
||||
|
||||
argv = sys.argv[1:] if argv is None else list(argv)
|
||||
if not argv or argv[0] in ("-h", "--help", "help"):
|
||||
print(usage())
|
||||
return 0 if argv else 2
|
||||
name, rest = argv[0], argv[1:]
|
||||
if name not in COMMANDS:
|
||||
print(f"Error: no command {name!r}\n\n{usage()}", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
module = import_module(f".{COMMANDS[name][0]}", package=__name__)
|
||||
try:
|
||||
return module.main(rest)
|
||||
except Abort as e:
|
||||
# The only exit path for an expected failure: one line, stderr, exit 1.
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
return 1
|
||||
@@ -1,43 +1,47 @@
|
||||
""" python3 -m docgen.book --root ../station -o out/book/station
|
||||
"""
|
||||
python3 -m docgen book --root SRC -o out/book/name [--reader python|code]
|
||||
python3 -m docgen book --schema schema.json -o DIR
|
||||
python3 -m docgen book --openapi spec.yaml -o DIR
|
||||
python3 -m docgen book --har session.har -o DIR
|
||||
|
||||
One book: larder measure, the steps, the web output, book measure. The step
|
||||
artifacts land in `steps/` and are ordinary files — nothing here needs this
|
||||
command to have been the thing that produced them.
|
||||
|
||||
Exits 1 when the two ends do not reconcile. The book is still written — the
|
||||
evidence is the point — but a build that lost input should fail a pipeline
|
||||
rather than pass quietly.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
KINDS = ("python", "code", "db", "openapi", "usage")
|
||||
from .common import PROG, Abort, style_args
|
||||
|
||||
|
||||
def main(argv=None) -> int:
|
||||
p = argparse.ArgumentParser(
|
||||
prog="python3 -m docgen.book",
|
||||
description="Run one docgen operation, measured at both ends.",
|
||||
)
|
||||
def main(argv) -> int:
|
||||
p = argparse.ArgumentParser(prog=f"{PROG} book",
|
||||
description="Run one docgen operation, measured at both ends.")
|
||||
src = p.add_mutually_exclusive_group(required=True)
|
||||
src.add_argument("--root", type=Path, help="A source tree (Python, or --lang code).")
|
||||
src.add_argument("--root", type=Path, help="A source tree.")
|
||||
src.add_argument("--schema", type=Path, help="A graphgen-compatible schema.json.")
|
||||
src.add_argument("--openapi", type=Path, help="An OpenAPI document.")
|
||||
src.add_argument("--har", type=Path, help="A HAR recording.")
|
||||
p.add_argument("--lang", choices=("python", "code"), default="python",
|
||||
p.add_argument("--reader", choices=("python", "code"), default="python",
|
||||
help="With --root: the stdlib ast reader, or tree-sitter. Default python.")
|
||||
p.add_argument("--output", "-o", type=Path, required=True,
|
||||
help="The book directory. Created if absent.")
|
||||
help="The book directory. Created if absent; a previous build is replaced.")
|
||||
p.add_argument("--slug", help="What to call it. Defaults to the source's name.")
|
||||
p.add_argument("--style", default="lucid")
|
||||
p.add_argument("--theme", default=None, help="dark (default) or lucid.")
|
||||
style_args(p)
|
||||
p.add_argument("--overlay", type=Path,
|
||||
help="A hand-written overlay, re-applied on every build.")
|
||||
help="A hand-written notebook overlay, re-applied on every build.")
|
||||
p.add_argument("--exclude", action="append", default=[],
|
||||
help="Directory name to skip. Repeatable.")
|
||||
p.add_argument("--quiet", "-q", action="store_true")
|
||||
args = p.parse_args(argv)
|
||||
|
||||
if args.root is not None:
|
||||
kind, source = args.lang, args.root
|
||||
kind, source = args.reader, args.root
|
||||
elif args.schema is not None:
|
||||
kind, source = "db", args.schema
|
||||
elif args.openapi is not None:
|
||||
@@ -46,35 +50,24 @@ def main(argv=None) -> int:
|
||||
kind, source = "usage", args.har
|
||||
|
||||
if not Path(source).exists():
|
||||
print(f"Error: {source} does not exist", file=sys.stderr)
|
||||
return 1
|
||||
raise Abort(f"{source} does not exist")
|
||||
|
||||
overlay = None
|
||||
if args.overlay:
|
||||
if not args.overlay.exists():
|
||||
# Absent is fine and is the documented default; named-but-missing is
|
||||
# a typo, and quietly building without it would hide the typo.
|
||||
print(f"Error: overlay {args.overlay} does not exist", file=sys.stderr)
|
||||
return 1
|
||||
raise Abort(f"overlay {args.overlay} does not exist")
|
||||
from ..notebook import spec as spec_mod
|
||||
overlay = spec_mod.load(args.overlay)
|
||||
|
||||
from .build import run
|
||||
from ..book.build import run
|
||||
|
||||
try:
|
||||
book = run(kind, source, args.output, slug=args.slug, style=args.style,
|
||||
theme=args.theme, exclude=tuple(args.exclude), overlay=overlay,
|
||||
quiet=args.quiet)
|
||||
except Exception as e: # noqa: BLE001 - the CLI reports, it does not traceback
|
||||
print(f"Error: {type(e).__name__}: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# Exit 1 when the two ends do not reconcile. The book is still written —
|
||||
# the evidence is the point — but a build that lost input should fail a
|
||||
# pipeline rather than pass quietly.
|
||||
lost = [r for r in book.compare() if not r.get("ok")]
|
||||
return 1 if lost else 0
|
||||
|
||||
raise Abort(f"{type(e).__name__}: {e}") from None
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
return 1 if any(not r["ok"] for r in book.compare()) else 0
|
||||
50
soleprint/atlas2/docgen/cli/check.py
Normal file
50
soleprint/atlas2/docgen/cli/check.py
Normal file
@@ -0,0 +1,50 @@
|
||||
"""
|
||||
python3 -m docgen check docgen's own suite
|
||||
python3 -m docgen check <book-dir> that book's own level
|
||||
python3 -m docgen check <book-dir> --only generated|custom
|
||||
|
||||
Two of docgen's three test levels, told apart by what they assert *about*. The
|
||||
third, the machine, is `make doctor`, and never fails.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from .common import PROG, Abort
|
||||
|
||||
HERE = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
def main(argv) -> int:
|
||||
p = argparse.ArgumentParser(prog=f"{PROG} check")
|
||||
p.add_argument("book", type=Path, nargs="?",
|
||||
help="A book directory (holding book.json). Omit for docgen's own suite.")
|
||||
p.add_argument("--only", choices=("generated", "custom"),
|
||||
help="With a book: run one half rather than both.")
|
||||
args = p.parse_args(argv)
|
||||
|
||||
if args.book is None:
|
||||
if args.only:
|
||||
raise Abort("--only applies to a book")
|
||||
# A subprocess rather than an import: the suite is a script that runs at
|
||||
# import time and exits, and it has to see a clean interpreter to test
|
||||
# what a fresh one would do.
|
||||
return subprocess.call([sys.executable, str(HERE / "selftest.py")])
|
||||
|
||||
from ..book.checks import Loaded, Report, custom, generated
|
||||
|
||||
try:
|
||||
book = Loaded(args.book)
|
||||
except (FileNotFoundError, json.JSONDecodeError) as e:
|
||||
raise Abort(str(e)) from None
|
||||
|
||||
print(f"{book.dir} — {book.data.get('slug', '?')}")
|
||||
r = Report()
|
||||
if args.only != "custom":
|
||||
generated(book, r)
|
||||
if args.only != "generated":
|
||||
custom(book, r)
|
||||
return r.total()
|
||||
79
soleprint/atlas2/docgen/cli/common.py
Normal file
79
soleprint/atlas2/docgen/cli/common.py
Normal file
@@ -0,0 +1,79 @@
|
||||
"""
|
||||
What every command does the same way — written once.
|
||||
|
||||
Each old `cli_*` file re-implemented these by hand: read a JSON file and say so
|
||||
if it cannot, validate it and print the first five problems, load a style and
|
||||
report a bad name, write to a file or to stdout. Eight copies had already begun
|
||||
to differ in their wording. Now a command raises `Abort` and `cli.main` turns it
|
||||
into the one exit path: `Error: <message>` on stderr, exit 1.
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# The package name is derived, not written: the folder can be copied anywhere
|
||||
# and renamed, and help text saying `docgen` for a folder called `docs2` lies.
|
||||
ROOT = __package__.rsplit(".", 1)[0]
|
||||
PROG = f"python3 -m {ROOT}"
|
||||
|
||||
|
||||
class Abort(Exception):
|
||||
"""An expected failure. Printed as one line, exit 1 — never a traceback."""
|
||||
|
||||
|
||||
def read_json(path: Path) -> dict:
|
||||
try:
|
||||
return json.loads(Path(path).read_text())
|
||||
except (OSError, json.JSONDecodeError) as e:
|
||||
raise Abort(f"could not read {path}: {e}") from None
|
||||
|
||||
|
||||
def read_ir(path: Path) -> dict:
|
||||
"""Read an IR and validate it at the boundary, or abort saying why."""
|
||||
from ..ir import check
|
||||
|
||||
data = read_json(path)
|
||||
problems = check(data)
|
||||
if problems:
|
||||
shown = "\n ".join(problems[:5])
|
||||
more = f"\n … and {len(problems) - 5} more" if len(problems) > 5 else ""
|
||||
raise Abort(f"{path} is not a valid IR ({len(problems)} problem(s)):\n {shown}{more}")
|
||||
return data
|
||||
|
||||
|
||||
def load_style(name: str, theme: str | None):
|
||||
from ..style import Style, StyleError
|
||||
|
||||
try:
|
||||
return Style.load(name, theme=theme)
|
||||
except StyleError as e:
|
||||
raise Abort(str(e)) from None
|
||||
|
||||
|
||||
def style_args(p) -> None:
|
||||
p.add_argument("--style", default="lucid", help="A shipped style, or a path to one.")
|
||||
p.add_argument("--theme", default=None, help="dark (default) or lucid.")
|
||||
|
||||
|
||||
def emit(text, output: Path | None, report: str = "") -> None:
|
||||
"""Write to `output`, or to stdout when there is none."""
|
||||
if output is None:
|
||||
if isinstance(text, bytes):
|
||||
sys.stdout.buffer.write(text)
|
||||
else:
|
||||
sys.stdout.write(text)
|
||||
return
|
||||
output = Path(output)
|
||||
output.parent.mkdir(parents=True, exist_ok=True)
|
||||
if isinstance(text, bytes):
|
||||
output.write_bytes(text)
|
||||
else:
|
||||
output.write_text(text)
|
||||
if report:
|
||||
print(report)
|
||||
|
||||
|
||||
def dump_ir(ir, output: Path | None, report: str = "") -> None:
|
||||
data = ir.to_dict() if hasattr(ir, "to_dict") else ir
|
||||
emit(json.dumps(data, indent=2) + "\n", output, report)
|
||||
252
soleprint/atlas2/docgen/cli/emit.py
Normal file
252
soleprint/atlas2/docgen/cli/emit.py
Normal file
@@ -0,0 +1,252 @@
|
||||
"""
|
||||
python3 -m docgen emit auto <ir.json> -o DIR whatever the structure asks for
|
||||
python3 -m docgen emit dot <ir.json> [-o out.svg|.dot]
|
||||
python3 -m docgen emit erd <ir.json> [-o out.svg]
|
||||
python3 -m docgen emit index <ir.json> [-o out.md|.json]
|
||||
python3 -m docgen emit minimap <ir.json> [-o out.svg] [--scale 0.55]
|
||||
python3 -m docgen emit notebook <ir.json> [-o out.ipynb] [--overlay f.json]
|
||||
python3 -m docgen emit site <ir.json> -o DIR
|
||||
python3 -m docgen emit explore <ir.json> -o DIR
|
||||
|
||||
IR -> an artifact. Every emitter validates its input first, so a broken document
|
||||
is reported here rather than drawn wrong. `--style` and `--theme` apply to every
|
||||
emitter that draws.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from .common import PROG, Abort, emit as write, load_style, read_ir, style_args
|
||||
|
||||
|
||||
def _parser(name: str, *, styled: bool = True, output_help: str = "") -> argparse.ArgumentParser:
|
||||
p = argparse.ArgumentParser(prog=f"{PROG} emit {name}")
|
||||
p.add_argument("ir", type=Path)
|
||||
p.add_argument("--output", "-o", type=Path, help=output_help or None)
|
||||
if styled:
|
||||
style_args(p)
|
||||
return p
|
||||
|
||||
|
||||
def _size(svg: str) -> str:
|
||||
m = re.search(r'width="(\d+)pt" height="(\d+)pt"', svg)
|
||||
return f"{m.group(1)}x{m.group(2)}" if m else ""
|
||||
|
||||
|
||||
def auto(argv) -> int:
|
||||
p = _parser("auto", output_help="Directory to write into.")
|
||||
p.add_argument("--force", help="Use this emitter regardless of what fits.")
|
||||
args = p.parse_args(argv)
|
||||
from ..emitters.auto import draw
|
||||
|
||||
data, style = read_ir(args.ir), load_style(args.style, args.theme)
|
||||
drawn = draw(data, style, force=args.force)
|
||||
print(f" {drawn['verdict']['kind']:<8} -> {drawn['emitter']}")
|
||||
print(f" {drawn['why']}")
|
||||
if drawn["content"] is None:
|
||||
raise Abort(drawn["why"])
|
||||
out_dir = args.output or Path(".")
|
||||
path = out_dir / f"{args.ir.stem}{drawn['suffix']}"
|
||||
write(drawn["content"], path, f" {path}")
|
||||
return 0
|
||||
|
||||
|
||||
def dot(argv) -> int:
|
||||
p = _parser("dot", output_help="Write here. .dot or .svg by suffix.")
|
||||
p.add_argument("--max-depth", type=int, default=None)
|
||||
p.add_argument("--quiet", "-q", action="store_true", help="Do not warn about shape.")
|
||||
args = p.parse_args(argv)
|
||||
from ..emitters.dot import RenderError, emit, render
|
||||
from ..ops import shape
|
||||
|
||||
data, style = read_ir(args.ir), load_style(args.style, args.theme)
|
||||
|
||||
# Aspect ratio is a property of the graph, not of the renderer: a layered
|
||||
# engine puts one dependency level in one row, so the widest level is the
|
||||
# width. Say so before writing the file, because the alternative is finding
|
||||
# out from a 13671pt image — and the fix is never a layout flag, it is a
|
||||
# smaller question.
|
||||
if not args.quiet:
|
||||
sh = shape(data)
|
||||
if sh["widest_level"] > 20 or sh["nodes"] > 60:
|
||||
est = sh["widest_level"] / max(sh["levels"], 1)
|
||||
print(f" note: {sh['nodes']} nodes, {sh['levels']} levels, widest level "
|
||||
f"{sh['widest_level']} — this will render roughly {est:.0f}:1.\n"
|
||||
" Around 20 nodes is where it stops being a diagram. Try "
|
||||
"`view --split`,\n `--around <id> --hops 2`, or `--subtree <id>`. "
|
||||
"Layout flags will not fix it.", file=sys.stderr)
|
||||
if sh["isolated"] > sh["nodes"] // 3:
|
||||
print(f" {sh['isolated']} of {sh['nodes']} nodes have no edges; they are "
|
||||
"laid out side by side.", file=sys.stderr)
|
||||
|
||||
dot_text = emit(data, style, max_depth=args.max_depth)
|
||||
if not args.output or args.output.suffix == ".dot":
|
||||
write(dot_text, args.output, f" {args.style}/{style.theme:6} {args.output}")
|
||||
return 0
|
||||
try:
|
||||
rendered = render(dot_text, fmt=args.output.suffix.lstrip(".") or "svg")
|
||||
except RenderError as e:
|
||||
raise Abort(str(e)) from None
|
||||
write(rendered, args.output, f" {args.style}/{style.theme:6} {args.output}")
|
||||
return 0
|
||||
|
||||
|
||||
def erd(argv) -> int:
|
||||
args = _parser("erd").parse_args(argv)
|
||||
from ..emitters.erd import emit
|
||||
|
||||
data, style = read_ir(args.ir), load_style(args.style, args.theme)
|
||||
try:
|
||||
svg = emit(data, style)
|
||||
except ValueError as e:
|
||||
raise Abort(str(e)) from None
|
||||
write(svg, args.output, f" erd/{style.theme:6} {args.output} {_size(svg)}")
|
||||
return 0
|
||||
|
||||
|
||||
def index(argv) -> int:
|
||||
p = _parser("index", styled=False,
|
||||
output_help=".md for the document, .json for a sidebar.")
|
||||
p.add_argument("--title", default="")
|
||||
args = p.parse_args(argv)
|
||||
from ..emitters.index import to_markdown, to_sidebar
|
||||
|
||||
data = read_ir(args.ir)
|
||||
if args.output and args.output.suffix == ".json":
|
||||
text = json.dumps(to_sidebar(data), indent=2) + "\n"
|
||||
else:
|
||||
text = to_markdown(data, title=args.title)
|
||||
write(text, args.output, f" index {args.output}")
|
||||
return 0
|
||||
|
||||
|
||||
def minimap(argv) -> int:
|
||||
p = _parser("minimap")
|
||||
p.add_argument("--scale", type=float, default=0.55, help="Pixels per source line.")
|
||||
p.add_argument("--width", type=int, default=1180, help="Wrap a shelf past this.")
|
||||
args = p.parse_args(argv)
|
||||
from ..emitters.minimap import emit
|
||||
|
||||
data, style = read_ir(args.ir), load_style(args.style, args.theme)
|
||||
try:
|
||||
svg = emit(data, style, scale=args.scale, target_width=args.width)
|
||||
except ValueError as e:
|
||||
raise Abort(str(e)) from None
|
||||
write(svg, args.output, f" minimap {args.output} {_size(svg)}")
|
||||
return 0
|
||||
|
||||
|
||||
def notebook(argv) -> int:
|
||||
p = _parser("notebook", styled=False)
|
||||
p.add_argument("--overlay", type=Path, help="Hand-written additions, re-applied.")
|
||||
p.add_argument("--spec-out", type=Path, help="Write the generated spec too.")
|
||||
p.add_argument("--scaffold", type=Path, help="Write a blank overlay and stop.")
|
||||
p.add_argument("--base-url", default="https://api.example.invalid")
|
||||
args = p.parse_args(argv)
|
||||
from ..emitters.notebook import emit
|
||||
from ..notebook import dump, from_ir, merge, scaffold
|
||||
|
||||
base = from_ir(read_ir(args.ir), base_url=args.base_url)
|
||||
|
||||
if args.scaffold:
|
||||
dump(scaffold(base), args.scaffold)
|
||||
print(f" overlay {args.scaffold} {len(base['steps'])} step(s), none filled in")
|
||||
return 0
|
||||
|
||||
overlay = None
|
||||
if args.overlay:
|
||||
if args.overlay.exists():
|
||||
overlay = json.loads(args.overlay.read_text())
|
||||
else:
|
||||
print(f" note: no overlay at {args.overlay} — generating the base only",
|
||||
file=sys.stderr)
|
||||
|
||||
spec, drift = merge(base, overlay)
|
||||
for d in drift:
|
||||
# The base moved under the overlay. Worth saying out loud; not a reason
|
||||
# to refuse to build the document.
|
||||
print(f" drift: {d}", file=sys.stderr)
|
||||
|
||||
if args.spec_out:
|
||||
dump(spec, args.spec_out)
|
||||
print(f" spec {args.spec_out}")
|
||||
|
||||
text = emit(spec)
|
||||
cells = len(json.loads(text)["cells"])
|
||||
extra = f", {len(drift)} drift" if drift else ""
|
||||
write(text, args.output,
|
||||
f" notebook {args.output} {len(spec['steps'])} steps, {cells} cells{extra}")
|
||||
return 0
|
||||
|
||||
|
||||
def site(argv) -> int:
|
||||
p = argparse.ArgumentParser(prog=f"{PROG} emit site")
|
||||
p.add_argument("ir", type=Path)
|
||||
p.add_argument("--output", "-o", type=Path, required=True, help="Directory.")
|
||||
style_args(p)
|
||||
p.add_argument("--title", default="")
|
||||
p.add_argument("--no-graph", action="store_true")
|
||||
args = p.parse_args(argv)
|
||||
from ..emitters.auto import draw
|
||||
from ..emitters.site import write as site_write
|
||||
|
||||
data, style = read_ir(args.ir), load_style(args.style, args.theme)
|
||||
args.output.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
graph_name = None
|
||||
if not args.no_graph:
|
||||
# Whatever the structure asks for, so the page carries the right picture
|
||||
# — the same `draw()` the book and `emit auto` use.
|
||||
drawn = draw(data, style)
|
||||
if drawn["content"] is not None and drawn["suffix"] == ".svg":
|
||||
graph_name = "graph.svg"
|
||||
write(drawn["content"], args.output / graph_name)
|
||||
else:
|
||||
print(f" note: {drawn['verdict']['kind']} — {drawn['why']}", file=sys.stderr)
|
||||
print(" no diagram on the page; the index is the artifact", file=sys.stderr)
|
||||
|
||||
for f in site_write(data, style, args.output, graph=graph_name, title=args.title):
|
||||
print(f" site {f}")
|
||||
if graph_name:
|
||||
print(f" site {args.output / graph_name}")
|
||||
return 0
|
||||
|
||||
|
||||
def explore(argv) -> int:
|
||||
p = argparse.ArgumentParser(prog=f"{PROG} emit explore")
|
||||
p.add_argument("ir", type=Path)
|
||||
p.add_argument("--output", "-o", type=Path, required=True, help="Directory.")
|
||||
style_args(p)
|
||||
p.add_argument("--scale", type=float, default=0.55)
|
||||
p.add_argument("--width", type=int, default=1100)
|
||||
p.add_argument("--hops", type=int, default=1)
|
||||
p.add_argument("--title", default="")
|
||||
args = p.parse_args(argv)
|
||||
from ..emitters.explore import write as explore_write
|
||||
|
||||
data, style = read_ir(args.ir), load_style(args.style, args.theme)
|
||||
try:
|
||||
path = explore_write(data, style, args.output, scale=args.scale, width=args.width,
|
||||
hops=args.hops, title=args.title)
|
||||
except ValueError as e:
|
||||
raise Abort(str(e)) from None
|
||||
graphs = args.output / "graphs"
|
||||
count = len(list(graphs.glob("*.svg"))) if graphs.exists() else 0
|
||||
print(f" explore {path} {count} neighbourhood diagram(s)")
|
||||
return 0
|
||||
|
||||
|
||||
EMITTERS = {"auto": auto, "dot": dot, "erd": erd, "index": index, "minimap": minimap,
|
||||
"notebook": notebook, "site": site, "explore": explore}
|
||||
|
||||
|
||||
def main(argv) -> int:
|
||||
if not argv or argv[0] in ("-h", "--help"):
|
||||
print(__doc__.strip("\n"))
|
||||
return 0 if argv else 2
|
||||
if argv[0] not in EMITTERS:
|
||||
raise Abort(f"no emitter {argv[0]!r} — have: {', '.join(EMITTERS)}")
|
||||
return EMITTERS[argv[0]](argv[1:])
|
||||
118
soleprint/atlas2/docgen/cli/extract.py
Normal file
118
soleprint/atlas2/docgen/cli/extract.py
Normal file
@@ -0,0 +1,118 @@
|
||||
"""
|
||||
python3 -m docgen extract python --root SRC [-o ir.json] [--exclude NAME ...]
|
||||
python3 -m docgen extract code --root SRC [-o ir.json] [--ext .cs ...]
|
||||
python3 -m docgen extract db --schema schema.json [-o ir.json]
|
||||
python3 -m docgen extract openapi --spec spec.yaml [-o ir.json]
|
||||
python3 -m docgen extract usage --har session.har [-o ir.json]
|
||||
|
||||
Source -> IR, one reader per source type. Writes to stdout without `-o`, so it
|
||||
composes with `view` and `emit`.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from collections import Counter
|
||||
from pathlib import Path
|
||||
|
||||
from .common import PROG, Abort, dump_ir
|
||||
|
||||
|
||||
def _parser(reader: str, source_flag: str, help_: str) -> argparse.ArgumentParser:
|
||||
p = argparse.ArgumentParser(prog=f"{PROG} extract {reader}")
|
||||
p.add_argument(source_flag, "-s", required=True, type=Path, help=help_)
|
||||
p.add_argument("--output", "-o", type=Path, help="Where to write. Default stdout.")
|
||||
return p
|
||||
|
||||
|
||||
def _counts(g) -> str:
|
||||
c = Counter(n.kind for n in g.nodes)
|
||||
return " · ".join(f"{v} {k}" for k, v in sorted(c.items(), key=lambda kv: -kv[1]))
|
||||
|
||||
|
||||
def python(argv) -> int:
|
||||
p = _parser("python", "--root", "Tree to read.")
|
||||
p.add_argument("--exclude", action="append", default=[], help="Directory name to skip.")
|
||||
args = p.parse_args(argv)
|
||||
from ..extractors.python import extract
|
||||
|
||||
try:
|
||||
g = extract(args.root, exclude=tuple(args.exclude))
|
||||
except (NotADirectoryError, OSError) as e:
|
||||
raise Abort(str(e)) from None
|
||||
unparsed = sum(1 for n in g.nodes if n.attrs.get("error"))
|
||||
dump_ir(g, args.output,
|
||||
f"{len(g.nodes)} nodes, {len(g.edges)} edges -> {args.output}"
|
||||
+ (f" ({unparsed} file(s) unparsed)" if unparsed else ""))
|
||||
return 0
|
||||
|
||||
|
||||
def code(argv) -> int:
|
||||
p = _parser("code", "--root", "Tree to read.")
|
||||
p.add_argument("--ext", action="append", default=[],
|
||||
help="Limit to these extensions. Default: every registered one.")
|
||||
p.add_argument("--exclude", action="append", default=[], help="Directory name to skip.")
|
||||
args = p.parse_args(argv)
|
||||
from ..extractors.code import MissingParser, extract
|
||||
|
||||
try:
|
||||
g = extract(args.root, suffixes=args.ext or None, exclude=tuple(args.exclude))
|
||||
except (MissingParser, NotADirectoryError, OSError) as e:
|
||||
raise Abort(str(e)) from None
|
||||
dump_ir(g, args.output, f"{len(g.nodes)} nodes -> {args.output} {_counts(g)}")
|
||||
return 0
|
||||
|
||||
|
||||
def db(argv) -> int:
|
||||
args = _parser("db", "--schema",
|
||||
"A graphgen-compatible schema.json, as modelgen emits.").parse_args(argv)
|
||||
from ..extractors.db import extract
|
||||
|
||||
try:
|
||||
g = extract(args.schema)
|
||||
except (OSError, json.JSONDecodeError, KeyError) as e:
|
||||
raise Abort(f"could not read {args.schema}: {e}") from None
|
||||
dump_ir(g, args.output, f"{len(g.nodes)} nodes, {len(g.edges)} edges -> {args.output}")
|
||||
return 0
|
||||
|
||||
|
||||
def openapi(argv) -> int:
|
||||
args = _parser("openapi", "--spec", "An OpenAPI document.").parse_args(argv)
|
||||
from ..extractors.openapi import extract
|
||||
|
||||
try:
|
||||
g = extract(args.spec)
|
||||
except (OSError, ImportError, ValueError) as e:
|
||||
raise Abort(str(e)) from None
|
||||
eps = sum(1 for n in g.nodes if n.kind == "endpoint")
|
||||
dump_ir(g, args.output,
|
||||
f"{len(g.nodes)} nodes ({eps} endpoints), {len(g.edges)} edges -> {args.output}")
|
||||
return 0
|
||||
|
||||
|
||||
def usage(argv) -> int:
|
||||
args = _parser("usage", "--har",
|
||||
"A HAR recording, as devtools/mitmproxy/Charles export.").parse_args(argv)
|
||||
from ..extractors.usage import extract
|
||||
|
||||
try:
|
||||
g = extract(args.har)
|
||||
except (OSError, json.JSONDecodeError, KeyError) as e:
|
||||
raise Abort(f"could not read {args.har}: {e}") from None
|
||||
eps = sum(1 for n in g.nodes if n.kind == "endpoint")
|
||||
ops = sum(1 for n in g.nodes if n.kind == "operation")
|
||||
dump_ir(g, args.output,
|
||||
f"{len(g.nodes)} nodes ({eps} endpoints, {ops} graphql), "
|
||||
f"{len(g.edges)} sequence edges -> {args.output}")
|
||||
return 0
|
||||
|
||||
|
||||
READERS = {"python": python, "code": code, "db": db, "openapi": openapi, "usage": usage}
|
||||
|
||||
|
||||
def main(argv) -> int:
|
||||
if not argv or argv[0] in ("-h", "--help"):
|
||||
print(__doc__.strip("\n"))
|
||||
return 0 if argv else 2
|
||||
if argv[0] not in READERS:
|
||||
raise Abort(f"no reader {argv[0]!r} — have: {', '.join(READERS)}")
|
||||
return READERS[argv[0]](argv[1:])
|
||||
79
soleprint/atlas2/docgen/cli/run.py
Normal file
79
soleprint/atlas2/docgen/cli/run.py
Normal file
@@ -0,0 +1,79 @@
|
||||
"""
|
||||
python3 -m docgen run [docgen.toml] [--only NAME ...] [--check] [--list]
|
||||
|
||||
Every book a run file lists, rebuilt in order. See `book/config.py` for the file.
|
||||
|
||||
--only NAME just these books (repeatable), still in run-file order
|
||||
--check run each book's own level after building it
|
||||
--list print what would run, fully resolved, and build nothing
|
||||
|
||||
One failing book never stops the rest; the run exits 1 if any book failed to
|
||||
build, lost input between its two ends, or failed its checks. Without a path it
|
||||
reads `docgen.toml` in the current directory.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
from .common import PROG, Abort
|
||||
|
||||
|
||||
def main(argv) -> int:
|
||||
p = argparse.ArgumentParser(prog=f"{PROG} run")
|
||||
p.add_argument("config", type=Path, nargs="?", default=Path("docgen.toml"))
|
||||
p.add_argument("--only", action="append", default=[], metavar="NAME")
|
||||
p.add_argument("--check", action="store_true",
|
||||
help="Run each book's own level after building it.")
|
||||
p.add_argument("--list", action="store_true",
|
||||
help="Print what would run, resolved, and build nothing.")
|
||||
p.add_argument("--verbose", "-v", action="store_true",
|
||||
help="Show each book's own output, not just the summary.")
|
||||
args = p.parse_args(argv)
|
||||
|
||||
from ..book.config import ConfigError, load, run
|
||||
|
||||
if not args.config.exists():
|
||||
raise Abort(f"no run file at {args.config} — see docgen.example.toml")
|
||||
try:
|
||||
runfile = load(args.config)
|
||||
selected = runfile.select(args.only)
|
||||
except ConfigError as e:
|
||||
raise Abort(str(e)) from None
|
||||
|
||||
if args.list:
|
||||
# The resolved form, because the whole question a run file raises is
|
||||
# "relative to what" — and the answer should be visible, not inferred.
|
||||
print(f"{runfile.path} — {len(selected)} of {len(runfile.books)} book(s)")
|
||||
if runfile.reference:
|
||||
print(f" reference {runfile.reference}")
|
||||
for b in selected:
|
||||
print(f" {b.line()}")
|
||||
return 0
|
||||
|
||||
print(f"{runfile.path} — {len(selected)} book(s)")
|
||||
results = run(runfile, [b.name for b in selected], check=args.check,
|
||||
quiet=not args.verbose)
|
||||
|
||||
width = max(len(r["name"]) for r in results)
|
||||
for r in results:
|
||||
if r["error"]:
|
||||
# First line only: a missing-reference error is a paragraph of advice,
|
||||
# and in a summary table it buries the next book's row.
|
||||
status, detail = "FAIL", r["error"].splitlines()[0]
|
||||
elif r["lost"]:
|
||||
status, detail = "LOST", "; ".join(r["lost"])
|
||||
elif r["checks_failed"]:
|
||||
status, detail = "FAIL", f"{len(r['checks_failed'])} check(s): " \
|
||||
+ ", ".join(r["checks_failed"][:3])
|
||||
else:
|
||||
status, detail = "ok ", r["out"]
|
||||
print(f" {status} {r['name']:<{width}} {detail}")
|
||||
|
||||
failed = [r for r in results if not r["ok"]]
|
||||
print()
|
||||
if failed:
|
||||
print(f"{len(failed)} of {len(results)} book(s) did not hold"
|
||||
+ ("" if args.verbose else " — --verbose for each book's own output"))
|
||||
return 1
|
||||
print(f"{len(results)} book(s) built" + (" and checked" if args.check else ""))
|
||||
return 0
|
||||
32
soleprint/atlas2/docgen/cli/validate.py
Normal file
32
soleprint/atlas2/docgen/cli/validate.py
Normal file
@@ -0,0 +1,32 @@
|
||||
"""
|
||||
python3 -m docgen validate <ir.json>
|
||||
|
||||
Check a document at the boundary. Also checks that `ir/model.py` and
|
||||
`ir/schema.json` still agree, since a document can only be as right as the
|
||||
contract it is checked against.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
from .common import PROG, Abort, read_json
|
||||
|
||||
|
||||
def main(argv) -> int:
|
||||
p = argparse.ArgumentParser(prog=f"{PROG} validate")
|
||||
p.add_argument("ir", type=Path)
|
||||
args = p.parse_args(argv)
|
||||
from ..ir.validate import check, check_model_matches_schema
|
||||
|
||||
drift = check_model_matches_schema()
|
||||
if drift:
|
||||
raise Abort("model.py and schema.json disagree:\n " + "\n ".join(drift))
|
||||
|
||||
data = read_json(args.ir)
|
||||
problems = check(data)
|
||||
if problems:
|
||||
raise Abort(f"{args.ir}: {len(problems)} problem(s)\n " + "\n ".join(problems))
|
||||
|
||||
print(f"{args.ir}: ok — {len(data['nodes'])} nodes, {len(data['edges'])} edges, "
|
||||
f"schema v{data['meta'].get('schema_version')}")
|
||||
return 0
|
||||
@@ -1,18 +1,19 @@
|
||||
""" python3 -m docgen.ops <ir.json> [views...] [-o out.json]
|
||||
"""
|
||||
python3 -m docgen view <ir.json> [views...] [-o out.json]
|
||||
|
||||
Views compose, left to right, in the order given on the command line."""
|
||||
IR -> a smaller IR. Views compose, applied in a fixed order: overview, the drops,
|
||||
only, subtree, around, depth. Each produces a document that still validates.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from ..ir import check
|
||||
from . import filter as F
|
||||
from .common import PROG, Abort, emit, read_json
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
p = argparse.ArgumentParser(prog="python3 -m docgen.ops")
|
||||
def main(argv) -> int:
|
||||
p = argparse.ArgumentParser(prog=f"{PROG} view")
|
||||
p.add_argument("ir", type=Path)
|
||||
p.add_argument("--output", "-o", type=Path)
|
||||
p.add_argument("--overview", action="store_true",
|
||||
@@ -32,12 +33,12 @@ def main(argv=None):
|
||||
help="Report what this will look like, and write nothing.")
|
||||
args = p.parse_args(argv)
|
||||
|
||||
try:
|
||||
ir = json.loads(args.ir.read_text())
|
||||
except (OSError, json.JSONDecodeError) as e:
|
||||
print(f"Error: could not read {args.ir}: {e}", file=sys.stderr)
|
||||
return 1
|
||||
from ..ir import check
|
||||
from ..ops import filter as F
|
||||
|
||||
# Read without validating first: a view is often how an oversized document
|
||||
# is made readable, and the result is validated before it is written.
|
||||
ir = read_json(args.ir)
|
||||
before = (len(ir["nodes"]), len(ir["edges"]))
|
||||
|
||||
if args.overview:
|
||||
@@ -60,42 +61,29 @@ def main(argv=None):
|
||||
ir = F.collapse_to_depth(ir, args.depth)
|
||||
|
||||
if args.shape:
|
||||
sh = F.shape(ir)
|
||||
for k, v in sh.items():
|
||||
for k, v in F.shape(ir).items():
|
||||
print(f" {k:<14} {v}")
|
||||
return 0
|
||||
|
||||
if args.split:
|
||||
if not args.output:
|
||||
print("Error: --split needs -o DIRECTORY", file=sys.stderr)
|
||||
return 1
|
||||
raise Abort("--split needs -o DIRECTORY")
|
||||
args.output.mkdir(parents=True, exist_ok=True)
|
||||
for name, part in F.split(ir).items():
|
||||
(args.output / f"{name}.json").write_text(json.dumps(part, indent=2) + "\n")
|
||||
target = args.output / f"{name}.json"
|
||||
target.write_text(json.dumps(part, indent=2) + "\n")
|
||||
sh = F.shape(part)
|
||||
print(f" {name:<16} {sh['nodes']:>4} nodes {sh['edges']:>4} edges "
|
||||
f"-> {args.output / (name + '.json')}")
|
||||
print(f" {name:<16} {sh['nodes']:>4} nodes {sh['edges']:>4} edges -> {target}")
|
||||
return 0
|
||||
|
||||
problems = check(ir)
|
||||
if problems:
|
||||
# A view that produces an invalid document is a bug in the view, and it
|
||||
# must not be written out for an emitter to trip over later.
|
||||
print(f"Error: the view produced an invalid IR ({len(problems)}):", file=sys.stderr)
|
||||
for pr in problems[:5]:
|
||||
print(f" {pr}", file=sys.stderr)
|
||||
return 1
|
||||
raise Abort(f"the view produced an invalid IR ({len(problems)}):\n "
|
||||
+ "\n ".join(problems[:5]))
|
||||
|
||||
text = json.dumps(ir, indent=2) + "\n"
|
||||
if args.output:
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.output.write_text(text)
|
||||
print(f" {before[0]} nodes, {before[1]} edges -> "
|
||||
f"{len(ir['nodes'])} nodes, {len(ir['edges'])} edges -> {args.output}")
|
||||
else:
|
||||
sys.stdout.write(text)
|
||||
emit(json.dumps(ir, indent=2) + "\n", args.output,
|
||||
f" {before[0]} nodes, {before[1]} edges -> "
|
||||
f"{len(ir['nodes'])} nodes, {len(ir['edges'])} edges -> {args.output}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
45
soleprint/atlas2/docgen/docgen.example.toml
Normal file
45
soleprint/atlas2/docgen/docgen.example.toml
Normal file
@@ -0,0 +1,45 @@
|
||||
# A run file: every book a project builds, rebuilt with one command.
|
||||
#
|
||||
# make run CONFIG=docgen.example.toml
|
||||
# python3 -m docgen run docgen.example.toml --only schema --check
|
||||
# python3 -m docgen run docgen.example.toml --list # resolved, nothing built
|
||||
#
|
||||
# Copy it next to the project it describes and edit the books. Paths are relative
|
||||
# to THIS FILE, not to where the command runs — so the same file builds the same
|
||||
# books from any directory. Unknown keys are refused rather than ignored.
|
||||
|
||||
# Optional. Where the repo holding station/tools/modelgen is, for reading
|
||||
# OpenAPI. $DOCGEN_REFERENCE wins over this when it is set.
|
||||
# reference = "../../"
|
||||
|
||||
[defaults]
|
||||
out = "out/run" # each book lands in <out>/<name> unless it sets `out`
|
||||
style = "lucid"
|
||||
theme = "dark"
|
||||
# A book's own value REPLACES a default, for every key — exclude included.
|
||||
exclude = ["__pycache__", "node_modules"]
|
||||
|
||||
# A tree of Python — here, docgen's own extractors. A book may not be written
|
||||
# inside the tree it reads (the next run would read the last run's output), so a
|
||||
# `root` of "." would need an `out` outside this folder.
|
||||
[[book]]
|
||||
name = "extractors"
|
||||
root = "extractors"
|
||||
|
||||
# A database schema, as modelgen writes it.
|
||||
[[book]]
|
||||
name = "schema"
|
||||
schema = "fixtures/shop.json"
|
||||
|
||||
# An OpenAPI document. Needs pyyaml and the reference repo; without them this
|
||||
# one book fails and says why, and the others still build.
|
||||
[[book]]
|
||||
name = "api"
|
||||
openapi = "fixtures/orders.yaml"
|
||||
theme = "lucid"
|
||||
|
||||
# Another tree read with tree-sitter instead (C#, TypeScript):
|
||||
# [[book]]
|
||||
# name = "frontend"
|
||||
# root = "../frontend/src"
|
||||
# reader = "code"
|
||||
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 70 KiB |
@@ -1,386 +1,406 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="886pt" height="2251pt" viewBox="0 0 886 2251">
|
||||
<rect width="886" height="2251" fill="#0a0a0a"/>
|
||||
<rect x="28.0" y="46.0" width="74.0" height="247.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.site — 494 lines</title></rect>
|
||||
<rect x="28.0" y="182.0" width="74.0" height="27.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.site._ledger" data-kind="function" class="blk"><title>_ledger — function, 54 lines</title></rect>
|
||||
<rect x="28.0" y="210.0" width="74.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.site._slots" data-kind="function" class="blk"><title>_slots — function, 13 lines</title></rect>
|
||||
<rect x="28.0" y="217.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.site._fill" data-kind="function" class="blk"><title>_fill — function, 4 lines</title></rect>
|
||||
<rect x="28.0" y="220.5" width="74.0" height="8.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.site._sidebar" data-kind="function" class="blk"><title>_sidebar — function, 17 lines</title></rect>
|
||||
<rect x="28.0" y="230.0" width="74.0" height="7.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.site._sections" data-kind="function" class="blk"><title>_sections — function, 15 lines</title></rect>
|
||||
<rect x="28.0" y="238.5" width="74.0" height="48.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.site.emit" data-kind="function" class="blk"><title>emit — function, 96 lines</title></rect>
|
||||
<rect x="28.0" y="287.5" width="74.0" height="5.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.site.write" data-kind="function" class="blk"><title>write — function, 10 lines</title></rect>
|
||||
<rect x="110.0" y="46.0" width="74.0" height="158.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.explore — 316 lines</title></rect>
|
||||
<rect x="110.0" y="65.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.explore._is_schema" data-kind="function" class="blk"><title>_is_schema — function, 4 lines</title></rect>
|
||||
<rect x="110.0" y="68.5" width="74.0" height="24.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.explore._neighbourhood_svgs" data-kind="function" class="blk"><title>_neighbourhood_svgs — function, 48 lines</title></rect>
|
||||
<rect x="117.0" y="75.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.emitters.explore._neighbourhood_svgs.render_one" data-kind="function" class="blk"><title>render_one — function, 2 lines</title></rect>
|
||||
<rect x="117.0" y="78.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.emitters.explore._neighbourhood_svgs.render_one#L66" data-kind="function" class="blk"><title>render_one — function, 2 lines</title></rect>
|
||||
<rect x="110.0" y="93.5" width="74.0" height="13.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.explore._facts" data-kind="function" class="blk"><title>_facts — function, 27 lines</title></rect>
|
||||
<rect x="110.0" y="108.0" width="74.0" height="86.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.explore.emit" data-kind="function" class="blk"><title>emit — function, 172 lines</title></rect>
|
||||
<rect x="110.0" y="195.0" width="74.0" height="8.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.explore.write" data-kind="function" class="blk"><title>write — function, 17 lines</title></rect>
|
||||
<rect x="192.0" y="46.0" width="74.0" height="146.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.dot — 292 lines</title></rect>
|
||||
<rect x="192.0" y="64.5" width="74.0" height="2.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.emitters.dot.RenderError" data-kind="class" class="blk"><title>RenderError — class, 2 lines</title></rect>
|
||||
<rect x="192.0" y="66.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot._esc" data-kind="function" class="blk"><title>_esc — function, 2 lines</title></rect>
|
||||
<rect x="192.0" y="68.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot._attrs" data-kind="function" class="blk"><title>_attrs — function, 3 lines</title></rect>
|
||||
<rect x="192.0" y="71.0" width="74.0" height="4.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot._style_words" data-kind="function" class="blk"><title>_style_words — function, 9 lines</title></rect>
|
||||
<rect x="192.0" y="76.5" width="74.0" height="12.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot._node_attrs" data-kind="function" class="blk"><title>_node_attrs — function, 24 lines</title></rect>
|
||||
<rect x="192.0" y="89.5" width="74.0" height="52.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot.emit" data-kind="function" class="blk"><title>emit — function, 105 lines</title></rect>
|
||||
<rect x="199.0" y="103.0" width="60.0" height="14.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.emitters.dot.emit.write" data-kind="function" class="blk"><title>write — function, 29 lines</title></rect>
|
||||
<rect x="192.0" y="143.0" width="74.0" height="4.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot._within" data-kind="function" class="blk"><title>_within — function, 8 lines</title></rect>
|
||||
<rect x="192.0" y="148.0" width="74.0" height="20.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot._endpoints" data-kind="function" class="blk"><title>_endpoints — function, 41 lines</title></rect>
|
||||
<rect x="199.0" y="153.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.emitters.dot._endpoints.walk" data-kind="function" class="blk"><title>walk — function, 4 lines</title></rect>
|
||||
<rect x="199.0" y="157.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.emitters.dot._endpoints.collapsed" data-kind="function" class="blk"><title>collapsed — function, 2 lines</title></rect>
|
||||
<rect x="199.0" y="158.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.emitters.dot._endpoints.first_leaf" data-kind="function" class="blk"><title>first_leaf — function, 4 lines</title></rect>
|
||||
<rect x="192.0" y="169.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot._safe" data-kind="function" class="blk"><title>_safe — function, 2 lines</title></rect>
|
||||
<rect x="192.0" y="171.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot._q" data-kind="function" class="blk"><title>_q — function, 2 lines</title></rect>
|
||||
<rect x="192.0" y="175.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot.have_graphviz" data-kind="function" class="blk"><title>have_graphviz — function, 2 lines</title></rect>
|
||||
<rect x="192.0" y="177.0" width="74.0" height="14.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot.render" data-kind="function" class="blk"><title>render — function, 29 lines</title></rect>
|
||||
<rect x="274.0" y="46.0" width="74.0" height="139.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.notebook — 279 lines</title></rect>
|
||||
<rect x="274.0" y="67.0" width="74.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.notebook._cell" data-kind="function" class="blk"><title>_cell — function, 13 lines</title></rect>
|
||||
<rect x="274.0" y="74.5" width="74.0" height="13.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.notebook._example" data-kind="function" class="blk"><title>_example — function, 26 lines</title></rect>
|
||||
<rect x="274.0" y="108.0" width="74.0" height="9.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.notebook._params_cell" data-kind="function" class="blk"><title>_params_cell — function, 18 lines</title></rect>
|
||||
<rect x="274.0" y="118.0" width="74.0" height="20.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.notebook._call_cell" data-kind="function" class="blk"><title>_call_cell — function, 40 lines</title></rect>
|
||||
<rect x="274.0" y="139.0" width="74.0" height="13.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.notebook._call_md" data-kind="function" class="blk"><title>_call_md — function, 26 lines</title></rect>
|
||||
<rect x="274.0" y="153.0" width="74.0" height="26.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.notebook.build" data-kind="function" class="blk"><title>build — function, 52 lines</title></rect>
|
||||
<rect x="274.0" y="180.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.notebook.emit" data-kind="function" class="blk"><title>emit — function, 3 lines</title></rect>
|
||||
<rect x="274.0" y="182.5" width="74.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.notebook.write" data-kind="function" class="blk"><title>write — function, 5 lines</title></rect>
|
||||
<rect x="356.0" y="46.0" width="74.0" height="139.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.minimap — 278 lines</title></rect>
|
||||
<rect x="356.0" y="77.5" width="74.0" height="28.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.minimap._files" data-kind="function" class="blk"><title>_files — function, 57 lines</title></rect>
|
||||
<rect x="363.0" y="81.5" width="60.0" height="9.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.emitters.minimap._files.declared" data-kind="function" class="blk"><title>declared — function, 18 lines</title></rect>
|
||||
<rect x="363.0" y="91.0" width="60.0" height="5.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.emitters.minimap._files.build" data-kind="function" class="blk"><title>build — function, 11 lines</title></rect>
|
||||
<rect x="356.0" y="107.0" width="74.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.minimap._bands" data-kind="function" class="blk"><title>_bands — function, 7 lines</title></rect>
|
||||
<rect x="356.0" y="111.5" width="74.0" height="9.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.minimap._blocks" data-kind="function" class="blk"><title>_blocks — function, 19 lines</title></rect>
|
||||
<rect x="356.0" y="122.0" width="74.0" height="60.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.minimap.emit" data-kind="function" class="blk"><title>emit — function, 120 lines</title></rect>
|
||||
<rect x="356.0" y="183.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.minimap.marks_to_labels" data-kind="function" class="blk"><title>marks_to_labels — function, 3 lines</title></rect>
|
||||
<rect x="438.0" y="46.0" width="74.0" height="130.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.erd — 260 lines</title></rect>
|
||||
<rect x="438.0" y="73.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.erd._truncate" data-kind="function" class="blk"><title>_truncate — function, 3 lines</title></rect>
|
||||
<rect x="438.0" y="75.5" width="74.0" height="10.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.erd._tables" data-kind="function" class="blk"><title>_tables — function, 20 lines</title></rect>
|
||||
<rect x="438.0" y="86.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.erd._card_height" data-kind="function" class="blk"><title>_card_height — function, 3 lines</title></rect>
|
||||
<rect x="438.0" y="89.0" width="74.0" height="10.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.erd.layout" data-kind="function" class="blk"><title>layout — function, 20 lines</title></rect>
|
||||
<rect x="438.0" y="100.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.erd._field_y" data-kind="function" class="blk"><title>_field_y — function, 3 lines</title></rect>
|
||||
<rect x="438.0" y="102.5" width="74.0" height="73.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.erd.emit" data-kind="function" class="blk"><title>emit — function, 146 lines</title></rect>
|
||||
<rect x="520.0" y="46.0" width="74.0" height="82.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.index — 164 lines</title></rect>
|
||||
<rect x="520.0" y="63.0" width="74.0" height="4.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.index._tree" data-kind="function" class="blk"><title>_tree — function, 8 lines</title></rect>
|
||||
<rect x="520.0" y="68.0" width="74.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.index._anchor" data-kind="function" class="blk"><title>_anchor — function, 5 lines</title></rect>
|
||||
<rect x="520.0" y="71.5" width="74.0" height="42.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.index.to_markdown" data-kind="function" class="blk"><title>to_markdown — function, 84 lines</title></rect>
|
||||
<rect x="527.0" y="83.0" width="60.0" height="13.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.emitters.index.to_markdown.walk" data-kind="function" class="blk"><title>walk — function, 27 lines</title></rect>
|
||||
<rect x="520.0" y="114.5" width="74.0" height="13.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.index.to_sidebar" data-kind="function" class="blk"><title>to_sidebar — function, 26 lines</title></rect>
|
||||
<rect x="527.0" y="118.0" width="60.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.emitters.index.to_sidebar.build" data-kind="function" class="blk"><title>build — function, 13 lines</title></rect>
|
||||
<rect x="602.0" y="46.0" width="74.0" height="43.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.cli_dot — 87 lines</title></rect>
|
||||
<rect x="602.0" y="52.5" width="74.0" height="36.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.cli_dot.main" data-kind="function" class="blk"><title>main — function, 73 lines</title></rect>
|
||||
<rect x="684.0" y="46.0" width="74.0" height="40.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.auto — 80 lines</title></rect>
|
||||
<rect x="684.0" y="57.5" width="74.0" height="28.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.auto.main" data-kind="function" class="blk"><title>main — function, 56 lines</title></rect>
|
||||
<rect x="766.0" y="46.0" width="74.0" height="37.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.cli_notebook — 74 lines</title></rect>
|
||||
<rect x="766.0" y="54.0" width="74.0" height="28.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.cli_notebook.main" data-kind="function" class="blk"><title>main — function, 57 lines</title></rect>
|
||||
<rect x="28.0" y="331.0" width="74.0" height="37.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.cli_site — 74 lines</title></rect>
|
||||
<rect x="28.0" y="339.0" width="74.0" height="28.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.cli_site.main" data-kind="function" class="blk"><title>main — function, 57 lines</title></rect>
|
||||
<rect x="110.0" y="331.0" width="74.0" height="25.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.cli_erd — 51 lines</title></rect>
|
||||
<rect x="110.0" y="337.0" width="74.0" height="19.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.cli_erd.main" data-kind="function" class="blk"><title>main — function, 38 lines</title></rect>
|
||||
<rect x="192.0" y="331.0" width="74.0" height="25.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.cli_minimap — 51 lines</title></rect>
|
||||
<rect x="192.0" y="337.5" width="74.0" height="18.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.cli_minimap.main" data-kind="function" class="blk"><title>main — function, 37 lines</title></rect>
|
||||
<rect x="274.0" y="331.0" width="74.0" height="24.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.cli_explore — 48 lines</title></rect>
|
||||
<rect x="274.0" y="337.0" width="74.0" height="17.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.cli_explore.main" data-kind="function" class="blk"><title>main — function, 35 lines</title></rect>
|
||||
<rect x="356.0" y="331.0" width="74.0" height="22.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.cli_index — 44 lines</title></rect>
|
||||
<rect x="356.0" y="336.5" width="74.0" height="16.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.cli_index.main" data-kind="function" class="blk"><title>main — function, 32 lines</title></rect>
|
||||
<rect x="438.0" y="331.0" width="74.0" height="18.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.__main__ — 37 lines</title></rect>
|
||||
<rect x="438.0" y="333.5" width="74.0" height="13.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.__main__.main" data-kind="function" class="blk"><title>main — function, 27 lines</title></rect>
|
||||
<rect x="538.0" y="331.0" width="74.0" height="1007.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.selftest — 2014 lines</title></rect>
|
||||
<rect x="538.0" y="375.5" width="74.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.selftest.check" data-kind="function" class="blk"><title>check — function, 5 lines</title></rect>
|
||||
<rect x="538.0" y="379.0" width="74.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.selftest._err" data-kind="function" class="blk"><title>_err — function, 7 lines</title></rect>
|
||||
<rect x="538.0" y="383.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.selftest.skip" data-kind="function" class="blk"><title>skip — function, 3 lines</title></rect>
|
||||
<rect x="538.0" y="386.0" width="74.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.selftest.build_tree" data-kind="function" class="blk"><title>build_tree — function, 5 lines</title></rect>
|
||||
<rect x="538.0" y="515.5" width="74.0" height="97.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.selftest._harvesting" data-kind="function" class="blk"><title>_harvesting — function, 194 lines</title></rect>
|
||||
<rect x="538.0" y="858.0" width="74.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.selftest._entry" data-kind="function" class="blk"><title>_entry — function, 7 lines</title></rect>
|
||||
<rect x="538.0" y="1111.0" width="74.0" height="139.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.selftest._books" data-kind="function" class="blk"><title>_books — function, 279 lines</title></rect>
|
||||
<rect x="538.0" y="1255.5" width="74.0" height="76.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.selftest._standalone" data-kind="function" class="blk"><title>_standalone — function, 153 lines</title></rect>
|
||||
<rect x="620.0" y="331.0" width="74.0" height="158.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.book — 316 lines</title></rect>
|
||||
<rect x="620.0" y="360.0" width="74.0" height="10.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.book.Step" data-kind="class" class="blk"><title>Step — class, 20 lines</title></rect>
|
||||
<rect x="627.0" y="365.0" width="60.0" height="5.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.Step.to_dict" data-kind="function" class="blk"><title>to_dict — function, 10 lines</title></rect>
|
||||
<rect x="620.0" y="381.5" width="74.0" height="15.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book._unit_counts" data-kind="function" class="blk"><title>_unit_counts — function, 30 lines</title></rect>
|
||||
<rect x="620.0" y="397.5" width="74.0" height="89.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.book.Book" data-kind="class" class="blk"><title>Book — class, 178 lines</title></rect>
|
||||
<rect x="627.0" y="399.0" width="60.0" height="8.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.Book.__init__" data-kind="function" class="blk"><title>__init__ — function, 17 lines</title></rect>
|
||||
<rect x="627.0" y="409.0" width="60.0" height="7.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.Book.step" data-kind="function" class="blk"><title>step — function, 14 lines</title></rect>
|
||||
<rect x="627.0" y="417.5" width="60.0" height="10.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.Book.measure" data-kind="function" class="blk"><title>measure — function, 21 lines</title></rect>
|
||||
<rect x="627.0" y="428.5" width="60.0" height="31.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.Book.compare" data-kind="function" class="blk"><title>compare — function, 62 lines</title></rect>
|
||||
<rect x="627.0" y="461.0" width="60.0" height="13.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.Book.close" data-kind="function" class="blk"><title>close — function, 27 lines</title></rect>
|
||||
<rect x="627.0" y="475.0" width="60.0" height="8.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.Book.to_dict" data-kind="function" class="blk"><title>to_dict — function, 17 lines</title></rect>
|
||||
<rect x="627.0" y="484.0" width="60.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.Book.write" data-kind="function" class="blk"><title>write — function, 5 lines</title></rect>
|
||||
<rect x="620.0" y="487.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book._tree_bytes" data-kind="function" class="blk"><title>_tree_bytes — function, 2 lines</title></rect>
|
||||
<rect x="702.0" y="331.0" width="74.0" height="97.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.style — 194 lines</title></rect>
|
||||
<rect x="702.0" y="353.5" width="74.0" height="2.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.style.StyleError" data-kind="class" class="blk"><title>StyleError — class, 2 lines</title></rect>
|
||||
<rect x="702.0" y="355.5" width="74.0" height="66.5" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.style.Style" data-kind="class" class="blk"><title>Style — class, 133 lines</title></rect>
|
||||
<rect x="709.0" y="357.0" width="60.0" height="8.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.__init__" data-kind="function" class="blk"><title>__init__ — function, 17 lines</title></rect>
|
||||
<rect x="709.0" y="367.5" width="60.0" height="6.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.load" data-kind="function" class="blk"><title>load — function, 12 lines</title></rect>
|
||||
<rect x="709.0" y="374.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.available" data-kind="function" class="blk"><title>available — function, 2 lines</title></rect>
|
||||
<rect x="709.0" y="376.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.themes" data-kind="function" class="blk"><title>themes — function, 2 lines</title></rect>
|
||||
<rect x="709.0" y="378.5" width="60.0" height="16.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.validate" data-kind="function" class="blk"><title>validate — function, 32 lines</title></rect>
|
||||
<rect x="709.0" y="396.0" width="60.0" height="6.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style._resolve" data-kind="function" class="blk"><title>_resolve — function, 12 lines</title></rect>
|
||||
<rect x="709.0" y="402.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style._lookup" data-kind="function" class="blk"><title>_lookup — function, 3 lines</title></rect>
|
||||
<rect x="709.0" y="404.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.node" data-kind="function" class="blk"><title>node — function, 2 lines</title></rect>
|
||||
<rect x="709.0" y="406.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.group" data-kind="function" class="blk"><title>group — function, 2 lines</title></rect>
|
||||
<rect x="709.0" y="407.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.edge" data-kind="function" class="blk"><title>edge — function, 2 lines</title></rect>
|
||||
<rect x="709.0" y="409.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.graph" data-kind="function" class="blk"><title>graph — function, 2 lines</title></rect>
|
||||
<rect x="709.0" y="410.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.geom" data-kind="function" class="blk"><title>geom — function, 2 lines</title></rect>
|
||||
<rect x="709.0" y="412.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.slot" data-kind="function" class="blk"><title>slot — function, 2 lines</title></rect>
|
||||
<rect x="709.0" y="413.5" width="60.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.domain_slot" data-kind="function" class="blk"><title>domain_slot — function, 13 lines</title></rect>
|
||||
<rect x="709.0" y="420.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.limits" data-kind="function" class="blk"><title>limits — function, 3 lines</title></rect>
|
||||
<rect x="702.0" y="423.0" width="74.0" height="4.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.harvest" data-kind="function" class="blk"><title>harvest — function, 9 lines</title></rect>
|
||||
<rect x="784.0" y="331.0" width="74.0" height="54.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.reference — 108 lines</title></rect>
|
||||
<rect x="784.0" y="354.0" width="74.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.reference._candidates" data-kind="function" class="blk"><title>_candidates — function, 7 lines</title></rect>
|
||||
<rect x="784.0" y="358.5" width="74.0" height="4.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.reference.root" data-kind="function" class="blk"><title>root — function, 9 lines</title></rect>
|
||||
<rect x="784.0" y="364.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.reference.station_tools" data-kind="function" class="blk"><title>station_tools — function, 4 lines</title></rect>
|
||||
<rect x="784.0" y="367.0" width="74.0" height="5.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.reference.describe" data-kind="function" class="blk"><title>describe — function, 10 lines</title></rect>
|
||||
<rect x="784.0" y="373.0" width="74.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.reference.on_path" data-kind="function" class="blk"><title>on_path — function, 13 lines</title></rect>
|
||||
<rect x="784.0" y="380.5" width="74.0" height="4.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.reference.missing" data-kind="function" class="blk"><title>missing — function, 8 lines</title></rect>
|
||||
<rect x="28.0" y="1376.0" width="74.0" height="14.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.ops — 28 lines</title></rect>
|
||||
<rect x="110.0" y="1376.0" width="74.0" height="14.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.notebook — 15 lines</title></rect>
|
||||
<rect x="192.0" y="1376.0" width="74.0" height="14.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters — 12 lines</title></rect>
|
||||
<rect x="274.0" y="1376.0" width="74.0" height="14.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.lab — 11 lines</title></rect>
|
||||
<rect x="356.0" y="1376.0" width="74.0" height="14.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.ir — 7 lines</title></rect>
|
||||
<rect x="438.0" y="1376.0" width="74.0" height="14.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors — 2 lines</title></rect>
|
||||
<rect x="538.0" y="1376.0" width="74.0" height="141.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors.code — 282 lines</title></rect>
|
||||
<rect x="538.0" y="1423.5" width="74.0" height="2.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.extractors.code.MissingParser" data-kind="class" class="blk"><title>MissingParser — class, 2 lines</title></rect>
|
||||
<rect x="538.0" y="1425.5" width="74.0" height="10.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.code._parser" data-kind="function" class="blk"><title>_parser — function, 21 lines</title></rect>
|
||||
<rect x="538.0" y="1437.0" width="74.0" height="5.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.code._name" data-kind="function" class="blk"><title>_name — function, 10 lines</title></rect>
|
||||
<rect x="538.0" y="1443.0" width="74.0" height="17.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.code._walk" data-kind="function" class="blk"><title>_walk — function, 34 lines</title></rect>
|
||||
<rect x="538.0" y="1461.0" width="74.0" height="13.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.code.extract_file" data-kind="function" class="blk"><title>extract_file — function, 27 lines</title></rect>
|
||||
<rect x="538.0" y="1475.5" width="74.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.code._count_errors" data-kind="function" class="blk"><title>_count_errors — function, 5 lines</title></rect>
|
||||
<rect x="538.0" y="1479.0" width="74.0" height="37.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.code.extract" data-kind="function" class="blk"><title>extract — function, 75 lines</title></rect>
|
||||
<rect x="620.0" y="1376.0" width="74.0" height="134.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors.usage — 269 lines</title></rect>
|
||||
<rect x="620.0" y="1408.0" width="74.0" height="13.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.usage._template" data-kind="function" class="blk"><title>_template — function, 27 lines</title></rect>
|
||||
<rect x="620.0" y="1422.5" width="74.0" height="5.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.usage._body" data-kind="function" class="blk"><title>_body — function, 10 lines</title></rect>
|
||||
<rect x="620.0" y="1428.5" width="74.0" height="7.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.usage._shape" data-kind="function" class="blk"><title>_shape — function, 15 lines</title></rect>
|
||||
<rect x="620.0" y="1437.0" width="74.0" height="5.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.usage._graphql" data-kind="function" class="blk"><title>_graphql — function, 11 lines</title></rect>
|
||||
<rect x="620.0" y="1443.5" width="74.0" height="66.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.usage.extract" data-kind="function" class="blk"><title>extract — function, 133 lines</title></rect>
|
||||
<rect x="702.0" y="1376.0" width="74.0" height="95.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors.openapi — 191 lines</title></rect>
|
||||
<rect x="702.0" y="1391.5" width="74.0" height="14.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.openapi._modelgen" data-kind="function" class="blk"><title>_modelgen — function, 28 lines</title></rect>
|
||||
<rect x="702.0" y="1406.5" width="74.0" height="3.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.openapi._type_name" data-kind="function" class="blk"><title>_type_name — function, 6 lines</title></rect>
|
||||
<rect x="702.0" y="1410.5" width="74.0" height="21.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.openapi._refs" data-kind="function" class="blk"><title>_refs — function, 43 lines</title></rect>
|
||||
<rect x="702.0" y="1433.0" width="74.0" height="38.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.openapi.extract" data-kind="function" class="blk"><title>extract — function, 76 lines</title></rect>
|
||||
<rect x="784.0" y="1376.0" width="74.0" height="80.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors.db — 161 lines</title></rect>
|
||||
<rect x="784.0" y="1395.5" width="74.0" height="41.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.db.from_schema_dict" data-kind="function" class="blk"><title>from_schema_dict — function, 82 lines</title></rect>
|
||||
<rect x="784.0" y="1437.5" width="74.0" height="5.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.db._relation" data-kind="function" class="blk"><title>_relation — function, 10 lines</title></rect>
|
||||
<rect x="784.0" y="1443.5" width="74.0" height="3.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.db._plain_type" data-kind="function" class="blk"><title>_plain_type — function, 6 lines</title></rect>
|
||||
<rect x="784.0" y="1447.5" width="74.0" height="4.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.db._dedupe" data-kind="function" class="blk"><title>_dedupe — function, 9 lines</title></rect>
|
||||
<rect x="784.0" y="1453.0" width="74.0" height="3.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.db.extract" data-kind="function" class="blk"><title>extract — function, 6 lines</title></rect>
|
||||
<rect x="28.0" y="1555.0" width="74.0" height="20.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors.code_main — 40 lines</title></rect>
|
||||
<rect x="28.0" y="1559.0" width="74.0" height="15.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.code_main.main" data-kind="function" class="blk"><title>main — function, 31 lines</title></rect>
|
||||
<rect x="110.0" y="1555.0" width="74.0" height="18.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors.python — 37 lines</title></rect>
|
||||
<rect x="110.0" y="1564.5" width="74.0" height="7.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.extract" data-kind="function" class="blk"><title>extract — function, 14 lines</title></rect>
|
||||
<rect x="192.0" y="1555.0" width="74.0" height="16.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors.usage_main — 33 lines</title></rect>
|
||||
<rect x="192.0" y="1559.0" width="74.0" height="12.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.usage_main.main" data-kind="function" class="blk"><title>main — function, 24 lines</title></rect>
|
||||
<rect x="274.0" y="1555.0" width="74.0" height="16.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors.db_main — 32 lines</title></rect>
|
||||
<rect x="274.0" y="1560.0" width="74.0" height="10.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.db_main.main" data-kind="function" class="blk"><title>main — function, 21 lines</title></rect>
|
||||
<rect x="356.0" y="1555.0" width="74.0" height="15.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors.openapi_main — 30 lines</title></rect>
|
||||
<rect x="356.0" y="1559.0" width="74.0" height="10.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.openapi_main.main" data-kind="function" class="blk"><title>main — function, 21 lines</title></rect>
|
||||
<rect x="438.0" y="1555.0" width="74.0" height="14.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors.__main__ — 26 lines</title></rect>
|
||||
<rect x="438.0" y="1557.7" width="74.0" height="8.6" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.__main__.main" data-kind="function" class="blk"><title>main — function, 16 lines</title></rect>
|
||||
<rect x="538.0" y="1555.0" width="74.0" height="175.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.book.build — 351 lines</title></rect>
|
||||
<rect x="538.0" y="1592.5" width="74.0" height="13.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.build.extract" data-kind="function" class="blk"><title>extract — function, 27 lines</title></rect>
|
||||
<rect x="538.0" y="1607.0" width="74.0" height="34.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.build.spec_from" data-kind="function" class="blk"><title>spec_from — function, 68 lines</title></rect>
|
||||
<rect x="538.0" y="1642.0" width="74.0" height="22.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.build._load_cell" data-kind="function" class="blk"><title>_load_cell — function, 44 lines</title></rect>
|
||||
<rect x="538.0" y="1665.0" width="74.0" height="65.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.build.run" data-kind="function" class="blk"><title>run — function, 130 lines</title></rect>
|
||||
<rect x="545.0" y="1671.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.build.run.say" data-kind="function" class="blk"><title>say — function, 3 lines</title></rect>
|
||||
<rect x="620.0" y="1555.0" width="74.0" height="153.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.book.checks — 306 lines</title></rect>
|
||||
<rect x="620.0" y="1585.5" width="74.0" height="13.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.book.checks.Loaded" data-kind="class" class="blk"><title>Loaded — class, 26 lines</title></rect>
|
||||
<rect x="627.0" y="1587.0" width="60.0" height="7.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.checks.Loaded.__init__" data-kind="function" class="blk"><title>__init__ — function, 15 lines</title></rect>
|
||||
<rect x="627.0" y="1595.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.checks.Loaded.larder" data-kind="function" class="blk"><title>larder — function, 2 lines</title></rect>
|
||||
<rect x="627.0" y="1597.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.checks.Loaded.measure" data-kind="function" class="blk"><title>measure — function, 2 lines</title></rect>
|
||||
<rect x="620.0" y="1599.5" width="74.0" height="18.5" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.book.checks.Report" data-kind="class" class="blk"><title>Report — class, 37 lines</title></rect>
|
||||
<rect x="627.0" y="1601.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.checks.Report.__init__" data-kind="function" class="blk"><title>__init__ — function, 2 lines</title></rect>
|
||||
<rect x="627.0" y="1602.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.checks.Report.note" data-kind="function" class="blk"><title>note — function, 2 lines</title></rect>
|
||||
<rect x="627.0" y="1604.0" width="60.0" height="4.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.checks.Report.check" data-kind="function" class="blk"><title>check — function, 8 lines</title></rect>
|
||||
<rect x="627.0" y="1608.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.checks.Report.skip" data-kind="function" class="blk"><title>skip — function, 3 lines</title></rect>
|
||||
<rect x="627.0" y="1610.5" width="60.0" height="7.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.checks.Report.total" data-kind="function" class="blk"><title>total — function, 15 lines</title></rect>
|
||||
<rect x="620.0" y="1619.0" width="74.0" height="41.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.checks.generated" data-kind="function" class="blk"><title>generated — function, 83 lines</title></rect>
|
||||
<rect x="620.0" y="1661.5" width="74.0" height="13.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.checks.custom" data-kind="function" class="blk"><title>custom — function, 26 lines</title></rect>
|
||||
<rect x="620.0" y="1675.5" width="74.0" height="16.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.checks._run_cells" data-kind="function" class="blk"><title>_run_cells — function, 33 lines</title></rect>
|
||||
<rect x="620.0" y="1693.0" width="74.0" height="12.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.checks.main" data-kind="function" class="blk"><title>main — function, 25 lines</title></rect>
|
||||
<rect x="702.0" y="1555.0" width="74.0" height="98.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.book.larder — 196 lines</title></rect>
|
||||
<rect x="702.0" y="1586.5" width="74.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.larder._count" data-kind="function" class="blk"><title>_count — function, 13 lines</title></rect>
|
||||
<rect x="702.0" y="1594.0" width="74.0" height="16.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.larder.redact" data-kind="function" class="blk"><title>redact — function, 32 lines</title></rect>
|
||||
<rect x="702.0" y="1611.5" width="74.0" height="38.5" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.book.larder.Larder" data-kind="class" class="blk"><title>Larder — class, 77 lines</title></rect>
|
||||
<rect x="709.0" y="1618.5" width="60.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.larder.Larder.__post_init__" data-kind="function" class="blk"><title>__post_init__ — function, 7 lines</title></rect>
|
||||
<rect x="709.0" y="1623.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.larder.Larder.read" data-kind="function" class="blk"><title>read — function, 3 lines</title></rect>
|
||||
<rect x="709.0" y="1625.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.larder.Larder.fail" data-kind="function" class="blk"><title>fail — function, 3 lines</title></rect>
|
||||
<rect x="709.0" y="1627.0" width="60.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.larder.Larder.to_dict" data-kind="function" class="blk"><title>to_dict — function, 13 lines</title></rect>
|
||||
<rect x="709.0" y="1634.5" width="60.0" height="5.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.larder.Larder.from_dict" data-kind="function" class="blk"><title>from_dict — function, 10 lines</title></rect>
|
||||
<rect x="709.0" y="1640.0" width="60.0" height="10.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.larder.Larder.line" data-kind="function" class="blk"><title>line — function, 20 lines</title></rect>
|
||||
<rect x="702.0" y="1651.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.larder.of" data-kind="function" class="blk"><title>of — function, 3 lines</title></rect>
|
||||
<rect x="784.0" y="1555.0" width="74.0" height="40.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.book.__main__ — 81 lines</title></rect>
|
||||
<rect x="784.0" y="1562.0" width="74.0" height="31.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.__main__.main" data-kind="function" class="blk"><title>main — function, 62 lines</title></rect>
|
||||
<rect x="28.0" y="1768.5" width="74.0" height="118.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors.python.collect — 236 lines</title></rect>
|
||||
<rect x="28.0" y="1785.0" width="74.0" height="5.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.extractors.python.collect.Definition" data-kind="class" class="blk"><title>Definition — class, 10 lines</title></rect>
|
||||
<rect x="28.0" y="1791.5" width="74.0" height="6.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.extractors.python.collect.Module" data-kind="class" class="blk"><title>Module — class, 12 lines</title></rect>
|
||||
<rect x="28.0" y="1798.5" width="74.0" height="33.5" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.extractors.python.collect._Collector" data-kind="class" class="blk"><title>_Collector — class, 67 lines</title></rect>
|
||||
<rect x="35.0" y="1800.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.extractors.python.collect._Collector.__init__" data-kind="function" class="blk"><title>__init__ — function, 3 lines</title></rect>
|
||||
<rect x="35.0" y="1803.0" width="60.0" height="8.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.extractors.python.collect._Collector._define" data-kind="function" class="blk"><title>_define — function, 17 lines</title></rect>
|
||||
<rect x="35.0" y="1812.0" width="60.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.extractors.python.collect._Collector.visit_ClassDef" data-kind="function" class="blk"><title>visit_ClassDef — function, 5 lines</title></rect>
|
||||
<rect x="35.0" y="1815.0" width="60.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.extractors.python.collect._Collector.visit_FunctionDef" data-kind="function" class="blk"><title>visit_FunctionDef — function, 5 lines</title></rect>
|
||||
<rect x="35.0" y="1820.5" width="60.0" height="4.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.extractors.python.collect._Collector.visit_Import" data-kind="function" class="blk"><title>visit_Import — function, 8 lines</title></rect>
|
||||
<rect x="35.0" y="1825.0" width="60.0" height="7.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.extractors.python.collect._Collector.visit_ImportFrom" data-kind="function" class="blk"><title>visit_ImportFrom — function, 14 lines</title></rect>
|
||||
<rect x="28.0" y="1833.0" width="74.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.collect._first_line" data-kind="function" class="blk"><title>_first_line — function, 5 lines</title></rect>
|
||||
<rect x="28.0" y="1836.5" width="74.0" height="7.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.collect._name_of" data-kind="function" class="blk"><title>_name_of — function, 15 lines</title></rect>
|
||||
<rect x="28.0" y="1845.0" width="74.0" height="8.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.collect._resolve_relative" data-kind="function" class="blk"><title>_resolve_relative — function, 16 lines</title></rect>
|
||||
<rect x="28.0" y="1854.0" width="74.0" height="13.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.collect.module_name" data-kind="function" class="blk"><title>module_name — function, 26 lines</title></rect>
|
||||
<rect x="28.0" y="1868.0" width="74.0" height="10.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.collect.collect_file" data-kind="function" class="blk"><title>collect_file — function, 21 lines</title></rect>
|
||||
<rect x="28.0" y="1879.5" width="74.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.collect.collect" data-kind="function" class="blk"><title>collect — function, 13 lines</title></rect>
|
||||
<rect x="110.0" y="1768.5" width="74.0" height="92.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors.python.resolve — 184 lines</title></rect>
|
||||
<rect x="110.0" y="1782.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.resolve._id_for" data-kind="function" class="blk"><title>_id_for — function, 2 lines</title></rect>
|
||||
<rect x="110.0" y="1784.5" width="74.0" height="16.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.resolve._resolve" data-kind="function" class="blk"><title>_resolve — function, 32 lines</title></rect>
|
||||
<rect x="110.0" y="1801.5" width="74.0" height="8.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.resolve.larder_of" data-kind="function" class="blk"><title>larder_of — function, 17 lines</title></rect>
|
||||
<rect x="110.0" y="1811.0" width="74.0" height="49.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.resolve.to_ir" data-kind="function" class="blk"><title>to_ir — function, 98 lines</title></rect>
|
||||
<rect x="117.0" y="1840.5" width="60.0" height="4.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.extractors.python.resolve.to_ir._point_at" data-kind="function" class="blk"><title>_point_at — function, 9 lines</title></rect>
|
||||
<rect x="192.0" y="1768.5" width="74.0" height="19.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors.python.__main__ — 38 lines</title></rect>
|
||||
<rect x="192.0" y="1773.5" width="74.0" height="11.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.__main__.main" data-kind="function" class="blk"><title>main — function, 23 lines</title></rect>
|
||||
<rect x="292.0" y="1768.5" width="74.0" height="156.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.ir.validate — 313 lines</title></rect>
|
||||
<rect x="292.0" y="1790.0" width="74.0" height="2.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.ir.validate.IRError" data-kind="class" class="blk"><title>IRError — class, 2 lines</title></rect>
|
||||
<rect x="292.0" y="1792.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ir.validate._schema" data-kind="function" class="blk"><title>_schema — function, 2 lines</title></rect>
|
||||
<rect x="292.0" y="1794.0" width="74.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ir.validate._props" data-kind="function" class="blk"><title>_props — function, 5 lines</title></rect>
|
||||
<rect x="292.0" y="1797.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ir.validate._fields" data-kind="function" class="blk"><title>_fields — function, 4 lines</title></rect>
|
||||
<rect x="292.0" y="1800.5" width="74.0" height="54.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ir.validate.check" data-kind="function" class="blk"><title>check — function, 108 lines</title></rect>
|
||||
<rect x="292.0" y="1862.0" width="74.0" height="29.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ir.validate._check_larder" data-kind="function" class="blk"><title>_check_larder — function, 58 lines</title></rect>
|
||||
<rect x="292.0" y="1892.0" width="74.0" height="3.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ir.validate.validate" data-kind="function" class="blk"><title>validate — function, 6 lines</title></rect>
|
||||
<rect x="292.0" y="1896.0" width="74.0" height="11.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ir.validate.check_model_matches_schema" data-kind="function" class="blk"><title>check_model_matches_schema — function, 23 lines</title></rect>
|
||||
<rect x="292.0" y="1908.5" width="74.0" height="16.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ir.validate.main" data-kind="function" class="blk"><title>main — function, 32 lines</title></rect>
|
||||
<rect x="374.0" y="1768.5" width="74.0" height="82.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.ir.model — 165 lines</title></rect>
|
||||
<rect x="374.0" y="1785.0" width="74.0" height="19.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.ir.model.Meta" data-kind="class" class="blk"><title>Meta — class, 38 lines</title></rect>
|
||||
<rect x="381.0" y="1795.0" width="60.0" height="9.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ir.model.Meta.to_dict" data-kind="function" class="blk"><title>to_dict — function, 18 lines</title></rect>
|
||||
<rect x="374.0" y="1805.5" width="74.0" height="10.5" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.ir.model.Node" data-kind="class" class="blk"><title>Node — class, 21 lines</title></rect>
|
||||
<rect x="381.0" y="1810.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ir.model.Node.__post_init__" data-kind="function" class="blk"><title>__post_init__ — function, 3 lines</title></rect>
|
||||
<rect x="381.0" y="1812.0" width="60.0" height="4.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ir.model.Node.to_dict" data-kind="function" class="blk"><title>to_dict — function, 8 lines</title></rect>
|
||||
<rect x="374.0" y="1817.5" width="74.0" height="7.5" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.ir.model.Edge" data-kind="class" class="blk"><title>Edge — class, 15 lines</title></rect>
|
||||
<rect x="381.0" y="1821.5" width="60.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ir.model.Edge.to_dict" data-kind="function" class="blk"><title>to_dict — function, 7 lines</title></rect>
|
||||
<rect x="374.0" y="1826.5" width="74.0" height="24.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.ir.model.Graph" data-kind="class" class="blk"><title>Graph — class, 48 lines</title></rect>
|
||||
<rect x="381.0" y="1831.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ir.model.Graph.node" data-kind="function" class="blk"><title>node — function, 4 lines</title></rect>
|
||||
<rect x="381.0" y="1833.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ir.model.Graph.edge" data-kind="function" class="blk"><title>edge — function, 4 lines</title></rect>
|
||||
<rect x="381.0" y="1836.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ir.model.Graph.has" data-kind="function" class="blk"><title>has — function, 2 lines</title></rect>
|
||||
<rect x="381.0" y="1838.5" width="60.0" height="8.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ir.model.Graph.to_dict" data-kind="function" class="blk"><title>to_dict — function, 16 lines</title></rect>
|
||||
<rect x="381.0" y="1847.5" width="60.0" height="3.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ir.model.Graph.from_dict" data-kind="function" class="blk"><title>from_dict — function, 6 lines</title></rect>
|
||||
<rect x="456.0" y="1768.5" width="74.0" height="14.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.ir.__main__ — 9 lines</title></rect>
|
||||
<rect x="556.0" y="1768.5" width="74.0" height="242.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.ops.filter — 485 lines</title></rect>
|
||||
<rect x="556.0" y="1786.5" width="74.0" height="28.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter._rebuild" data-kind="function" class="blk"><title>_rebuild — function, 57 lines</title></rect>
|
||||
<rect x="563.0" y="1791.0" width="60.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ops.filter._rebuild.surviving_parent" data-kind="function" class="blk"><title>surviving_parent — function, 5 lines</title></rect>
|
||||
<rect x="563.0" y="1798.0" width="60.0" height="3.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ops.filter._rebuild.lift" data-kind="function" class="blk"><title>lift — function, 6 lines</title></rect>
|
||||
<rect x="556.0" y="1816.0" width="74.0" height="7.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.drop_kinds" data-kind="function" class="blk"><title>drop_kinds — function, 14 lines</title></rect>
|
||||
<rect x="556.0" y="1824.0" width="74.0" height="7.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.only_kinds" data-kind="function" class="blk"><title>only_kinds — function, 14 lines</title></rect>
|
||||
<rect x="556.0" y="1832.0" width="74.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.drop_stdlib" data-kind="function" class="blk"><title>drop_stdlib — function, 13 lines</title></rect>
|
||||
<rect x="556.0" y="1839.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.drop_external" data-kind="function" class="blk"><title>drop_external — function, 3 lines</title></rect>
|
||||
<rect x="556.0" y="1842.0" width="74.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.subtree" data-kind="function" class="blk"><title>subtree — function, 13 lines</title></rect>
|
||||
<rect x="556.0" y="1849.5" width="74.0" height="22.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.neighbourhood" data-kind="function" class="blk"><title>neighbourhood — function, 45 lines</title></rect>
|
||||
<rect x="556.0" y="1873.0" width="74.0" height="9.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.collapse_to_depth" data-kind="function" class="blk"><title>collapse_to_depth — function, 18 lines</title></rect>
|
||||
<rect x="563.0" y="1878.0" width="60.0" height="3.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ops.filter.collapse_to_depth.level" data-kind="function" class="blk"><title>level — function, 6 lines</title></rect>
|
||||
<rect x="556.0" y="1883.0" width="74.0" height="7.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.drop_builtins" data-kind="function" class="blk"><title>drop_builtins — function, 14 lines</title></rect>
|
||||
<rect x="556.0" y="1891.0" width="74.0" height="17.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.overview" data-kind="function" class="blk"><title>overview — function, 35 lines</title></rect>
|
||||
<rect x="556.0" y="1909.5" width="74.0" height="36.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.shape" data-kind="function" class="blk"><title>shape — function, 72 lines</title></rect>
|
||||
<rect x="563.0" y="1933.5" width="60.0" height="4.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ops.filter.shape.rank_of" data-kind="function" class="blk"><title>rank_of — function, 9 lines</title></rect>
|
||||
<rect x="556.0" y="1946.5" width="74.0" height="12.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.split" data-kind="function" class="blk"><title>split — function, 24 lines</title></rect>
|
||||
<rect x="556.0" y="1959.5" width="74.0" height="51.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.classify" data-kind="function" class="blk"><title>classify — function, 102 lines</title></rect>
|
||||
<rect x="638.0" y="1768.5" width="74.0" height="51.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.ops.__main__ — 102 lines</title></rect>
|
||||
<rect x="638.0" y="1775.0" width="74.0" height="42.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.__main__.main" data-kind="function" class="blk"><title>main — function, 84 lines</title></rect>
|
||||
<rect x="738.0" y="1768.5" width="74.0" height="111.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.style.extract — 222 lines</title></rect>
|
||||
<rect x="738.0" y="1799.0" width="74.0" height="8.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.extract._values_from" data-kind="function" class="blk"><title>_values_from — function, 17 lines</title></rect>
|
||||
<rect x="738.0" y="1808.5" width="74.0" height="22.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.extract._normalise" data-kind="function" class="blk"><title>_normalise — function, 45 lines</title></rect>
|
||||
<rect x="738.0" y="1832.0" width="74.0" height="12.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.extract._svg_files" data-kind="function" class="blk"><title>_svg_files — function, 25 lines</title></rect>
|
||||
<rect x="738.0" y="1845.5" width="74.0" height="21.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.extract.harvest" data-kind="function" class="blk"><title>harvest — function, 43 lines</title></rect>
|
||||
<rect x="738.0" y="1868.0" width="74.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.extract.write" data-kind="function" class="blk"><title>write — function, 7 lines</title></rect>
|
||||
<rect x="738.0" y="1872.5" width="74.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.extract.summarise" data-kind="function" class="blk"><title>summarise — function, 13 lines</title></rect>
|
||||
<rect x="28.0" y="2049.0" width="74.0" height="105.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.style.tokens — 211 lines</title></rect>
|
||||
<rect x="28.0" y="2077.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.tokens._top" data-kind="function" class="blk"><title>_top — function, 2 lines</title></rect>
|
||||
<rect x="28.0" y="2079.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.tokens._mode" data-kind="function" class="blk"><title>_mode — function, 3 lines</title></rect>
|
||||
<rect x="28.0" y="2081.5" width="74.0" height="3.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.tokens._luminance" data-kind="function" class="blk"><title>_luminance — function, 6 lines</title></rect>
|
||||
<rect x="28.0" y="2085.5" width="74.0" height="50.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.tokens.derive" data-kind="function" class="blk"><title>derive — function, 101 lines</title></rect>
|
||||
<rect x="35.0" y="2107.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.tokens.derive.accent" data-kind="function" class="blk"><title>accent — function, 2 lines</title></rect>
|
||||
<rect x="28.0" y="2137.0" width="74.0" height="7.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.tokens.geometry" data-kind="function" class="blk"><title>geometry — function, 14 lines</title></rect>
|
||||
<rect x="28.0" y="2145.0" width="74.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.tokens.write" data-kind="function" class="blk"><title>write — function, 7 lines</title></rect>
|
||||
<rect x="28.0" y="2149.5" width="74.0" height="4.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.tokens.from_folder" data-kind="function" class="blk"><title>from_folder — function, 9 lines</title></rect>
|
||||
<rect x="128.0" y="2049.0" width="74.0" height="14.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen — 2 lines</title></rect>
|
||||
<rect x="228.0" y="2049.0" width="74.0" height="75.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.lab.pg_probe — 150 lines</title></rect>
|
||||
<rect x="228.0" y="2084.5" width="74.0" height="15.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.lab.pg_probe.probe" data-kind="function" class="blk"><title>probe — function, 30 lines</title></rect>
|
||||
<rect x="228.0" y="2106.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.lab.pg_probe._simplify" data-kind="function" class="blk"><title>_simplify — function, 3 lines</title></rect>
|
||||
<rect x="228.0" y="2109.0" width="74.0" height="12.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.lab.pg_probe.main" data-kind="function" class="blk"><title>main — function, 25 lines</title></rect>
|
||||
<rect x="328.0" y="2049.0" width="74.0" height="132.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.notebook.spec — 264 lines</title></rect>
|
||||
<rect x="328.0" y="2077.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.notebook.spec._step" data-kind="function" class="blk"><title>_step — function, 4 lines</title></rect>
|
||||
<rect x="328.0" y="2080.0" width="74.0" height="54.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.notebook.spec.from_ir" data-kind="function" class="blk"><title>from_ir — function, 108 lines</title></rect>
|
||||
<rect x="335.0" y="2087.0" width="60.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.notebook.spec.from_ir._order" data-kind="function" class="blk"><title>_order — function, 5 lines</title></rect>
|
||||
<rect x="328.0" y="2135.0" width="74.0" height="10.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.notebook.spec.scaffold" data-kind="function" class="blk"><title>scaffold — function, 20 lines</title></rect>
|
||||
<rect x="328.0" y="2146.0" width="74.0" height="29.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.notebook.spec.merge" data-kind="function" class="blk"><title>merge — function, 58 lines</title></rect>
|
||||
<rect x="328.0" y="2176.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.notebook.spec.load" data-kind="function" class="blk"><title>load — function, 2 lines</title></rect>
|
||||
<rect x="328.0" y="2178.0" width="74.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.notebook.spec.dump" data-kind="function" class="blk"><title>dump — function, 5 lines</title></rect>
|
||||
<text x="28" y="40" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.emitters</text>
|
||||
<text x="28" y="325" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.emitters</text>
|
||||
<text x="538" y="325" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen</text>
|
||||
<text x="28" y="1370" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen</text>
|
||||
<text x="538" y="1370" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.extractors</text>
|
||||
<text x="28" y="1549" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.extractors</text>
|
||||
<text x="538" y="1549" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.book</text>
|
||||
<text x="28" y="1762" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.extractors.python</text>
|
||||
<text x="292" y="1762" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.ir</text>
|
||||
<text x="556" y="1762" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.ops</text>
|
||||
<text x="738" y="1762" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.style</text>
|
||||
<text x="28" y="2043" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.style</text>
|
||||
<text x="128" y="2043" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">(root)</text>
|
||||
<text x="228" y="2043" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.lab</text>
|
||||
<text x="328" y="2043" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.notebook</text>
|
||||
<text x="28" y="302" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">site</text>
|
||||
<text x="110" y="213" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">explore</text>
|
||||
<text x="192" y="201" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">dot</text>
|
||||
<text x="274" y="194" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">notebook</text>
|
||||
<text x="356" y="194" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">minimap</text>
|
||||
<text x="438" y="185" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">erd</text>
|
||||
<text x="520" y="137" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">index</text>
|
||||
<text x="602" y="98" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">cli_dot</text>
|
||||
<text x="684" y="95" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">auto</text>
|
||||
<text x="766" y="92" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">cli_noteboo</text>
|
||||
<text x="28" y="377" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">cli_site</text>
|
||||
<text x="110" y="366" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">cli_erd</text>
|
||||
<text x="192" y="366" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">cli_minimap</text>
|
||||
<text x="274" y="364" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">cli_explore</text>
|
||||
<text x="356" y="362" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">cli_index</text>
|
||||
<text x="438" y="358" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">__main__</text>
|
||||
<text x="538" y="1347" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">selftest</text>
|
||||
<text x="620" y="498" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">book</text>
|
||||
<text x="702" y="437" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">style</text>
|
||||
<text x="784" y="394" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">reference</text>
|
||||
<text x="28" y="1399" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">ops</text>
|
||||
<text x="110" y="1399" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">notebook</text>
|
||||
<text x="192" y="1399" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">emitters</text>
|
||||
<text x="274" y="1399" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">lab</text>
|
||||
<text x="356" y="1399" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">ir</text>
|
||||
<text x="438" y="1399" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">extractors</text>
|
||||
<text x="538" y="1526" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">code</text>
|
||||
<text x="620" y="1520" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">usage</text>
|
||||
<text x="702" y="1480" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">openapi</text>
|
||||
<text x="784" y="1466" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">db</text>
|
||||
<text x="28" y="1584" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">code_main</text>
|
||||
<text x="110" y="1582" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">python</text>
|
||||
<text x="192" y="1580" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">usage_main</text>
|
||||
<text x="274" y="1580" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">db_main</text>
|
||||
<text x="356" y="1579" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">openapi_mai</text>
|
||||
<text x="438" y="1578" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">__main__</text>
|
||||
<text x="538" y="1740" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">build</text>
|
||||
<text x="620" y="1717" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">checks</text>
|
||||
<text x="702" y="1662" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">larder</text>
|
||||
<text x="784" y="1604" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">__main__</text>
|
||||
<text x="28" y="1896" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">collect</text>
|
||||
<text x="110" y="1870" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">resolve</text>
|
||||
<text x="192" y="1796" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">__main__</text>
|
||||
<text x="292" y="1934" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">validate</text>
|
||||
<text x="374" y="1860" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">model</text>
|
||||
<text x="456" y="1792" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">__main__</text>
|
||||
<text x="556" y="2020" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">filter</text>
|
||||
<text x="638" y="1828" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">__main__</text>
|
||||
<text x="738" y="1888" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">extract</text>
|
||||
<text x="28" y="2164" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">tokens</text>
|
||||
<text x="128" y="2072" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">docgen</text>
|
||||
<text x="228" y="2133" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">pg_probe</text>
|
||||
<text x="328" y="2190" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">spec</text>
|
||||
<rect x="28" y="2230.0" width="9" height="9" rx="2" fill="#1a1a1a"/>
|
||||
<text x="41" y="2238.0" font-family="Helvetica,sans-Serif" font-size="9" fill="#666666">module</text>
|
||||
<rect x="86" y="2230.0" width="9" height="9" rx="2" fill="#1d4ed8"/>
|
||||
<text x="99" y="2238.0" font-family="Helvetica,sans-Serif" font-size="9" fill="#666666">class</text>
|
||||
<rect x="138" y="2230.0" width="9" height="9" rx="2" fill="#d4a574"/>
|
||||
<text x="151" y="2238.0" font-family="Helvetica,sans-Serif" font-size="9" fill="#666666">interface</text>
|
||||
<rect x="214" y="2230.0" width="9" height="9" rx="2" fill="#15803d"/>
|
||||
<text x="227" y="2238.0" font-family="Helvetica,sans-Serif" font-size="9" fill="#666666">function</text>
|
||||
<text x="858" y="2238.0" text-anchor="end" font-family="Helvetica,sans-Serif" font-size="9" fill="#666666">53 files · 9,752 lines · 1px ≈ 2.0 lines</text>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="886pt" height="2238pt" viewBox="0 0 886 2238">
|
||||
<rect width="886" height="2238" fill="#0a0a0a"/>
|
||||
<rect x="28.0" y="46.0" width="74.0" height="1164.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.selftest — 2328 lines</title></rect>
|
||||
<rect x="28.0" y="94.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.selftest.own_py_files" data-kind="function" class="blk"><title>own_py_files — function, 3 lines</title></rect>
|
||||
<rect x="28.0" y="96.0" width="74.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.selftest.check" data-kind="function" class="blk"><title>check — function, 5 lines</title></rect>
|
||||
<rect x="28.0" y="99.5" width="74.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.selftest._err" data-kind="function" class="blk"><title>_err — function, 7 lines</title></rect>
|
||||
<rect x="28.0" y="104.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.selftest.skip" data-kind="function" class="blk"><title>skip — function, 3 lines</title></rect>
|
||||
<rect x="28.0" y="106.5" width="74.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.selftest.build_tree" data-kind="function" class="blk"><title>build_tree — function, 5 lines</title></rect>
|
||||
<rect x="28.0" y="236.0" width="74.0" height="97.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.selftest._harvesting" data-kind="function" class="blk"><title>_harvesting — function, 194 lines</title></rect>
|
||||
<rect x="28.0" y="578.5" width="74.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.selftest._entry" data-kind="function" class="blk"><title>_entry — function, 7 lines</title></rect>
|
||||
<rect x="28.0" y="831.5" width="74.0" height="139.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.selftest._books" data-kind="function" class="blk"><title>_books — function, 279 lines</title></rect>
|
||||
<rect x="28.0" y="976.0" width="74.0" height="76.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.selftest._standalone" data-kind="function" class="blk"><title>_standalone — function, 153 lines</title></rect>
|
||||
<rect x="28.0" y="1057.5" width="74.0" height="44.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.selftest._layout" data-kind="function" class="blk"><title>_layout — function, 89 lines</title></rect>
|
||||
<rect x="28.0" y="1106.5" width="74.0" height="97.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.selftest._runfiles" data-kind="function" class="blk"><title>_runfiles — function, 195 lines</title></rect>
|
||||
<rect x="35.0" y="1112.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.selftest._runfiles.write" data-kind="function" class="blk"><title>write — function, 4 lines</title></rect>
|
||||
<rect x="35.0" y="1115.0" width="60.0" height="3.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.selftest._runfiles.problems" data-kind="function" class="blk"><title>problems — function, 6 lines</title></rect>
|
||||
<rect x="110.0" y="46.0" width="74.0" height="158.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.book — 316 lines</title></rect>
|
||||
<rect x="110.0" y="75.0" width="74.0" height="10.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.book.Step" data-kind="class" class="blk"><title>Step — class, 20 lines</title></rect>
|
||||
<rect x="117.0" y="80.0" width="60.0" height="5.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.Step.to_dict" data-kind="function" class="blk"><title>to_dict — function, 10 lines</title></rect>
|
||||
<rect x="110.0" y="96.5" width="74.0" height="15.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book._unit_counts" data-kind="function" class="blk"><title>_unit_counts — function, 30 lines</title></rect>
|
||||
<rect x="110.0" y="112.5" width="74.0" height="89.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.book.Book" data-kind="class" class="blk"><title>Book — class, 178 lines</title></rect>
|
||||
<rect x="117.0" y="114.0" width="60.0" height="8.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.Book.__init__" data-kind="function" class="blk"><title>__init__ — function, 17 lines</title></rect>
|
||||
<rect x="117.0" y="124.0" width="60.0" height="7.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.Book.step" data-kind="function" class="blk"><title>step — function, 14 lines</title></rect>
|
||||
<rect x="117.0" y="132.5" width="60.0" height="10.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.Book.measure" data-kind="function" class="blk"><title>measure — function, 21 lines</title></rect>
|
||||
<rect x="117.0" y="143.5" width="60.0" height="31.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.Book.compare" data-kind="function" class="blk"><title>compare — function, 62 lines</title></rect>
|
||||
<rect x="117.0" y="176.0" width="60.0" height="13.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.Book.close" data-kind="function" class="blk"><title>close — function, 27 lines</title></rect>
|
||||
<rect x="117.0" y="190.0" width="60.0" height="8.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.Book.to_dict" data-kind="function" class="blk"><title>to_dict — function, 17 lines</title></rect>
|
||||
<rect x="117.0" y="199.0" width="60.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.Book.write" data-kind="function" class="blk"><title>write — function, 5 lines</title></rect>
|
||||
<rect x="110.0" y="202.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book._tree_bytes" data-kind="function" class="blk"><title>_tree_bytes — function, 2 lines</title></rect>
|
||||
<rect x="192.0" y="46.0" width="74.0" height="97.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.style — 194 lines</title></rect>
|
||||
<rect x="192.0" y="68.5" width="74.0" height="2.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.style.StyleError" data-kind="class" class="blk"><title>StyleError — class, 2 lines</title></rect>
|
||||
<rect x="192.0" y="70.5" width="74.0" height="66.5" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.style.Style" data-kind="class" class="blk"><title>Style — class, 133 lines</title></rect>
|
||||
<rect x="199.0" y="72.0" width="60.0" height="8.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.__init__" data-kind="function" class="blk"><title>__init__ — function, 17 lines</title></rect>
|
||||
<rect x="199.0" y="82.5" width="60.0" height="6.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.load" data-kind="function" class="blk"><title>load — function, 12 lines</title></rect>
|
||||
<rect x="199.0" y="89.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.available" data-kind="function" class="blk"><title>available — function, 2 lines</title></rect>
|
||||
<rect x="199.0" y="91.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.themes" data-kind="function" class="blk"><title>themes — function, 2 lines</title></rect>
|
||||
<rect x="199.0" y="93.5" width="60.0" height="16.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.validate" data-kind="function" class="blk"><title>validate — function, 32 lines</title></rect>
|
||||
<rect x="199.0" y="111.0" width="60.0" height="6.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style._resolve" data-kind="function" class="blk"><title>_resolve — function, 12 lines</title></rect>
|
||||
<rect x="199.0" y="117.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style._lookup" data-kind="function" class="blk"><title>_lookup — function, 3 lines</title></rect>
|
||||
<rect x="199.0" y="119.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.node" data-kind="function" class="blk"><title>node — function, 2 lines</title></rect>
|
||||
<rect x="199.0" y="121.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.group" data-kind="function" class="blk"><title>group — function, 2 lines</title></rect>
|
||||
<rect x="199.0" y="122.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.edge" data-kind="function" class="blk"><title>edge — function, 2 lines</title></rect>
|
||||
<rect x="199.0" y="124.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.graph" data-kind="function" class="blk"><title>graph — function, 2 lines</title></rect>
|
||||
<rect x="199.0" y="125.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.geom" data-kind="function" class="blk"><title>geom — function, 2 lines</title></rect>
|
||||
<rect x="199.0" y="127.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.slot" data-kind="function" class="blk"><title>slot — function, 2 lines</title></rect>
|
||||
<rect x="199.0" y="128.5" width="60.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.domain_slot" data-kind="function" class="blk"><title>domain_slot — function, 13 lines</title></rect>
|
||||
<rect x="199.0" y="135.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.Style.limits" data-kind="function" class="blk"><title>limits — function, 3 lines</title></rect>
|
||||
<rect x="192.0" y="138.0" width="74.0" height="4.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.harvest" data-kind="function" class="blk"><title>harvest — function, 9 lines</title></rect>
|
||||
<rect x="274.0" y="46.0" width="74.0" height="54.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.reference — 108 lines</title></rect>
|
||||
<rect x="274.0" y="69.0" width="74.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.reference._candidates" data-kind="function" class="blk"><title>_candidates — function, 7 lines</title></rect>
|
||||
<rect x="274.0" y="73.5" width="74.0" height="4.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.reference.root" data-kind="function" class="blk"><title>root — function, 9 lines</title></rect>
|
||||
<rect x="274.0" y="79.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.reference.station_tools" data-kind="function" class="blk"><title>station_tools — function, 4 lines</title></rect>
|
||||
<rect x="274.0" y="82.0" width="74.0" height="5.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.reference.describe" data-kind="function" class="blk"><title>describe — function, 10 lines</title></rect>
|
||||
<rect x="274.0" y="88.0" width="74.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.reference.on_path" data-kind="function" class="blk"><title>on_path — function, 13 lines</title></rect>
|
||||
<rect x="274.0" y="95.5" width="74.0" height="4.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.reference.missing" data-kind="function" class="blk"><title>missing — function, 8 lines</title></rect>
|
||||
<rect x="356.0" y="46.0" width="74.0" height="38.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.cli — 76 lines</title></rect>
|
||||
<rect x="356.0" y="68.5" width="74.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.usage" data-kind="function" class="blk"><title>usage — function, 7 lines</title></rect>
|
||||
<rect x="356.0" y="73.0" width="74.0" height="10.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.main" data-kind="function" class="blk"><title>main — function, 21 lines</title></rect>
|
||||
<rect x="438.0" y="46.0" width="74.0" height="14.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.ops — 28 lines</title></rect>
|
||||
<rect x="520.0" y="46.0" width="74.0" height="14.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.notebook — 15 lines</title></rect>
|
||||
<rect x="602.0" y="46.0" width="74.0" height="14.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters — 12 lines</title></rect>
|
||||
<rect x="684.0" y="46.0" width="74.0" height="14.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.lab — 11 lines</title></rect>
|
||||
<rect x="766.0" y="46.0" width="74.0" height="14.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.__main__ — 9 lines</title></rect>
|
||||
<rect x="28.0" y="1248.0" width="74.0" height="14.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.ir — 7 lines</title></rect>
|
||||
<rect x="110.0" y="1248.0" width="74.0" height="14.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors — 2 lines</title></rect>
|
||||
<rect x="210.0" y="1248.0" width="74.0" height="126.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.cli.emit — 253 lines</title></rect>
|
||||
<rect x="210.0" y="1260.0" width="74.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.emit._parser" data-kind="function" class="blk"><title>_parser — function, 7 lines</title></rect>
|
||||
<rect x="210.0" y="1264.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.emit._size" data-kind="function" class="blk"><title>_size — function, 3 lines</title></rect>
|
||||
<rect x="210.0" y="1267.0" width="74.0" height="8.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.emit.auto" data-kind="function" class="blk"><title>auto — function, 16 lines</title></rect>
|
||||
<rect x="210.0" y="1276.0" width="74.0" height="19.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.emit.dot" data-kind="function" class="blk"><title>dot — function, 38 lines</title></rect>
|
||||
<rect x="210.0" y="1296.0" width="74.0" height="5.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.emit.erd" data-kind="function" class="blk"><title>erd — function, 11 lines</title></rect>
|
||||
<rect x="210.0" y="1302.5" width="74.0" height="7.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.emit.index" data-kind="function" class="blk"><title>index — function, 14 lines</title></rect>
|
||||
<rect x="210.0" y="1310.5" width="74.0" height="7.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.emit.minimap" data-kind="function" class="blk"><title>minimap — function, 14 lines</title></rect>
|
||||
<rect x="210.0" y="1318.5" width="74.0" height="20.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.emit.notebook" data-kind="function" class="blk"><title>notebook — function, 41 lines</title></rect>
|
||||
<rect x="210.0" y="1340.0" width="74.0" height="15.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.emit.site" data-kind="function" class="blk"><title>site — function, 31 lines</title></rect>
|
||||
<rect x="210.0" y="1356.5" width="74.0" height="11.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.emit.explore" data-kind="function" class="blk"><title>explore — function, 22 lines</title></rect>
|
||||
<rect x="210.0" y="1370.5" width="74.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.emit.main" data-kind="function" class="blk"><title>main — function, 7 lines</title></rect>
|
||||
<rect x="292.0" y="1248.0" width="74.0" height="59.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.cli.extract — 119 lines</title></rect>
|
||||
<rect x="292.0" y="1257.5" width="74.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.extract._parser" data-kind="function" class="blk"><title>_parser — function, 5 lines</title></rect>
|
||||
<rect x="292.0" y="1261.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.extract._counts" data-kind="function" class="blk"><title>_counts — function, 3 lines</title></rect>
|
||||
<rect x="292.0" y="1263.5" width="74.0" height="7.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.extract.python" data-kind="function" class="blk"><title>python — function, 15 lines</title></rect>
|
||||
<rect x="292.0" y="1272.0" width="74.0" height="7.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.extract.code" data-kind="function" class="blk"><title>code — function, 14 lines</title></rect>
|
||||
<rect x="292.0" y="1280.0" width="74.0" height="5.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.extract.db" data-kind="function" class="blk"><title>db — function, 11 lines</title></rect>
|
||||
<rect x="292.0" y="1286.5" width="74.0" height="6.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.extract.openapi" data-kind="function" class="blk"><title>openapi — function, 12 lines</title></rect>
|
||||
<rect x="292.0" y="1293.5" width="74.0" height="7.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.extract.usage" data-kind="function" class="blk"><title>usage — function, 15 lines</title></rect>
|
||||
<rect x="292.0" y="1303.5" width="74.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.extract.main" data-kind="function" class="blk"><title>main — function, 7 lines</title></rect>
|
||||
<rect x="374.0" y="1248.0" width="74.0" height="45.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.cli.view — 90 lines</title></rect>
|
||||
<rect x="374.0" y="1255.0" width="74.0" height="37.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.view.main" data-kind="function" class="blk"><title>main — function, 75 lines</title></rect>
|
||||
<rect x="456.0" y="1248.0" width="74.0" height="40.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.cli.common — 80 lines</title></rect>
|
||||
<rect x="456.0" y="1258.0" width="74.0" height="2.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.cli.common.Abort" data-kind="class" class="blk"><title>Abort — class, 2 lines</title></rect>
|
||||
<rect x="456.0" y="1260.0" width="74.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.common.read_json" data-kind="function" class="blk"><title>read_json — function, 5 lines</title></rect>
|
||||
<rect x="456.0" y="1263.5" width="74.0" height="5.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.common.read_ir" data-kind="function" class="blk"><title>read_ir — function, 11 lines</title></rect>
|
||||
<rect x="456.0" y="1270.0" width="74.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.common.load_style" data-kind="function" class="blk"><title>load_style — function, 7 lines</title></rect>
|
||||
<rect x="456.0" y="1274.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.common.style_args" data-kind="function" class="blk"><title>style_args — function, 3 lines</title></rect>
|
||||
<rect x="456.0" y="1277.0" width="74.0" height="8.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.common.emit" data-kind="function" class="blk"><title>emit — function, 16 lines</title></rect>
|
||||
<rect x="456.0" y="1286.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.common.dump_ir" data-kind="function" class="blk"><title>dump_ir — function, 3 lines</title></rect>
|
||||
<rect x="538.0" y="1248.0" width="74.0" height="40.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.cli.run — 80 lines</title></rect>
|
||||
<rect x="538.0" y="1258.0" width="74.0" height="29.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.run.main" data-kind="function" class="blk"><title>main — function, 59 lines</title></rect>
|
||||
<rect x="620.0" y="1248.0" width="74.0" height="37.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.cli.book — 74 lines</title></rect>
|
||||
<rect x="620.0" y="1258.5" width="74.0" height="26.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.book.main" data-kind="function" class="blk"><title>main — function, 52 lines</title></rect>
|
||||
<rect x="702.0" y="1248.0" width="74.0" height="25.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.cli.check — 51 lines</title></rect>
|
||||
<rect x="702.0" y="1258.0" width="74.0" height="15.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.check.main" data-kind="function" class="blk"><title>main — function, 30 lines</title></rect>
|
||||
<rect x="784.0" y="1248.0" width="74.0" height="16.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.cli.validate — 33 lines</title></rect>
|
||||
<rect x="784.0" y="1255.0" width="74.0" height="9.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.cli.validate.main" data-kind="function" class="blk"><title>main — function, 18 lines</title></rect>
|
||||
<rect x="28.0" y="1412.5" width="74.0" height="247.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.site — 494 lines</title></rect>
|
||||
<rect x="28.0" y="1548.5" width="74.0" height="27.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.site._ledger" data-kind="function" class="blk"><title>_ledger — function, 54 lines</title></rect>
|
||||
<rect x="28.0" y="1576.5" width="74.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.site._slots" data-kind="function" class="blk"><title>_slots — function, 13 lines</title></rect>
|
||||
<rect x="28.0" y="1584.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.site._fill" data-kind="function" class="blk"><title>_fill — function, 4 lines</title></rect>
|
||||
<rect x="28.0" y="1587.0" width="74.0" height="8.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.site._sidebar" data-kind="function" class="blk"><title>_sidebar — function, 17 lines</title></rect>
|
||||
<rect x="28.0" y="1596.5" width="74.0" height="7.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.site._sections" data-kind="function" class="blk"><title>_sections — function, 15 lines</title></rect>
|
||||
<rect x="28.0" y="1605.0" width="74.0" height="48.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.site.emit" data-kind="function" class="blk"><title>emit — function, 96 lines</title></rect>
|
||||
<rect x="28.0" y="1654.0" width="74.0" height="5.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.site.write" data-kind="function" class="blk"><title>write — function, 10 lines</title></rect>
|
||||
<rect x="110.0" y="1412.5" width="74.0" height="158.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.explore — 316 lines</title></rect>
|
||||
<rect x="110.0" y="1432.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.explore._is_schema" data-kind="function" class="blk"><title>_is_schema — function, 4 lines</title></rect>
|
||||
<rect x="110.0" y="1435.0" width="74.0" height="24.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.explore._neighbourhood_svgs" data-kind="function" class="blk"><title>_neighbourhood_svgs — function, 48 lines</title></rect>
|
||||
<rect x="117.0" y="1441.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.emitters.explore._neighbourhood_svgs.render_one" data-kind="function" class="blk"><title>render_one — function, 2 lines</title></rect>
|
||||
<rect x="117.0" y="1445.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.emitters.explore._neighbourhood_svgs.render_one#L66" data-kind="function" class="blk"><title>render_one — function, 2 lines</title></rect>
|
||||
<rect x="110.0" y="1460.0" width="74.0" height="13.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.explore._facts" data-kind="function" class="blk"><title>_facts — function, 27 lines</title></rect>
|
||||
<rect x="110.0" y="1474.5" width="74.0" height="86.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.explore.emit" data-kind="function" class="blk"><title>emit — function, 172 lines</title></rect>
|
||||
<rect x="110.0" y="1561.5" width="74.0" height="8.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.explore.write" data-kind="function" class="blk"><title>write — function, 17 lines</title></rect>
|
||||
<rect x="192.0" y="1412.5" width="74.0" height="146.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.dot — 292 lines</title></rect>
|
||||
<rect x="192.0" y="1431.0" width="74.0" height="2.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.emitters.dot.RenderError" data-kind="class" class="blk"><title>RenderError — class, 2 lines</title></rect>
|
||||
<rect x="192.0" y="1433.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot._esc" data-kind="function" class="blk"><title>_esc — function, 2 lines</title></rect>
|
||||
<rect x="192.0" y="1435.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot._attrs" data-kind="function" class="blk"><title>_attrs — function, 3 lines</title></rect>
|
||||
<rect x="192.0" y="1437.5" width="74.0" height="4.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot._style_words" data-kind="function" class="blk"><title>_style_words — function, 9 lines</title></rect>
|
||||
<rect x="192.0" y="1443.0" width="74.0" height="12.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot._node_attrs" data-kind="function" class="blk"><title>_node_attrs — function, 24 lines</title></rect>
|
||||
<rect x="192.0" y="1456.0" width="74.0" height="52.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot.emit" data-kind="function" class="blk"><title>emit — function, 105 lines</title></rect>
|
||||
<rect x="199.0" y="1469.5" width="60.0" height="14.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.emitters.dot.emit.write" data-kind="function" class="blk"><title>write — function, 29 lines</title></rect>
|
||||
<rect x="192.0" y="1509.5" width="74.0" height="4.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot._within" data-kind="function" class="blk"><title>_within — function, 8 lines</title></rect>
|
||||
<rect x="192.0" y="1514.5" width="74.0" height="20.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot._endpoints" data-kind="function" class="blk"><title>_endpoints — function, 41 lines</title></rect>
|
||||
<rect x="199.0" y="1519.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.emitters.dot._endpoints.walk" data-kind="function" class="blk"><title>walk — function, 4 lines</title></rect>
|
||||
<rect x="199.0" y="1523.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.emitters.dot._endpoints.collapsed" data-kind="function" class="blk"><title>collapsed — function, 2 lines</title></rect>
|
||||
<rect x="199.0" y="1525.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.emitters.dot._endpoints.first_leaf" data-kind="function" class="blk"><title>first_leaf — function, 4 lines</title></rect>
|
||||
<rect x="192.0" y="1536.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot._safe" data-kind="function" class="blk"><title>_safe — function, 2 lines</title></rect>
|
||||
<rect x="192.0" y="1538.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot._q" data-kind="function" class="blk"><title>_q — function, 2 lines</title></rect>
|
||||
<rect x="192.0" y="1541.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot.have_graphviz" data-kind="function" class="blk"><title>have_graphviz — function, 2 lines</title></rect>
|
||||
<rect x="192.0" y="1543.5" width="74.0" height="14.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.dot.render" data-kind="function" class="blk"><title>render — function, 29 lines</title></rect>
|
||||
<rect x="274.0" y="1412.5" width="74.0" height="139.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.notebook — 279 lines</title></rect>
|
||||
<rect x="274.0" y="1433.5" width="74.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.notebook._cell" data-kind="function" class="blk"><title>_cell — function, 13 lines</title></rect>
|
||||
<rect x="274.0" y="1441.0" width="74.0" height="13.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.notebook._example" data-kind="function" class="blk"><title>_example — function, 26 lines</title></rect>
|
||||
<rect x="274.0" y="1474.5" width="74.0" height="9.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.notebook._params_cell" data-kind="function" class="blk"><title>_params_cell — function, 18 lines</title></rect>
|
||||
<rect x="274.0" y="1484.5" width="74.0" height="20.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.notebook._call_cell" data-kind="function" class="blk"><title>_call_cell — function, 40 lines</title></rect>
|
||||
<rect x="274.0" y="1505.5" width="74.0" height="13.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.notebook._call_md" data-kind="function" class="blk"><title>_call_md — function, 26 lines</title></rect>
|
||||
<rect x="274.0" y="1519.5" width="74.0" height="26.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.notebook.build" data-kind="function" class="blk"><title>build — function, 52 lines</title></rect>
|
||||
<rect x="274.0" y="1546.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.notebook.emit" data-kind="function" class="blk"><title>emit — function, 3 lines</title></rect>
|
||||
<rect x="274.0" y="1549.0" width="74.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.notebook.write" data-kind="function" class="blk"><title>write — function, 5 lines</title></rect>
|
||||
<rect x="356.0" y="1412.5" width="74.0" height="139.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.minimap — 278 lines</title></rect>
|
||||
<rect x="356.0" y="1444.0" width="74.0" height="28.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.minimap._files" data-kind="function" class="blk"><title>_files — function, 57 lines</title></rect>
|
||||
<rect x="363.0" y="1448.0" width="60.0" height="9.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.emitters.minimap._files.declared" data-kind="function" class="blk"><title>declared — function, 18 lines</title></rect>
|
||||
<rect x="363.0" y="1457.5" width="60.0" height="5.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.emitters.minimap._files.build" data-kind="function" class="blk"><title>build — function, 11 lines</title></rect>
|
||||
<rect x="356.0" y="1473.5" width="74.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.minimap._bands" data-kind="function" class="blk"><title>_bands — function, 7 lines</title></rect>
|
||||
<rect x="356.0" y="1478.0" width="74.0" height="9.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.minimap._blocks" data-kind="function" class="blk"><title>_blocks — function, 19 lines</title></rect>
|
||||
<rect x="356.0" y="1488.5" width="74.0" height="60.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.minimap.emit" data-kind="function" class="blk"><title>emit — function, 120 lines</title></rect>
|
||||
<rect x="356.0" y="1549.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.minimap.marks_to_labels" data-kind="function" class="blk"><title>marks_to_labels — function, 3 lines</title></rect>
|
||||
<rect x="438.0" y="1412.5" width="74.0" height="130.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.erd — 260 lines</title></rect>
|
||||
<rect x="438.0" y="1439.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.erd._truncate" data-kind="function" class="blk"><title>_truncate — function, 3 lines</title></rect>
|
||||
<rect x="438.0" y="1442.0" width="74.0" height="10.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.erd._tables" data-kind="function" class="blk"><title>_tables — function, 20 lines</title></rect>
|
||||
<rect x="438.0" y="1453.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.erd._card_height" data-kind="function" class="blk"><title>_card_height — function, 3 lines</title></rect>
|
||||
<rect x="438.0" y="1455.5" width="74.0" height="10.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.erd.layout" data-kind="function" class="blk"><title>layout — function, 20 lines</title></rect>
|
||||
<rect x="438.0" y="1466.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.erd._field_y" data-kind="function" class="blk"><title>_field_y — function, 3 lines</title></rect>
|
||||
<rect x="438.0" y="1469.0" width="74.0" height="73.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.erd.emit" data-kind="function" class="blk"><title>emit — function, 146 lines</title></rect>
|
||||
<rect x="520.0" y="1412.5" width="74.0" height="82.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.index — 164 lines</title></rect>
|
||||
<rect x="520.0" y="1429.5" width="74.0" height="4.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.index._tree" data-kind="function" class="blk"><title>_tree — function, 8 lines</title></rect>
|
||||
<rect x="520.0" y="1434.5" width="74.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.index._anchor" data-kind="function" class="blk"><title>_anchor — function, 5 lines</title></rect>
|
||||
<rect x="520.0" y="1438.0" width="74.0" height="42.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.index.to_markdown" data-kind="function" class="blk"><title>to_markdown — function, 84 lines</title></rect>
|
||||
<rect x="527.0" y="1449.5" width="60.0" height="13.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.emitters.index.to_markdown.walk" data-kind="function" class="blk"><title>walk — function, 27 lines</title></rect>
|
||||
<rect x="520.0" y="1481.0" width="74.0" height="13.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.index.to_sidebar" data-kind="function" class="blk"><title>to_sidebar — function, 26 lines</title></rect>
|
||||
<rect x="527.0" y="1484.5" width="60.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.emitters.index.to_sidebar.build" data-kind="function" class="blk"><title>build — function, 13 lines</title></rect>
|
||||
<rect x="602.0" y="1412.5" width="74.0" height="32.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.emitters.auto — 64 lines</title></rect>
|
||||
<rect x="602.0" y="1426.0" width="74.0" height="18.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.emitters.auto.draw" data-kind="function" class="blk"><title>draw — function, 36 lines</title></rect>
|
||||
<rect x="702.0" y="1412.5" width="74.0" height="141.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors.code — 282 lines</title></rect>
|
||||
<rect x="702.0" y="1460.0" width="74.0" height="2.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.extractors.code.MissingParser" data-kind="class" class="blk"><title>MissingParser — class, 2 lines</title></rect>
|
||||
<rect x="702.0" y="1462.0" width="74.0" height="10.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.code._parser" data-kind="function" class="blk"><title>_parser — function, 21 lines</title></rect>
|
||||
<rect x="702.0" y="1473.5" width="74.0" height="5.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.code._name" data-kind="function" class="blk"><title>_name — function, 10 lines</title></rect>
|
||||
<rect x="702.0" y="1479.5" width="74.0" height="17.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.code._walk" data-kind="function" class="blk"><title>_walk — function, 34 lines</title></rect>
|
||||
<rect x="702.0" y="1497.5" width="74.0" height="13.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.code.extract_file" data-kind="function" class="blk"><title>extract_file — function, 27 lines</title></rect>
|
||||
<rect x="702.0" y="1512.0" width="74.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.code._count_errors" data-kind="function" class="blk"><title>_count_errors — function, 5 lines</title></rect>
|
||||
<rect x="702.0" y="1515.5" width="74.0" height="37.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.code.extract" data-kind="function" class="blk"><title>extract — function, 75 lines</title></rect>
|
||||
<rect x="784.0" y="1412.5" width="74.0" height="134.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors.usage — 269 lines</title></rect>
|
||||
<rect x="784.0" y="1444.5" width="74.0" height="13.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.usage._template" data-kind="function" class="blk"><title>_template — function, 27 lines</title></rect>
|
||||
<rect x="784.0" y="1459.0" width="74.0" height="5.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.usage._body" data-kind="function" class="blk"><title>_body — function, 10 lines</title></rect>
|
||||
<rect x="784.0" y="1465.0" width="74.0" height="7.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.usage._shape" data-kind="function" class="blk"><title>_shape — function, 15 lines</title></rect>
|
||||
<rect x="784.0" y="1473.5" width="74.0" height="5.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.usage._graphql" data-kind="function" class="blk"><title>_graphql — function, 11 lines</title></rect>
|
||||
<rect x="784.0" y="1480.0" width="74.0" height="66.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.usage.extract" data-kind="function" class="blk"><title>extract — function, 133 lines</title></rect>
|
||||
<rect x="28.0" y="1697.5" width="74.0" height="95.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors.openapi — 191 lines</title></rect>
|
||||
<rect x="28.0" y="1713.0" width="74.0" height="14.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.openapi._modelgen" data-kind="function" class="blk"><title>_modelgen — function, 28 lines</title></rect>
|
||||
<rect x="28.0" y="1728.0" width="74.0" height="3.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.openapi._type_name" data-kind="function" class="blk"><title>_type_name — function, 6 lines</title></rect>
|
||||
<rect x="28.0" y="1732.0" width="74.0" height="21.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.openapi._refs" data-kind="function" class="blk"><title>_refs — function, 43 lines</title></rect>
|
||||
<rect x="28.0" y="1754.5" width="74.0" height="38.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.openapi.extract" data-kind="function" class="blk"><title>extract — function, 76 lines</title></rect>
|
||||
<rect x="110.0" y="1697.5" width="74.0" height="80.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors.db — 161 lines</title></rect>
|
||||
<rect x="110.0" y="1717.0" width="74.0" height="41.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.db.from_schema_dict" data-kind="function" class="blk"><title>from_schema_dict — function, 82 lines</title></rect>
|
||||
<rect x="110.0" y="1759.0" width="74.0" height="5.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.db._relation" data-kind="function" class="blk"><title>_relation — function, 10 lines</title></rect>
|
||||
<rect x="110.0" y="1765.0" width="74.0" height="3.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.db._plain_type" data-kind="function" class="blk"><title>_plain_type — function, 6 lines</title></rect>
|
||||
<rect x="110.0" y="1769.0" width="74.0" height="4.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.db._dedupe" data-kind="function" class="blk"><title>_dedupe — function, 9 lines</title></rect>
|
||||
<rect x="110.0" y="1774.5" width="74.0" height="3.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.db.extract" data-kind="function" class="blk"><title>extract — function, 6 lines</title></rect>
|
||||
<rect x="192.0" y="1697.5" width="74.0" height="18.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors.python — 37 lines</title></rect>
|
||||
<rect x="192.0" y="1707.0" width="74.0" height="7.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.extract" data-kind="function" class="blk"><title>extract — function, 14 lines</title></rect>
|
||||
<rect x="292.0" y="1697.5" width="74.0" height="190.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.book.build — 381 lines</title></rect>
|
||||
<rect x="292.0" y="1735.0" width="74.0" height="13.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.build.extract" data-kind="function" class="blk"><title>extract — function, 27 lines</title></rect>
|
||||
<rect x="292.0" y="1749.5" width="74.0" height="34.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.build.spec_from" data-kind="function" class="blk"><title>spec_from — function, 68 lines</title></rect>
|
||||
<rect x="292.0" y="1784.5" width="74.0" height="22.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.build._load_cell" data-kind="function" class="blk"><title>_load_cell — function, 44 lines</title></rect>
|
||||
<rect x="292.0" y="1811.0" width="74.0" height="13.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.build.clear" data-kind="function" class="blk"><title>clear — function, 26 lines</title></rect>
|
||||
<rect x="292.0" y="1825.0" width="74.0" height="62.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.build.run" data-kind="function" class="blk"><title>run — function, 125 lines</title></rect>
|
||||
<rect x="299.0" y="1831.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.build.run.say" data-kind="function" class="blk"><title>say — function, 3 lines</title></rect>
|
||||
<rect x="374.0" y="1697.5" width="74.0" height="164.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.book.config — 328 lines</title></rect>
|
||||
<rect x="374.0" y="1738.0" width="74.0" height="3.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.book.config.ConfigError" data-kind="class" class="blk"><title>ConfigError — class, 6 lines</title></rect>
|
||||
<rect x="381.0" y="1739.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.config.ConfigError.__init__" data-kind="function" class="blk"><title>__init__ — function, 3 lines</title></rect>
|
||||
<rect x="374.0" y="1742.5" width="74.0" height="7.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.book.config.Entry" data-kind="class" class="blk"><title>Entry — class, 14 lines</title></rect>
|
||||
<rect x="381.0" y="1748.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.config.Entry.line" data-kind="function" class="blk"><title>line — function, 2 lines</title></rect>
|
||||
<rect x="374.0" y="1751.0" width="74.0" height="8.5" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.book.config.RunFile" data-kind="class" class="blk"><title>RunFile — class, 17 lines</title></rect>
|
||||
<rect x="381.0" y="1753.5" width="60.0" height="6.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.config.RunFile.select" data-kind="function" class="blk"><title>select — function, 12 lines</title></rect>
|
||||
<rect x="374.0" y="1760.5" width="74.0" height="3.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.config._path" data-kind="function" class="blk"><title>_path — function, 6 lines</title></rect>
|
||||
<rect x="374.0" y="1764.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.config._within" data-kind="function" class="blk"><title>_within — function, 3 lines</title></rect>
|
||||
<rect x="374.0" y="1767.0" width="74.0" height="65.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.config.load" data-kind="function" class="blk"><title>load — function, 130 lines</title></rect>
|
||||
<rect x="381.0" y="1799.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.config.load.pick" data-kind="function" class="blk"><title>pick — function, 3 lines</title></rect>
|
||||
<rect x="374.0" y="1833.0" width="74.0" height="5.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.config.apply_reference" data-kind="function" class="blk"><title>apply_reference — function, 11 lines</title></rect>
|
||||
<rect x="374.0" y="1839.5" width="74.0" height="21.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.config.run" data-kind="function" class="blk"><title>run — function, 43 lines</title></rect>
|
||||
<rect x="456.0" y="1697.5" width="74.0" height="137.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.book.checks — 275 lines</title></rect>
|
||||
<rect x="456.0" y="1728.0" width="74.0" height="13.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.book.checks.Loaded" data-kind="class" class="blk"><title>Loaded — class, 26 lines</title></rect>
|
||||
<rect x="463.0" y="1729.5" width="60.0" height="7.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.checks.Loaded.__init__" data-kind="function" class="blk"><title>__init__ — function, 15 lines</title></rect>
|
||||
<rect x="463.0" y="1738.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.checks.Loaded.larder" data-kind="function" class="blk"><title>larder — function, 2 lines</title></rect>
|
||||
<rect x="463.0" y="1740.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.checks.Loaded.measure" data-kind="function" class="blk"><title>measure — function, 2 lines</title></rect>
|
||||
<rect x="456.0" y="1742.0" width="74.0" height="18.5" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.book.checks.Report" data-kind="class" class="blk"><title>Report — class, 37 lines</title></rect>
|
||||
<rect x="463.0" y="1743.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.checks.Report.__init__" data-kind="function" class="blk"><title>__init__ — function, 2 lines</title></rect>
|
||||
<rect x="463.0" y="1745.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.checks.Report.note" data-kind="function" class="blk"><title>note — function, 2 lines</title></rect>
|
||||
<rect x="463.0" y="1746.5" width="60.0" height="4.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.checks.Report.check" data-kind="function" class="blk"><title>check — function, 8 lines</title></rect>
|
||||
<rect x="463.0" y="1751.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.checks.Report.skip" data-kind="function" class="blk"><title>skip — function, 3 lines</title></rect>
|
||||
<rect x="463.0" y="1753.0" width="60.0" height="7.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.checks.Report.total" data-kind="function" class="blk"><title>total — function, 15 lines</title></rect>
|
||||
<rect x="456.0" y="1761.5" width="74.0" height="41.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.checks.generated" data-kind="function" class="blk"><title>generated — function, 83 lines</title></rect>
|
||||
<rect x="456.0" y="1804.0" width="74.0" height="13.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.checks.custom" data-kind="function" class="blk"><title>custom — function, 26 lines</title></rect>
|
||||
<rect x="456.0" y="1818.0" width="74.0" height="16.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.checks._run_cells" data-kind="function" class="blk"><title>_run_cells — function, 33 lines</title></rect>
|
||||
<rect x="538.0" y="1697.5" width="74.0" height="98.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.book.larder — 196 lines</title></rect>
|
||||
<rect x="538.0" y="1729.0" width="74.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.larder._count" data-kind="function" class="blk"><title>_count — function, 13 lines</title></rect>
|
||||
<rect x="538.0" y="1736.5" width="74.0" height="16.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.larder.redact" data-kind="function" class="blk"><title>redact — function, 32 lines</title></rect>
|
||||
<rect x="538.0" y="1754.0" width="74.0" height="38.5" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.book.larder.Larder" data-kind="class" class="blk"><title>Larder — class, 77 lines</title></rect>
|
||||
<rect x="545.0" y="1761.0" width="60.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.larder.Larder.__post_init__" data-kind="function" class="blk"><title>__post_init__ — function, 7 lines</title></rect>
|
||||
<rect x="545.0" y="1765.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.larder.Larder.read" data-kind="function" class="blk"><title>read — function, 3 lines</title></rect>
|
||||
<rect x="545.0" y="1767.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.larder.Larder.fail" data-kind="function" class="blk"><title>fail — function, 3 lines</title></rect>
|
||||
<rect x="545.0" y="1769.5" width="60.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.larder.Larder.to_dict" data-kind="function" class="blk"><title>to_dict — function, 13 lines</title></rect>
|
||||
<rect x="545.0" y="1777.0" width="60.0" height="5.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.larder.Larder.from_dict" data-kind="function" class="blk"><title>from_dict — function, 10 lines</title></rect>
|
||||
<rect x="545.0" y="1782.5" width="60.0" height="10.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.book.larder.Larder.line" data-kind="function" class="blk"><title>line — function, 20 lines</title></rect>
|
||||
<rect x="538.0" y="1793.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.book.larder.of" data-kind="function" class="blk"><title>of — function, 3 lines</title></rect>
|
||||
<rect x="638.0" y="1697.5" width="74.0" height="118.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors.python.collect — 236 lines</title></rect>
|
||||
<rect x="638.0" y="1714.0" width="74.0" height="5.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.extractors.python.collect.Definition" data-kind="class" class="blk"><title>Definition — class, 10 lines</title></rect>
|
||||
<rect x="638.0" y="1720.5" width="74.0" height="6.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.extractors.python.collect.Module" data-kind="class" class="blk"><title>Module — class, 12 lines</title></rect>
|
||||
<rect x="638.0" y="1727.5" width="74.0" height="33.5" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.extractors.python.collect._Collector" data-kind="class" class="blk"><title>_Collector — class, 67 lines</title></rect>
|
||||
<rect x="645.0" y="1729.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.extractors.python.collect._Collector.__init__" data-kind="function" class="blk"><title>__init__ — function, 3 lines</title></rect>
|
||||
<rect x="645.0" y="1732.0" width="60.0" height="8.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.extractors.python.collect._Collector._define" data-kind="function" class="blk"><title>_define — function, 17 lines</title></rect>
|
||||
<rect x="645.0" y="1741.0" width="60.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.extractors.python.collect._Collector.visit_ClassDef" data-kind="function" class="blk"><title>visit_ClassDef — function, 5 lines</title></rect>
|
||||
<rect x="645.0" y="1744.0" width="60.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.extractors.python.collect._Collector.visit_FunctionDef" data-kind="function" class="blk"><title>visit_FunctionDef — function, 5 lines</title></rect>
|
||||
<rect x="645.0" y="1749.5" width="60.0" height="4.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.extractors.python.collect._Collector.visit_Import" data-kind="function" class="blk"><title>visit_Import — function, 8 lines</title></rect>
|
||||
<rect x="645.0" y="1754.0" width="60.0" height="7.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.extractors.python.collect._Collector.visit_ImportFrom" data-kind="function" class="blk"><title>visit_ImportFrom — function, 14 lines</title></rect>
|
||||
<rect x="638.0" y="1762.0" width="74.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.collect._first_line" data-kind="function" class="blk"><title>_first_line — function, 5 lines</title></rect>
|
||||
<rect x="638.0" y="1765.5" width="74.0" height="7.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.collect._name_of" data-kind="function" class="blk"><title>_name_of — function, 15 lines</title></rect>
|
||||
<rect x="638.0" y="1774.0" width="74.0" height="8.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.collect._resolve_relative" data-kind="function" class="blk"><title>_resolve_relative — function, 16 lines</title></rect>
|
||||
<rect x="638.0" y="1783.0" width="74.0" height="13.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.collect.module_name" data-kind="function" class="blk"><title>module_name — function, 26 lines</title></rect>
|
||||
<rect x="638.0" y="1797.0" width="74.0" height="10.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.collect.collect_file" data-kind="function" class="blk"><title>collect_file — function, 21 lines</title></rect>
|
||||
<rect x="638.0" y="1808.5" width="74.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.collect.collect" data-kind="function" class="blk"><title>collect — function, 13 lines</title></rect>
|
||||
<rect x="720.0" y="1697.5" width="74.0" height="92.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.extractors.python.resolve — 184 lines</title></rect>
|
||||
<rect x="720.0" y="1711.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.resolve._id_for" data-kind="function" class="blk"><title>_id_for — function, 2 lines</title></rect>
|
||||
<rect x="720.0" y="1713.5" width="74.0" height="16.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.resolve._resolve" data-kind="function" class="blk"><title>_resolve — function, 32 lines</title></rect>
|
||||
<rect x="720.0" y="1730.5" width="74.0" height="8.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.resolve.larder_of" data-kind="function" class="blk"><title>larder_of — function, 17 lines</title></rect>
|
||||
<rect x="720.0" y="1740.0" width="74.0" height="49.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.extractors.python.resolve.to_ir" data-kind="function" class="blk"><title>to_ir — function, 98 lines</title></rect>
|
||||
<rect x="727.0" y="1769.5" width="60.0" height="4.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.extractors.python.resolve.to_ir._point_at" data-kind="function" class="blk"><title>_point_at — function, 9 lines</title></rect>
|
||||
<rect x="28.0" y="1926.0" width="74.0" height="139.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.ir.validate — 278 lines</title></rect>
|
||||
<rect x="28.0" y="1947.0" width="74.0" height="2.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.ir.validate.IRError" data-kind="class" class="blk"><title>IRError — class, 2 lines</title></rect>
|
||||
<rect x="28.0" y="1949.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ir.validate._schema" data-kind="function" class="blk"><title>_schema — function, 2 lines</title></rect>
|
||||
<rect x="28.0" y="1951.0" width="74.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ir.validate._props" data-kind="function" class="blk"><title>_props — function, 5 lines</title></rect>
|
||||
<rect x="28.0" y="1954.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ir.validate._fields" data-kind="function" class="blk"><title>_fields — function, 4 lines</title></rect>
|
||||
<rect x="28.0" y="1957.5" width="74.0" height="54.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ir.validate.check" data-kind="function" class="blk"><title>check — function, 108 lines</title></rect>
|
||||
<rect x="28.0" y="2019.0" width="74.0" height="29.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ir.validate._check_larder" data-kind="function" class="blk"><title>_check_larder — function, 58 lines</title></rect>
|
||||
<rect x="28.0" y="2049.0" width="74.0" height="3.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ir.validate.validate" data-kind="function" class="blk"><title>validate — function, 6 lines</title></rect>
|
||||
<rect x="28.0" y="2053.0" width="74.0" height="11.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ir.validate.check_model_matches_schema" data-kind="function" class="blk"><title>check_model_matches_schema — function, 23 lines</title></rect>
|
||||
<rect x="110.0" y="1926.0" width="74.0" height="82.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.ir.model — 165 lines</title></rect>
|
||||
<rect x="110.0" y="1942.5" width="74.0" height="19.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.ir.model.Meta" data-kind="class" class="blk"><title>Meta — class, 38 lines</title></rect>
|
||||
<rect x="117.0" y="1952.5" width="60.0" height="9.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ir.model.Meta.to_dict" data-kind="function" class="blk"><title>to_dict — function, 18 lines</title></rect>
|
||||
<rect x="110.0" y="1963.0" width="74.0" height="10.5" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.ir.model.Node" data-kind="class" class="blk"><title>Node — class, 21 lines</title></rect>
|
||||
<rect x="117.0" y="1967.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ir.model.Node.__post_init__" data-kind="function" class="blk"><title>__post_init__ — function, 3 lines</title></rect>
|
||||
<rect x="117.0" y="1969.5" width="60.0" height="4.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ir.model.Node.to_dict" data-kind="function" class="blk"><title>to_dict — function, 8 lines</title></rect>
|
||||
<rect x="110.0" y="1975.0" width="74.0" height="7.5" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.ir.model.Edge" data-kind="class" class="blk"><title>Edge — class, 15 lines</title></rect>
|
||||
<rect x="117.0" y="1979.0" width="60.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ir.model.Edge.to_dict" data-kind="function" class="blk"><title>to_dict — function, 7 lines</title></rect>
|
||||
<rect x="110.0" y="1984.0" width="74.0" height="24.0" rx="2" fill="#1d4ed8" stroke="none" opacity="0.95" data-id="docgen.ir.model.Graph" data-kind="class" class="blk"><title>Graph — class, 48 lines</title></rect>
|
||||
<rect x="117.0" y="1988.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ir.model.Graph.node" data-kind="function" class="blk"><title>node — function, 4 lines</title></rect>
|
||||
<rect x="117.0" y="1991.0" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ir.model.Graph.edge" data-kind="function" class="blk"><title>edge — function, 4 lines</title></rect>
|
||||
<rect x="117.0" y="1993.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ir.model.Graph.has" data-kind="function" class="blk"><title>has — function, 2 lines</title></rect>
|
||||
<rect x="117.0" y="1996.0" width="60.0" height="8.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ir.model.Graph.to_dict" data-kind="function" class="blk"><title>to_dict — function, 16 lines</title></rect>
|
||||
<rect x="117.0" y="2005.0" width="60.0" height="3.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ir.model.Graph.from_dict" data-kind="function" class="blk"><title>from_dict — function, 6 lines</title></rect>
|
||||
<rect x="210.0" y="1926.0" width="74.0" height="111.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.style.extract — 222 lines</title></rect>
|
||||
<rect x="210.0" y="1956.5" width="74.0" height="8.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.extract._values_from" data-kind="function" class="blk"><title>_values_from — function, 17 lines</title></rect>
|
||||
<rect x="210.0" y="1966.0" width="74.0" height="22.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.extract._normalise" data-kind="function" class="blk"><title>_normalise — function, 45 lines</title></rect>
|
||||
<rect x="210.0" y="1989.5" width="74.0" height="12.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.extract._svg_files" data-kind="function" class="blk"><title>_svg_files — function, 25 lines</title></rect>
|
||||
<rect x="210.0" y="2003.0" width="74.0" height="21.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.extract.harvest" data-kind="function" class="blk"><title>harvest — function, 43 lines</title></rect>
|
||||
<rect x="210.0" y="2025.5" width="74.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.extract.write" data-kind="function" class="blk"><title>write — function, 7 lines</title></rect>
|
||||
<rect x="210.0" y="2030.0" width="74.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.extract.summarise" data-kind="function" class="blk"><title>summarise — function, 13 lines</title></rect>
|
||||
<rect x="292.0" y="1926.0" width="74.0" height="105.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.style.tokens — 211 lines</title></rect>
|
||||
<rect x="292.0" y="1954.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.tokens._top" data-kind="function" class="blk"><title>_top — function, 2 lines</title></rect>
|
||||
<rect x="292.0" y="1956.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.tokens._mode" data-kind="function" class="blk"><title>_mode — function, 3 lines</title></rect>
|
||||
<rect x="292.0" y="1958.5" width="74.0" height="3.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.tokens._luminance" data-kind="function" class="blk"><title>_luminance — function, 6 lines</title></rect>
|
||||
<rect x="292.0" y="1962.5" width="74.0" height="50.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.tokens.derive" data-kind="function" class="blk"><title>derive — function, 101 lines</title></rect>
|
||||
<rect x="299.0" y="1984.5" width="60.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.style.tokens.derive.accent" data-kind="function" class="blk"><title>accent — function, 2 lines</title></rect>
|
||||
<rect x="292.0" y="2014.0" width="74.0" height="7.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.tokens.geometry" data-kind="function" class="blk"><title>geometry — function, 14 lines</title></rect>
|
||||
<rect x="292.0" y="2022.0" width="74.0" height="3.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.tokens.write" data-kind="function" class="blk"><title>write — function, 7 lines</title></rect>
|
||||
<rect x="292.0" y="2026.5" width="74.0" height="4.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.style.tokens.from_folder" data-kind="function" class="blk"><title>from_folder — function, 9 lines</title></rect>
|
||||
<rect x="392.0" y="1926.0" width="74.0" height="14.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen — 2 lines</title></rect>
|
||||
<rect x="492.0" y="1926.0" width="74.0" height="75.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.lab.pg_probe — 150 lines</title></rect>
|
||||
<rect x="492.0" y="1961.5" width="74.0" height="15.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.lab.pg_probe.probe" data-kind="function" class="blk"><title>probe — function, 30 lines</title></rect>
|
||||
<rect x="492.0" y="1983.5" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.lab.pg_probe._simplify" data-kind="function" class="blk"><title>_simplify — function, 3 lines</title></rect>
|
||||
<rect x="492.0" y="1986.0" width="74.0" height="12.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.lab.pg_probe.main" data-kind="function" class="blk"><title>main — function, 25 lines</title></rect>
|
||||
<rect x="592.0" y="1926.0" width="74.0" height="132.0" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.notebook.spec — 264 lines</title></rect>
|
||||
<rect x="592.0" y="1954.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.notebook.spec._step" data-kind="function" class="blk"><title>_step — function, 4 lines</title></rect>
|
||||
<rect x="592.0" y="1957.0" width="74.0" height="54.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.notebook.spec.from_ir" data-kind="function" class="blk"><title>from_ir — function, 108 lines</title></rect>
|
||||
<rect x="599.0" y="1964.0" width="60.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.notebook.spec.from_ir._order" data-kind="function" class="blk"><title>_order — function, 5 lines</title></rect>
|
||||
<rect x="592.0" y="2012.0" width="74.0" height="10.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.notebook.spec.scaffold" data-kind="function" class="blk"><title>scaffold — function, 20 lines</title></rect>
|
||||
<rect x="592.0" y="2023.0" width="74.0" height="29.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.notebook.spec.merge" data-kind="function" class="blk"><title>merge — function, 58 lines</title></rect>
|
||||
<rect x="592.0" y="2053.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.notebook.spec.load" data-kind="function" class="blk"><title>load — function, 2 lines</title></rect>
|
||||
<rect x="592.0" y="2055.0" width="74.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.notebook.spec.dump" data-kind="function" class="blk"><title>dump — function, 5 lines</title></rect>
|
||||
<rect x="692.0" y="1926.0" width="74.0" height="242.5" rx="2" fill="#141414" stroke="#333333" stroke-width="1"><title>docgen.ops.filter — 485 lines</title></rect>
|
||||
<rect x="692.0" y="1944.0" width="74.0" height="28.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter._rebuild" data-kind="function" class="blk"><title>_rebuild — function, 57 lines</title></rect>
|
||||
<rect x="699.0" y="1948.5" width="60.0" height="2.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ops.filter._rebuild.surviving_parent" data-kind="function" class="blk"><title>surviving_parent — function, 5 lines</title></rect>
|
||||
<rect x="699.0" y="1955.5" width="60.0" height="3.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ops.filter._rebuild.lift" data-kind="function" class="blk"><title>lift — function, 6 lines</title></rect>
|
||||
<rect x="692.0" y="1973.5" width="74.0" height="7.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.drop_kinds" data-kind="function" class="blk"><title>drop_kinds — function, 14 lines</title></rect>
|
||||
<rect x="692.0" y="1981.5" width="74.0" height="7.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.only_kinds" data-kind="function" class="blk"><title>only_kinds — function, 14 lines</title></rect>
|
||||
<rect x="692.0" y="1989.5" width="74.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.drop_stdlib" data-kind="function" class="blk"><title>drop_stdlib — function, 13 lines</title></rect>
|
||||
<rect x="692.0" y="1997.0" width="74.0" height="2.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.drop_external" data-kind="function" class="blk"><title>drop_external — function, 3 lines</title></rect>
|
||||
<rect x="692.0" y="1999.5" width="74.0" height="6.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.subtree" data-kind="function" class="blk"><title>subtree — function, 13 lines</title></rect>
|
||||
<rect x="692.0" y="2007.0" width="74.0" height="22.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.neighbourhood" data-kind="function" class="blk"><title>neighbourhood — function, 45 lines</title></rect>
|
||||
<rect x="692.0" y="2030.5" width="74.0" height="9.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.collapse_to_depth" data-kind="function" class="blk"><title>collapse_to_depth — function, 18 lines</title></rect>
|
||||
<rect x="699.0" y="2035.5" width="60.0" height="3.0" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ops.filter.collapse_to_depth.level" data-kind="function" class="blk"><title>level — function, 6 lines</title></rect>
|
||||
<rect x="692.0" y="2040.5" width="74.0" height="7.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.drop_builtins" data-kind="function" class="blk"><title>drop_builtins — function, 14 lines</title></rect>
|
||||
<rect x="692.0" y="2048.5" width="74.0" height="17.5" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.overview" data-kind="function" class="blk"><title>overview — function, 35 lines</title></rect>
|
||||
<rect x="692.0" y="2067.0" width="74.0" height="36.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.shape" data-kind="function" class="blk"><title>shape — function, 72 lines</title></rect>
|
||||
<rect x="699.0" y="2091.0" width="60.0" height="4.5" rx="2" fill="#15803d" stroke="none" opacity="0.8" data-id="docgen.ops.filter.shape.rank_of" data-kind="function" class="blk"><title>rank_of — function, 9 lines</title></rect>
|
||||
<rect x="692.0" y="2104.0" width="74.0" height="12.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.split" data-kind="function" class="blk"><title>split — function, 24 lines</title></rect>
|
||||
<rect x="692.0" y="2117.0" width="74.0" height="51.0" rx="2" fill="#15803d" stroke="none" opacity="0.95" data-id="docgen.ops.filter.classify" data-kind="function" class="blk"><title>classify — function, 102 lines</title></rect>
|
||||
<text x="28" y="40" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen</text>
|
||||
<text x="28" y="1242" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen</text>
|
||||
<text x="210" y="1242" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.cli</text>
|
||||
<text x="28" y="1406" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.emitters</text>
|
||||
<text x="702" y="1406" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.extractors</text>
|
||||
<text x="28" y="1692" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.extractors</text>
|
||||
<text x="292" y="1692" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.book</text>
|
||||
<text x="638" y="1692" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.extractors.python</text>
|
||||
<text x="28" y="1920" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.ir</text>
|
||||
<text x="210" y="1920" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.style</text>
|
||||
<text x="392" y="1920" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">(root)</text>
|
||||
<text x="492" y="1920" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.lab</text>
|
||||
<text x="592" y="1920" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.notebook</text>
|
||||
<text x="692" y="1920" font-family="Helvetica,sans-Serif" font-size="10" font-weight="bold" fill="#a3a3a3">docgen.ops</text>
|
||||
<text x="28" y="1219" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">selftest</text>
|
||||
<text x="110" y="213" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">book</text>
|
||||
<text x="192" y="152" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">style</text>
|
||||
<text x="274" y="109" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">reference</text>
|
||||
<text x="356" y="93" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">cli</text>
|
||||
<text x="438" y="69" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">ops</text>
|
||||
<text x="520" y="69" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">notebook</text>
|
||||
<text x="602" y="69" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">emitters</text>
|
||||
<text x="684" y="69" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">lab</text>
|
||||
<text x="766" y="69" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">__main__</text>
|
||||
<text x="28" y="1271" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">ir</text>
|
||||
<text x="110" y="1271" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">extractors</text>
|
||||
<text x="210" y="1384" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">emit</text>
|
||||
<text x="292" y="1316" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">extract</text>
|
||||
<text x="374" y="1302" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">view</text>
|
||||
<text x="456" y="1297" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">common</text>
|
||||
<text x="538" y="1297" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">run</text>
|
||||
<text x="620" y="1294" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">book</text>
|
||||
<text x="702" y="1282" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">check</text>
|
||||
<text x="784" y="1274" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">validate</text>
|
||||
<text x="28" y="1668" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">site</text>
|
||||
<text x="110" y="1580" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">explore</text>
|
||||
<text x="192" y="1568" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">dot</text>
|
||||
<text x="274" y="1561" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">notebook</text>
|
||||
<text x="356" y="1560" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">minimap</text>
|
||||
<text x="438" y="1552" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">erd</text>
|
||||
<text x="520" y="1504" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">index</text>
|
||||
<text x="602" y="1454" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">auto</text>
|
||||
<text x="702" y="1562" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">code</text>
|
||||
<text x="784" y="1556" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">usage</text>
|
||||
<text x="28" y="1802" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">openapi</text>
|
||||
<text x="110" y="1787" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">db</text>
|
||||
<text x="192" y="1725" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">python</text>
|
||||
<text x="292" y="1897" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">build</text>
|
||||
<text x="374" y="1870" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">config</text>
|
||||
<text x="456" y="1844" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">checks</text>
|
||||
<text x="538" y="1804" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">larder</text>
|
||||
<text x="638" y="1824" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">collect</text>
|
||||
<text x="720" y="1798" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">resolve</text>
|
||||
<text x="28" y="2074" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">validate</text>
|
||||
<text x="110" y="2018" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">model</text>
|
||||
<text x="210" y="2046" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">extract</text>
|
||||
<text x="292" y="2040" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">tokens</text>
|
||||
<text x="392" y="1949" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">docgen</text>
|
||||
<text x="492" y="2010" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">pg_probe</text>
|
||||
<text x="592" y="2067" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">spec</text>
|
||||
<text x="692" y="2178" font-family="Helvetica,sans-Serif" font-size="7" fill="#666666">filter</text>
|
||||
<rect x="28" y="2217.5" width="9" height="9" rx="2" fill="#1a1a1a"/>
|
||||
<text x="41" y="2225.5" font-family="Helvetica,sans-Serif" font-size="9" fill="#666666">module</text>
|
||||
<rect x="86" y="2217.5" width="9" height="9" rx="2" fill="#1d4ed8"/>
|
||||
<text x="99" y="2225.5" font-family="Helvetica,sans-Serif" font-size="9" fill="#666666">class</text>
|
||||
<rect x="138" y="2217.5" width="9" height="9" rx="2" fill="#d4a574"/>
|
||||
<text x="151" y="2225.5" font-family="Helvetica,sans-Serif" font-size="9" fill="#666666">interface</text>
|
||||
<rect x="214" y="2217.5" width="9" height="9" rx="2" fill="#15803d"/>
|
||||
<text x="227" y="2225.5" font-family="Helvetica,sans-Serif" font-size="9" fill="#666666">function</text>
|
||||
<text x="858" y="2225.5" text-anchor="end" font-family="Helvetica,sans-Serif" font-size="9" fill="#666666">47 files · 10,350 lines · 1px ≈ 2.0 lines</text>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 79 KiB |
@@ -41,6 +41,7 @@
|
||||
|
||||
<div class="group">Reference</div>
|
||||
<a href="#standalone">Standalone</a>
|
||||
<a href="#runs">Run files</a>
|
||||
<a href="#commands">Commands</a>
|
||||
<a href="#deps">Dependencies</a>
|
||||
<a href="#testing">Testing</a>
|
||||
@@ -117,6 +118,11 @@
|
||||
<pre><code>make book SRC=/path/to/repo BOOK=out/book/mine
|
||||
make check BOOK=out/book/mine</code></pre>
|
||||
|
||||
<p>
|
||||
More than one, rebuilt together, is a <a href="#runs">run file</a>:
|
||||
<code>make run CONFIG=docgen.toml</code>.
|
||||
</p>
|
||||
|
||||
<pre><code> larder /path/to/repo — 45 files read, 2 failed, 12 packages
|
||||
book 312 nodes · 244 edges · 26 external · 8 artifacts
|
||||
ok 45 file(s) read produced 45 module(s)
|
||||
@@ -128,13 +134,13 @@ make check BOOK=out/book/mine</code></pre>
|
||||
</p>
|
||||
|
||||
<pre><code><span class="c"># 1. read something</span>
|
||||
python3 -m docgen.extractors.python --root ../station/tools/histgen -o ir.json
|
||||
python3 -m docgen extract python --root ../station/tools/histgen -o ir.json
|
||||
|
||||
<span class="c"># 2. narrow it to a useful view</span>
|
||||
python3 -m docgen.ops ir.json --overview -o view.json
|
||||
python3 -m docgen view ir.json --overview -o view.json
|
||||
|
||||
<span class="c"># 3. draw whatever its structure asks for</span>
|
||||
python3 -m docgen.emitters auto view.json -o out/</code></pre>
|
||||
python3 -m docgen emit auto view.json -o out/</code></pre>
|
||||
|
||||
<p>Or through the Makefile, which is a thin wrapper over exactly those:</p>
|
||||
|
||||
@@ -281,7 +287,7 @@ make self <span class="c"># docgen's book of soleprint
|
||||
or the picture is smaller than the source and says nothing about it.
|
||||
</p>
|
||||
<p>
|
||||
<code>python3 -m docgen.book</code> exits 1 when a reconciliation fails. The
|
||||
<code>python3 -m docgen book</code> exits 1 when a reconciliation fails. The
|
||||
book is still written — the evidence is the point — but a build that lost input
|
||||
should fail a pipeline rather than pass quietly.
|
||||
</p>
|
||||
@@ -383,7 +389,7 @@ make check BOOK=out/book/station</code></pre>
|
||||
and it reads its field lists out of <code>schema.json</code> so the schema and
|
||||
the dataclasses cannot drift apart.
|
||||
</p>
|
||||
<pre><code>python3 -m docgen.ir ir.json</code></pre>
|
||||
<pre><code>python3 -m docgen validate ir.json</code></pre>
|
||||
<p>
|
||||
It catches what a schema cannot: an edge naming a node that does not exist, a
|
||||
containment cycle, a duplicate id, and a visual field smuggled into
|
||||
@@ -416,7 +422,7 @@ make check BOOK=out/book/station</code></pre>
|
||||
<tr><td><code>flat</code></td><td>the index</td><td>most nodes have no relationships: that is a list</td></tr>
|
||||
</table>
|
||||
|
||||
<pre><code>$ python3 -m docgen.emitters auto view.json -o out/
|
||||
<pre><code>$ python3 -m docgen emit auto view.json -o out/
|
||||
sheet -> index
|
||||
109 nodes sit at one level; any layered engine draws that as a
|
||||
strip. Split it, scope it, or read it as an index</code></pre>
|
||||
@@ -537,10 +543,10 @@ make check BOOK=out/book/station</code></pre>
|
||||
the same narrowing.
|
||||
</p>
|
||||
|
||||
<pre><code>python3 -m docgen.ops ir.json --overview -o view.json
|
||||
python3 -m docgen.ops ir.json --around docgen.ir --hops 2 -o view.json
|
||||
python3 -m docgen.ops ir.json --split -o parts/
|
||||
python3 -m docgen.ops ir.json --shape <span class="c"># what will this look like?</span></code></pre>
|
||||
<pre><code>python3 -m docgen view ir.json --overview -o view.json
|
||||
python3 -m docgen view ir.json --around docgen.ir --hops 2 -o view.json
|
||||
python3 -m docgen view ir.json --split -o parts/
|
||||
python3 -m docgen view ir.json --shape <span class="c"># what will this look like?</span></code></pre>
|
||||
|
||||
<p>
|
||||
All of them are IR→IR, all composable, and each produces a document that
|
||||
@@ -738,8 +744,8 @@ python3 -m docgen.ops ir.json --shape <span class="c"># what will this
|
||||
<b>absent</b> — it is an addition, never a dependency.
|
||||
</div>
|
||||
|
||||
<pre><code>python3 -m docgen.emitters notebook ir.json --scaffold overlay.json
|
||||
python3 -m docgen.emitters notebook ir.json --overlay overlay.json -o walkthrough.ipynb</code></pre>
|
||||
<pre><code>python3 -m docgen emit notebook ir.json --scaffold overlay.json
|
||||
python3 -m docgen emit notebook ir.json --overlay overlay.json -o walkthrough.ipynb</code></pre>
|
||||
|
||||
<!-- ─────────────────────────────────────────────────────────────── -->
|
||||
<h2 id="style">Style & colour</h2>
|
||||
@@ -802,6 +808,7 @@ python3 -m docgen.emitters notebook ir.json --overlay overlay.json -o walkthroug
|
||||
<pre><code>cp -r docgen /somewhere/else
|
||||
cd /somewhere/else/docgen
|
||||
make doctor <span class="c"># what this machine has</span>
|
||||
make sync <span class="c"># optional: every group, from uv.lock</span>
|
||||
make check <span class="c"># the suite, from the copy</span>
|
||||
make book SRC=/path/to/any/repo BOOK=out/book/theirs</code></pre>
|
||||
|
||||
@@ -865,19 +872,116 @@ make doctor
|
||||
|
||||
<table>
|
||||
<tr><th>context</th><th>checks</th><th>skipped</th></tr>
|
||||
<tr><td>in the repo</td><td>250</td><td>tree-sitter (259 with it)</td></tr>
|
||||
<tr><td>copied out</td><td>242</td><td>tree-sitter, OpenAPI, the in-place case</td></tr>
|
||||
<tr><td>copied out, <code>DOCGEN_REFERENCE</code> set</td><td>249</td>
|
||||
<td>tree-sitter, the in-place case</td></tr>
|
||||
<tr><td>in the repo, synced</td><td>287</td><td>—</td></tr>
|
||||
<tr><td>copied out, bare <code>python3</code></td><td>270</td><td>tree-sitter, OpenAPI, the in-place case</td></tr>
|
||||
<tr><td>copied out, synced</td><td>279</td><td>OpenAPI, the in-place case</td></tr>
|
||||
<tr><td>copied out, synced, <code>DOCGEN_REFERENCE</code> set</td><td>286</td>
|
||||
<td>the in-place case — correctly, there is no repo above</td></tr>
|
||||
</table>
|
||||
|
||||
<!-- ─────────────────────────────────────────────────────────────── -->
|
||||
<h2 id="runs">Run files</h2>
|
||||
|
||||
<p>
|
||||
A book gets rebuilt many times — after a merge, before a release, whenever the
|
||||
source moves — and each one is a source, an output directory and a handful of
|
||||
options. Typed out every time, those drift: one run excludes
|
||||
<code>migrations</code>, the next forgets. A <b>run file</b> writes them down
|
||||
once, so the rebuild is exact.
|
||||
</p>
|
||||
|
||||
<pre><code><span class="c"># docgen.toml — kept beside the project it describes</span>
|
||||
reference = "../soleprint" <span class="c"># optional; $DOCGEN_REFERENCE wins</span>
|
||||
|
||||
[defaults]
|
||||
out = "out/book" <span class="c"># each book goes to <out>/<name></span>
|
||||
theme = "dark"
|
||||
exclude = ["migrations", "tests"]
|
||||
|
||||
[[book]]
|
||||
name = "station"
|
||||
root = "../soleprint/station"
|
||||
|
||||
[[book]]
|
||||
name = "frontend"
|
||||
root = "../web/src"
|
||||
reader = "code" <span class="c"># C# / TypeScript, through tree-sitter</span>
|
||||
|
||||
[[book]]
|
||||
name = "orders-api"
|
||||
openapi = "specs/orders.yaml"
|
||||
overlay = "overlays/orders.json"
|
||||
out = "/srv/docs/orders"</code></pre>
|
||||
|
||||
<pre><code>make run CONFIG=docgen.toml
|
||||
make run CONFIG=docgen.toml ONLY=station,frontend CHECK=1
|
||||
python3 -m docgen run docgen.toml --list <span class="c"># resolved paths, nothing built</span></code></pre>
|
||||
|
||||
<pre><code>docgen.toml — 3 book(s)
|
||||
ok station /home/me/proj/out/book/station
|
||||
ok frontend /home/me/proj/out/book/frontend
|
||||
FAIL orders-api ImportError: modelgen is not reachable — …
|
||||
|
||||
1 of 3 book(s) did not hold — --verbose for each book's own output</code></pre>
|
||||
|
||||
<p>
|
||||
Each book names <b>exactly one</b> source — <code>root</code>,
|
||||
<code>schema</code>, <code>openapi</code> or <code>har</code> — the same choice
|
||||
the <code>book</code> command makes you take. One failing book never stops the
|
||||
rest, and the run exits 1 if any book failed to build, lost input between its
|
||||
two ends, or failed its checks. <code>docgen.example.toml</code> ships with
|
||||
docgen and runs against its own fixtures.
|
||||
</p>
|
||||
|
||||
<h3>The rules, each one a thing that goes wrong otherwise</h3>
|
||||
|
||||
<ul>
|
||||
<li><b>Paths are relative to the run file</b>, not to wherever the command ran.
|
||||
Otherwise the same file builds different books from different
|
||||
directories.</li>
|
||||
<li><b>A book's value replaces the default, for every key</b> — including
|
||||
<code>exclude</code>, where merging looks tempting. One rule nobody has to
|
||||
remember beats a clever one somebody has to look up. A default
|
||||
<code>exclude</code> simply does not apply to a schema or a spec.</li>
|
||||
<li><b>Unknown keys are refused, not ignored</b>, all of them at once.
|
||||
<code>exlude = [...]</code> silently doing nothing is how a rebuild quietly
|
||||
starts reading <code>node_modules</code>.</li>
|
||||
<li><b>A book may not be written inside the tree it reads</b> — the next run
|
||||
would read the last run's output — and <b>two books may not share an output
|
||||
directory</b>, where the second would clear the first every time.</li>
|
||||
<li><b>The environment beats the file.</b> A <code>reference</code> in the run
|
||||
file is used only when <code>$DOCGEN_REFERENCE</code> is not set, which is
|
||||
rig's precedence for every setting it has.</li>
|
||||
</ul>
|
||||
|
||||
<div class="note">
|
||||
<b>A rebuild replaces the previous build, and nothing else.</b> Before writing,
|
||||
a book removes exactly what a build writes — <code>book.json</code>,
|
||||
<code>notebook.ipynb</code>, <code>steps/</code>, <code>site/</code>,
|
||||
<code>explore/</code> — and only from a directory that already holds a
|
||||
<code>book.json</code>. Without it a graph that is now <code>graph.md</code> kept
|
||||
its old <code>graph.svg</code>, unlisted in the ledger and still on the page.
|
||||
A hand-written <code>checks.py</code> or <code>overlay.json</code> is never
|
||||
touched, and neither is a directory docgen did not write.
|
||||
</div>
|
||||
|
||||
<p>
|
||||
TOML because a run file is written by people: <code>tomllib</code> is the
|
||||
stdlib, it takes comments — the reason a book excludes something belongs next
|
||||
to the exclusion — and it is already the format of the
|
||||
<code>pyproject.toml</code> beside it. The IR and the style files stay JSON,
|
||||
because those are data that tools write.
|
||||
</p>
|
||||
|
||||
<!-- ─────────────────────────────────────────────────────────────── -->
|
||||
<h2 id="commands">Commands</h2>
|
||||
|
||||
<h3>Make</h3>
|
||||
<table>
|
||||
<tr><th>target</th><th>does</th></tr>
|
||||
<tr><td><code>make sync</code></td><td><code>.venv</code> with every optional group, from <code>uv.lock</code></td></tr>
|
||||
<tr><td><code>make book SRC=…</code></td><td><b>one whole operation</b>, measured at both ends</td></tr>
|
||||
<tr><td><code>make run CONFIG=…</code></td><td>every book a <a href="#runs">run file</a> lists</td></tr>
|
||||
<tr><td><code>make check</code></td><td>docgen's own suite, offline, nothing installed</td></tr>
|
||||
<tr><td><code>make check BOOK=…</code></td><td>one book's own level — generated and custom</td></tr>
|
||||
<tr><td><code>make doctor</code></td><td>what this machine has and what it is missing</td></tr>
|
||||
@@ -896,8 +1000,10 @@ make doctor
|
||||
<p>
|
||||
Variables: <code>SRC</code>, <code>OUT</code>, <code>SCHEMA</code>,
|
||||
<code>OPENAPI</code>, <code>HAR</code>, <code>BOOK</code>, <code>SLUG</code>,
|
||||
<code>READER</code>, <code>OVERLAY</code>, <code>STYLE</code>,
|
||||
<code>THEME</code>, <code>SCALE</code>, <code>DEPTH</code>, <code>PY</code>.
|
||||
<code>READER</code>, <code>OVERLAY</code>, <code>CONFIG</code>,
|
||||
<code>ONLY</code>, <code>CHECK</code>, <code>STYLE</code>, <code>THEME</code>,
|
||||
<code>SCALE</code>, <code>PY</code>. <code>PY</code> is the synced
|
||||
<code>.venv</code> when there is one and <code>python3</code> when there is not.
|
||||
The Makefile derives its own package name from where it sits, so the folder can
|
||||
be copied anywhere and renamed and still work.
|
||||
</p>
|
||||
@@ -909,49 +1015,100 @@ make doctor
|
||||
property the spine exists to preserve, not to replace.
|
||||
</p>
|
||||
|
||||
<h3>Modules</h3>
|
||||
<pre><code>python3 -m docgen.book --root SRC -o out/book/slug <span class="c"># the whole operation</span>
|
||||
python3 -m docgen.book.checks out/book/slug <span class="c"># that book's level</span>
|
||||
<h3>The command line</h3>
|
||||
|
||||
<p>
|
||||
One entry point, <code>python3 -m docgen <command></code>, run from the
|
||||
directory <em>above</em> the folder (or with it on <code>PYTHONPATH</code>, which
|
||||
is what the Makefile does). Each command is plain argparse and takes
|
||||
<code>--help</code>.
|
||||
</p>
|
||||
|
||||
python3 -m docgen.extractors.python --root SRC -o ir.json
|
||||
python3 -m docgen.extractors code --root SRC -o ir.json
|
||||
python3 -m docgen.extractors db --schema schema.json -o ir.json
|
||||
python3 -m docgen.extractors openapi --spec spec.yaml -o ir.json
|
||||
python3 -m docgen.extractors usage --har session.har -o ir.json
|
||||
<pre><code>python3 -m docgen book --root SRC -o out/book/slug <span class="c"># the whole operation</span>
|
||||
python3 -m docgen run docgen.toml <span class="c"># every book a run file lists</span>
|
||||
python3 -m docgen check <span class="c"># docgen's own suite</span>
|
||||
python3 -m docgen check out/book/slug <span class="c"># that book's level</span>
|
||||
|
||||
python3 -m docgen.ir ir.json <span class="c"># validate</span>
|
||||
python3 -m docgen.ops ir.json --overview -o view.json
|
||||
python3 -m docgen extract python --root SRC -o ir.json
|
||||
python3 -m docgen extract code --root SRC -o ir.json
|
||||
python3 -m docgen extract db --schema schema.json -o ir.json
|
||||
python3 -m docgen extract openapi --spec spec.yaml -o ir.json
|
||||
python3 -m docgen extract usage --har session.har -o ir.json
|
||||
|
||||
python3 -m docgen.emitters auto view.json -o out/
|
||||
python3 -m docgen.emitters index ir.json -o index.md
|
||||
python3 -m docgen.emitters dot view.json -o graph.svg --theme lucid
|
||||
python3 -m docgen.emitters erd ir.json -o schema.svg
|
||||
python3 -m docgen.emitters minimap ir.json -o map.svg --scale 0.5
|
||||
python3 -m docgen.emitters notebook ir.json -o book.ipynb --overlay overlay.json
|
||||
python3 -m docgen.emitters site view.json -o site/
|
||||
python3 -m docgen.emitters explore ir.json -o explore/</code></pre>
|
||||
python3 -m docgen validate ir.json
|
||||
python3 -m docgen view ir.json --overview -o view.json
|
||||
|
||||
python3 -m docgen emit auto view.json -o out/
|
||||
python3 -m docgen emit index ir.json -o index.md
|
||||
python3 -m docgen emit dot view.json -o graph.svg --theme lucid
|
||||
python3 -m docgen emit erd ir.json -o schema.svg
|
||||
python3 -m docgen emit minimap ir.json -o map.svg --scale 0.5
|
||||
python3 -m docgen emit notebook ir.json -o book.ipynb --overlay overlay.json
|
||||
python3 -m docgen emit site view.json -o site/
|
||||
python3 -m docgen emit explore ir.json -o explore/</code></pre>
|
||||
|
||||
<h3>Where the command line lives</h3>
|
||||
|
||||
<p>
|
||||
All of it in <code>cli/</code>, and nowhere else. <code>extractors/</code>,
|
||||
<code>ops/</code>, <code>emitters/</code> and <code>book/</code> hold library
|
||||
code only — no argparse, no <code>__main__.py</code>, no
|
||||
<code>cli_dot.py</code> sitting next to <code>dot.py</code>. Two kinds of file
|
||||
in one folder make every folder answer two questions, and the command-line half
|
||||
is the half that grows copies: eight <code>cli_*</code> files each
|
||||
re-implemented "read the IR, validate it, load the style" by hand, and had begun
|
||||
to word their errors differently.
|
||||
</p>
|
||||
|
||||
<pre><code>cli/
|
||||
├── __init__.py <span class="c">the command table and the one exit path</span>
|
||||
├── common.py <span class="c">read and validate an IR, load a style, write or print</span>
|
||||
├── book.py run.py check.py
|
||||
└── extract.py validate.py view.py emit.py</code></pre>
|
||||
|
||||
<p>
|
||||
A command reports an expected failure by raising, and <code>cli.main</code>
|
||||
turns it into the only exit path: one <code>Error:</code> line on stderr, exit 1,
|
||||
never a traceback. Doing that split also surfaced a third copy of "which drawing
|
||||
does this graph want" — in the <code>auto</code> command, the <code>site</code>
|
||||
command and the book — which is now <code>emitters.auto.draw()</code>, returning
|
||||
content and leaving the file name to the caller.
|
||||
</p>
|
||||
|
||||
<!-- ─────────────────────────────────────────────────────────────── -->
|
||||
<h2 id="deps">Dependencies</h2>
|
||||
|
||||
<p>
|
||||
Everything below is optional. The stdlib covers the whole structural path — see <a href="#standalone">standalone</a>
|
||||
for the one seam out of the folder.
|
||||
The core is <strong>standard library only</strong>, Python 3.11 or later —
|
||||
<code>pyproject.toml</code> declares no required dependency at all. Everything
|
||||
else is an optional <b>dependency group</b>, pinned in a committed
|
||||
<code>uv.lock</code>, and reported by <code>make doctor</code>; when something is
|
||||
missing you lose exactly one capability and get told what to install. See
|
||||
<a href="#standalone">standalone</a> for the one seam out of the folder.
|
||||
</p>
|
||||
|
||||
<pre><code>make sync <span class="c"># uv sync --all-groups → .venv/</span>
|
||||
uv sync --group code <span class="c"># or just the one you need</span>
|
||||
make lock <span class="c"># after editing pyproject.toml</span></code></pre>
|
||||
|
||||
<p>
|
||||
The core is <strong>standard library only</strong>. Everything else is optional
|
||||
and reported by <code>make doctor</code>; when something is missing you lose
|
||||
exactly one capability and get told what to install.
|
||||
<code>[tool.uv] package = false</code>, the same choice
|
||||
<code>station/tools/dataconvert</code> makes: this is a folder of modules run in
|
||||
place, not something to install. The lock pins what the optional groups resolve
|
||||
to; the folder still runs on a bare <code>python3</code> without it.
|
||||
</p>
|
||||
|
||||
<table>
|
||||
<tr><th>needs</th><th>for</th><th>without it</th></tr>
|
||||
<tr><td><code>graphviz</code> (binary)</td><td>rendering DOT to SVG</td>
|
||||
<td>ERD, minimap, index and notebooks still work</td></tr>
|
||||
<tr><td><code>tree_sitter</code> + grammars</td><td>C#, TypeScript, TSX</td>
|
||||
<tr><td>group <code>code</code> — tree-sitter + grammars</td><td>C#, TypeScript, TSX</td>
|
||||
<td>Python only</td></tr>
|
||||
<tr><td><code>networkx</code></td><td><code>lab/</code> experiments</td>
|
||||
<tr><td>group <code>openapi</code> — pyyaml</td><td>reading OpenAPI (with the reference repo)</td>
|
||||
<td>the other four sources</td></tr>
|
||||
<tr><td>group <code>harvest</code> — lxml</td><td>a theme from exported diagrams</td>
|
||||
<td>the shipped themes</td></tr>
|
||||
<tr><td>group <code>lab</code> — networkx</td><td><code>lab/</code> experiments</td>
|
||||
<td>nothing — nothing depends on it yet</td></tr>
|
||||
<tr><td><code>node</code></td><td>testing the browser pages</td>
|
||||
<td>those checks skip</td></tr>
|
||||
@@ -979,16 +1136,19 @@ python3 -m docgen.emitters explore ir.json -o explore/</code></pre>
|
||||
<tr><th>command</th><th>asks about</th><th>fails?</th></tr>
|
||||
<tr><td><code>make doctor</code></td><td>the machine — what is installed</td>
|
||||
<td>never; it reports</td></tr>
|
||||
<tr><td><code>make check</code></td><td>docgen — 259 checks</td>
|
||||
<tr><td><code>make check</code></td><td>docgen — 287 checks</td>
|
||||
<td>exit 1</td></tr>
|
||||
<tr><td><code>make check BOOK=<dir></code></td><td>that one book</td>
|
||||
<td>exit 1</td></tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
All 259 with both optional dependencies installed, 244 with neither — the suite
|
||||
skips rather than fails when tree-sitter, lxml or the OpenAPI reader is absent.
|
||||
See <a href="#standalone">standalone</a> for the counts outside the repo.
|
||||
All 287 after <code>make sync</code>, 272 with nothing optional installed — the
|
||||
suite skips rather than fails when tree-sitter, lxml or the OpenAPI reader is
|
||||
absent. See <a href="#standalone">standalone</a> for the counts outside the repo.
|
||||
Among them, two that keep this page's structure true: nothing outside
|
||||
<code>cli/</code> imports argparse, and every import the suite allows is a group
|
||||
in <code>pyproject.toml</code> and pinned in <code>uv.lock</code>.
|
||||
</p>
|
||||
|
||||
<h3>The book level, where custom checks live</h3>
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
""" python3 -m docgen.emitters <emitter> <ir.json> [options]"""
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
argv = sys.argv[1:] if argv is None else argv
|
||||
if not argv:
|
||||
print("usage: python3 -m docgen.emitters <auto|dot|index|erd|notebook|site|minimap|explore> <ir.json> [-o OUT] [--style NAME] [--theme NAME]",
|
||||
file=sys.stderr)
|
||||
return 2
|
||||
name, rest = argv[0], argv[1:]
|
||||
if name == "dot":
|
||||
from .cli_dot import main as run
|
||||
elif name == "index":
|
||||
from .cli_index import main as run
|
||||
elif name == "erd":
|
||||
from .cli_erd import main as run
|
||||
elif name == "auto":
|
||||
from .auto import main as run
|
||||
elif name == "notebook":
|
||||
from .cli_notebook import main as run
|
||||
elif name == "site":
|
||||
from .cli_site import main as run
|
||||
elif name == "minimap":
|
||||
from .cli_minimap import main as run
|
||||
elif name == "explore":
|
||||
from .cli_explore import main as run
|
||||
else:
|
||||
print(f"Error: no emitter {name!r} — have: auto, dot, index, erd, notebook, site, minimap, explore", file=sys.stderr)
|
||||
return 1
|
||||
return run(rest)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -1,79 +1,63 @@
|
||||
"""
|
||||
Draw it the way its structure asks to be drawn.
|
||||
|
||||
python3 -m docgen.emitters auto ir.json -o out/
|
||||
|
||||
`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 writes the index,
|
||||
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.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
## One function, three callers
|
||||
|
||||
from ..ir import check
|
||||
from ..ops import classify
|
||||
from ..style import Style, StyleError
|
||||
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
|
||||
|
||||
def main(argv=None):
|
||||
p = argparse.ArgumentParser(prog="python3 -m docgen.emitters auto")
|
||||
p.add_argument("ir", type=Path)
|
||||
p.add_argument("--output", "-o", type=Path, help="Directory to write into.")
|
||||
p.add_argument("--style", default="lucid")
|
||||
p.add_argument("--theme", default=None)
|
||||
p.add_argument("--force", help="Use this emitter regardless of what fits.")
|
||||
args = p.parse_args(argv)
|
||||
# What each emitter produces, so a caller can name the file without knowing
|
||||
# which emitter ran.
|
||||
SUFFIX = {"erd": ".svg", "dot": ".svg", "index": ".md"}
|
||||
|
||||
try:
|
||||
data = json.loads(args.ir.read_text())
|
||||
except (OSError, json.JSONDecodeError) as e:
|
||||
print(f"Error: could not read {args.ir}: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
problems = check(data)
|
||||
if problems:
|
||||
print(f"Error: {args.ir} is not a valid IR ({len(problems)}):", file=sys.stderr)
|
||||
for pr in problems[:5]:
|
||||
print(f" {pr}", file=sys.stderr)
|
||||
return 1
|
||||
def draw(ir: dict, style, *, force: str | None = None) -> dict:
|
||||
"""The drawing this graph asks for, as content.
|
||||
|
||||
verdict = classify(data)
|
||||
chosen = args.force or verdict["emitter"]
|
||||
print(f" {verdict['kind']:<8} -> {chosen}")
|
||||
print(f" {verdict['why']}")
|
||||
Returns::
|
||||
|
||||
out_dir = args.output or Path(".")
|
||||
out_dir.mkdir(parents=True, exist_ok=True)
|
||||
stem = args.ir.stem
|
||||
{"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}
|
||||
|
||||
try:
|
||||
style = Style.load(args.style, theme=args.theme)
|
||||
except StyleError as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
return 1
|
||||
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 as erd_emit
|
||||
|
||||
path = out_dir / f"{stem}.svg"
|
||||
path.write_text(erd_emit(data, style))
|
||||
from .erd import emit
|
||||
out["content"] = emit(ir, style)
|
||||
elif chosen == "index":
|
||||
from .index import to_markdown
|
||||
|
||||
path = out_dir / f"{stem}.md"
|
||||
path.write_text(to_markdown(data))
|
||||
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:
|
||||
from .dot import emit as dot_emit, render
|
||||
|
||||
path = out_dir / f"{stem}.svg"
|
||||
opts = verdict.get("options") or {}
|
||||
path.write_bytes(render(dot_emit(data, style, rankdir=opts.get("rankdir"))))
|
||||
|
||||
print(f" {path}")
|
||||
return 0
|
||||
raise ValueError(f"no emitter {chosen!r} — have: erd, dot, index")
|
||||
return out
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
""" python3 -m docgen.emitters dot <ir.json> [-o out.svg] [--style lucid] [--theme dark]"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from ..ir import check
|
||||
from ..ops import shape
|
||||
from ..style import Style, StyleError
|
||||
from .dot import RenderError, emit, render
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
p = argparse.ArgumentParser(prog="python3 -m docgen.emitters dot")
|
||||
p.add_argument("ir", type=Path)
|
||||
p.add_argument("--output", "-o", type=Path, help="Write here. .dot or .svg by suffix.")
|
||||
p.add_argument("--style", default="lucid")
|
||||
p.add_argument("--theme", default=None)
|
||||
p.add_argument("--max-depth", type=int, default=None)
|
||||
p.add_argument("--quiet", "-q", action="store_true", help="Do not warn about shape.")
|
||||
args = p.parse_args(argv)
|
||||
|
||||
try:
|
||||
data = json.loads(args.ir.read_text())
|
||||
except (OSError, json.JSONDecodeError) as e:
|
||||
print(f"Error: could not read {args.ir}: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
problems = check(data)
|
||||
if problems:
|
||||
print(f"Error: {args.ir} is not a valid IR ({len(problems)} problem(s)):", file=sys.stderr)
|
||||
for pr in problems[:5]:
|
||||
print(f" {pr}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
try:
|
||||
style = Style.load(args.style, theme=args.theme)
|
||||
except StyleError as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# Aspect ratio is a property of the graph, not of the renderer: a layered
|
||||
# engine puts one dependency level in one row, so the widest level is the
|
||||
# width. Say so before writing the file, because the alternative is finding
|
||||
# out from a 13671pt image — and the fix is never a layout flag, it is a
|
||||
# smaller question.
|
||||
if not args.quiet:
|
||||
sh = shape(data)
|
||||
if sh["widest_level"] > 20 or sh["nodes"] > 60:
|
||||
est = sh["widest_level"] / max(sh["levels"], 1)
|
||||
print(
|
||||
f" note: {sh['nodes']} nodes, {sh['levels']} levels, widest level "
|
||||
f"{sh['widest_level']} — this will render roughly {est:.0f}:1.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
print(
|
||||
" Around 20 nodes is where it stops being a diagram. Try "
|
||||
"`ops --split`,\n `--around <id> --hops 2`, or `--subtree <id>`. "
|
||||
"Layout flags will not fix it.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
if sh["isolated"] > sh["nodes"] // 3:
|
||||
print(
|
||||
f" {sh['isolated']} of {sh['nodes']} nodes have no edges; they are "
|
||||
"laid out side by side.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
|
||||
dot_text = emit(data, style, max_depth=args.max_depth)
|
||||
|
||||
if not args.output:
|
||||
sys.stdout.write(dot_text)
|
||||
return 0
|
||||
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
if args.output.suffix == ".dot":
|
||||
args.output.write_text(dot_text)
|
||||
else:
|
||||
try:
|
||||
args.output.write_bytes(render(dot_text, fmt=args.output.suffix.lstrip(".") or "svg"))
|
||||
except RenderError as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
return 1
|
||||
print(f" {args.style}/{style.theme:6} {args.output}")
|
||||
return 0
|
||||
@@ -1,50 +0,0 @@
|
||||
""" python3 -m docgen.emitters erd <ir.json> [-o out.svg] [--theme dark]"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from ..ir import check
|
||||
from ..style import Style, StyleError
|
||||
from .erd import emit
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
p = argparse.ArgumentParser(prog="python3 -m docgen.emitters erd")
|
||||
p.add_argument("ir", type=Path)
|
||||
p.add_argument("--output", "-o", type=Path)
|
||||
p.add_argument("--style", default="lucid")
|
||||
p.add_argument("--theme", default=None)
|
||||
args = p.parse_args(argv)
|
||||
|
||||
try:
|
||||
data = json.loads(args.ir.read_text())
|
||||
except (OSError, json.JSONDecodeError) as e:
|
||||
print(f"Error: could not read {args.ir}: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
problems = check(data)
|
||||
if problems:
|
||||
print(f"Error: {args.ir} is not a valid IR ({len(problems)} problem(s)):", file=sys.stderr)
|
||||
for pr in problems[:5]:
|
||||
print(f" {pr}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
try:
|
||||
style = Style.load(args.style, theme=args.theme)
|
||||
svg = emit(data, style)
|
||||
except (StyleError, ValueError) as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if args.output:
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.output.write_text(svg)
|
||||
import re
|
||||
m = re.search(r'width="(\d+)pt" height="(\d+)pt"', svg)
|
||||
size = f"{m.group(1)}x{m.group(2)} {int(m.group(1))/int(m.group(2)):.1f}:1" if m else ""
|
||||
print(f" erd/{style.theme:6} {args.output} {size}")
|
||||
else:
|
||||
sys.stdout.write(svg)
|
||||
return 0
|
||||
@@ -1,47 +0,0 @@
|
||||
""" python3 -m docgen.emitters explore <ir.json> -o DIR [--scale 0.55] [--hops 1]"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from ..ir import check
|
||||
from ..style import Style, StyleError
|
||||
from .explore import write
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
p = argparse.ArgumentParser(prog="python3 -m docgen.emitters explore")
|
||||
p.add_argument("ir", type=Path)
|
||||
p.add_argument("--output", "-o", type=Path, required=True, help="Directory.")
|
||||
p.add_argument("--style", default="lucid")
|
||||
p.add_argument("--theme", default=None)
|
||||
p.add_argument("--scale", type=float, default=0.55)
|
||||
p.add_argument("--width", type=int, default=1100)
|
||||
p.add_argument("--hops", type=int, default=1)
|
||||
p.add_argument("--title", default="")
|
||||
args = p.parse_args(argv)
|
||||
|
||||
try:
|
||||
data = json.loads(args.ir.read_text())
|
||||
except (OSError, json.JSONDecodeError) as e:
|
||||
print(f"Error: could not read {args.ir}: {e}", file=sys.stderr)
|
||||
return 1
|
||||
problems = check(data)
|
||||
if problems:
|
||||
print(f"Error: {args.ir} is not a valid IR ({len(problems)}):", file=sys.stderr)
|
||||
for pr in problems[:5]:
|
||||
print(f" {pr}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
try:
|
||||
style = Style.load(args.style, theme=args.theme)
|
||||
path = write(data, style, args.output, scale=args.scale, width=args.width,
|
||||
hops=args.hops, title=args.title)
|
||||
except (StyleError, ValueError) as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
graphs = len(list((args.output / "graphs").glob("*.svg"))) if (args.output / "graphs").exists() else 0
|
||||
print(f" explore {path} {graphs} neighbourhood diagram(s)")
|
||||
return 0
|
||||
@@ -1,43 +0,0 @@
|
||||
""" python3 -m docgen.emitters index <ir.json> [-o out.md|out.json]"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from ..ir import check
|
||||
from .index import to_markdown, to_sidebar
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
p = argparse.ArgumentParser(prog="python3 -m docgen.emitters index")
|
||||
p.add_argument("ir", type=Path)
|
||||
p.add_argument("--output", "-o", type=Path, help=".md for the document, .json for a sidebar.")
|
||||
p.add_argument("--title", default="")
|
||||
args = p.parse_args(argv)
|
||||
|
||||
try:
|
||||
data = json.loads(args.ir.read_text())
|
||||
except (OSError, json.JSONDecodeError) as e:
|
||||
print(f"Error: could not read {args.ir}: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
problems = check(data)
|
||||
if problems:
|
||||
print(f"Error: {args.ir} is not a valid IR ({len(problems)} problem(s)):", file=sys.stderr)
|
||||
for pr in problems[:5]:
|
||||
print(f" {pr}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if args.output and args.output.suffix == ".json":
|
||||
text = json.dumps(to_sidebar(data), indent=2) + "\n"
|
||||
else:
|
||||
text = to_markdown(data, title=args.title)
|
||||
|
||||
if args.output:
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.output.write_text(text)
|
||||
print(f" index {args.output}")
|
||||
else:
|
||||
sys.stdout.write(text)
|
||||
return 0
|
||||
@@ -1,50 +0,0 @@
|
||||
""" python3 -m docgen.emitters minimap <ir.json> [-o out.svg] [--scale 0.55]"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from ..ir import check
|
||||
from ..style import Style, StyleError
|
||||
from .minimap import emit
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
p = argparse.ArgumentParser(prog="python3 -m docgen.emitters minimap")
|
||||
p.add_argument("ir", type=Path)
|
||||
p.add_argument("--output", "-o", type=Path)
|
||||
p.add_argument("--style", default="lucid")
|
||||
p.add_argument("--theme", default=None)
|
||||
p.add_argument("--scale", type=float, default=0.55, help="Pixels per source line.")
|
||||
p.add_argument("--width", type=int, default=1180, help="Wrap a shelf past this.")
|
||||
args = p.parse_args(argv)
|
||||
|
||||
try:
|
||||
data = json.loads(args.ir.read_text())
|
||||
except (OSError, json.JSONDecodeError) as e:
|
||||
print(f"Error: could not read {args.ir}: {e}", file=sys.stderr)
|
||||
return 1
|
||||
problems = check(data)
|
||||
if problems:
|
||||
print(f"Error: {args.ir} is not a valid IR ({len(problems)}):", file=sys.stderr)
|
||||
for pr in problems[:5]:
|
||||
print(f" {pr}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
try:
|
||||
style = Style.load(args.style, theme=args.theme)
|
||||
svg = emit(data, style, scale=args.scale, target_width=args.width)
|
||||
except (StyleError, ValueError) as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if args.output:
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.output.write_text(svg)
|
||||
m = re.search(r'width="(\d+)pt" height="(\d+)pt"', svg)
|
||||
print(f" minimap {args.output} {m.group(1)}x{m.group(2)}" if m else "")
|
||||
else:
|
||||
sys.stdout.write(svg)
|
||||
return 0
|
||||
@@ -1,73 +0,0 @@
|
||||
""" python3 -m docgen.emitters notebook <ir.json> [-o out.ipynb] [--overlay f.json]
|
||||
|
||||
--spec-out FILE write the generated spec (the base), for reading/diffing
|
||||
--scaffold FILE write a blank overlay listing every step id
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from ..ir import check
|
||||
from ..notebook import dump, from_ir, merge, scaffold
|
||||
from .notebook import emit
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
p = argparse.ArgumentParser(prog="python3 -m docgen.emitters notebook")
|
||||
p.add_argument("ir", type=Path)
|
||||
p.add_argument("--output", "-o", type=Path)
|
||||
p.add_argument("--overlay", type=Path, help="Hand-written additions, re-applied.")
|
||||
p.add_argument("--spec-out", type=Path, help="Write the generated spec too.")
|
||||
p.add_argument("--scaffold", type=Path, help="Write a blank overlay and stop.")
|
||||
p.add_argument("--base-url", default="https://api.example.invalid")
|
||||
args = p.parse_args(argv)
|
||||
|
||||
try:
|
||||
data = json.loads(args.ir.read_text())
|
||||
except (OSError, json.JSONDecodeError) as e:
|
||||
print(f"Error: could not read {args.ir}: {e}", file=sys.stderr)
|
||||
return 1
|
||||
problems = check(data)
|
||||
if problems:
|
||||
print(f"Error: {args.ir} is not a valid IR ({len(problems)}):", file=sys.stderr)
|
||||
for pr in problems[:5]:
|
||||
print(f" {pr}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
base = from_ir(data, base_url=args.base_url)
|
||||
|
||||
if args.scaffold:
|
||||
dump(scaffold(base), args.scaffold)
|
||||
print(f" overlay {args.scaffold} {len(base['steps'])} step(s), none filled in")
|
||||
return 0
|
||||
|
||||
overlay = None
|
||||
if args.overlay:
|
||||
if args.overlay.exists():
|
||||
overlay = json.loads(args.overlay.read_text())
|
||||
else:
|
||||
print(f" note: no overlay at {args.overlay} — generating the base only",
|
||||
file=sys.stderr)
|
||||
|
||||
spec, drift = merge(base, overlay)
|
||||
for d in drift:
|
||||
# The base moved under the overlay. Worth saying out loud; not a reason
|
||||
# to refuse to build the document.
|
||||
print(f" drift: {d}", file=sys.stderr)
|
||||
|
||||
if args.spec_out:
|
||||
dump(spec, args.spec_out)
|
||||
print(f" spec {args.spec_out}")
|
||||
|
||||
text = emit(spec)
|
||||
if args.output:
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.output.write_text(text)
|
||||
n = len(json.loads(text)["cells"])
|
||||
extra = f", {len(drift)} drift" if drift else ""
|
||||
print(f" notebook {args.output} {len(spec['steps'])} steps, {n} cells{extra}")
|
||||
else:
|
||||
sys.stdout.write(text)
|
||||
return 0
|
||||
@@ -1,73 +0,0 @@
|
||||
""" python3 -m docgen.emitters site <ir.json> -o DIR [--theme lucid]
|
||||
|
||||
Writes index.html, viewer.html, site.css and the graph — self-contained, offline.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from ..ir import check
|
||||
from ..ops import classify
|
||||
from ..style import Style, StyleError
|
||||
from .site import write
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
p = argparse.ArgumentParser(prog="python3 -m docgen.emitters site")
|
||||
p.add_argument("ir", type=Path)
|
||||
p.add_argument("--output", "-o", type=Path, required=True, help="Directory.")
|
||||
p.add_argument("--style", default="lucid")
|
||||
p.add_argument("--theme", default=None)
|
||||
p.add_argument("--title", default="")
|
||||
p.add_argument("--no-graph", action="store_true")
|
||||
args = p.parse_args(argv)
|
||||
|
||||
try:
|
||||
data = json.loads(args.ir.read_text())
|
||||
except (OSError, json.JSONDecodeError) as e:
|
||||
print(f"Error: could not read {args.ir}: {e}", file=sys.stderr)
|
||||
return 1
|
||||
problems = check(data)
|
||||
if problems:
|
||||
print(f"Error: {args.ir} is not a valid IR ({len(problems)}):", file=sys.stderr)
|
||||
for pr in problems[:5]:
|
||||
print(f" {pr}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
try:
|
||||
style = Style.load(args.style, theme=args.theme)
|
||||
except StyleError as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
args.output.mkdir(parents=True, exist_ok=True)
|
||||
graph_name = None
|
||||
if not args.no_graph:
|
||||
# Whatever the structure asks for, so the page carries the right picture.
|
||||
verdict = classify(data)
|
||||
if verdict["emitter"] == "erd":
|
||||
from .erd import emit as draw
|
||||
(args.output / "graph.svg").write_text(draw(data, style))
|
||||
graph_name = "graph.svg"
|
||||
elif verdict["emitter"] == "dot":
|
||||
from .dot import emit as dot_emit, have_graphviz, render
|
||||
if have_graphviz():
|
||||
opts = verdict.get("options") or {}
|
||||
(args.output / "graph.svg").write_bytes(
|
||||
render(dot_emit(data, style, rankdir=opts.get("rankdir")))
|
||||
)
|
||||
graph_name = "graph.svg"
|
||||
else:
|
||||
print(" note: graphviz absent — the site is text only", file=sys.stderr)
|
||||
else:
|
||||
print(f" note: {verdict['kind']} — {verdict['why']}", file=sys.stderr)
|
||||
print(" no diagram on the page; the index is the artifact", file=sys.stderr)
|
||||
|
||||
files = write(data, style, args.output, graph=graph_name, title=args.title)
|
||||
for f in files:
|
||||
print(f" site {f}")
|
||||
if graph_name:
|
||||
print(f" site {args.output / graph_name}")
|
||||
return 0
|
||||
@@ -13,8 +13,8 @@ for positions, or re-deriving containment from edges. It is not, because
|
||||
`parent` is containment and `kind` is meaning, and that is all a table of
|
||||
contents needs.
|
||||
|
||||
python3 -m docgen.emitters index ir.json # markdown to stdout
|
||||
python3 -m docgen.emitters index ir.json -o x.json # sidebar JSON
|
||||
python3 -m docgen emit index ir.json # markdown to stdout
|
||||
python3 -m docgen emit index ir.json -o x.json # sidebar JSON
|
||||
|
||||
## What it reports that a diagram cannot
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
""" python3 -m docgen.extractors <db|openapi|usage|code> [options]"""
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
argv = sys.argv[1:] if argv is None else argv
|
||||
if argv and argv[0] == "openapi":
|
||||
from .openapi_main import main as run
|
||||
return run(argv[1:])
|
||||
if argv and argv[0] == "code":
|
||||
from .code_main import main as run
|
||||
return run(argv[1:])
|
||||
if argv and argv[0] == "usage":
|
||||
from .usage_main import main as run
|
||||
return run(argv[1:])
|
||||
if argv and argv[0] == "db":
|
||||
from .db_main import main as run
|
||||
return run(argv[1:])
|
||||
from .db_main import main as run # bare form stays the db one, as before
|
||||
return run(argv)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
Source in several languages -> IR structure, via **tree-sitter**.
|
||||
|
||||
python3 -m docgen.extractors code --root src/ --lang auto -o ir.json
|
||||
python3 -m docgen extract code --root src/ -o ir.json
|
||||
|
||||
Adopts a parser rather than writing one, which is the rule the brief sets and
|
||||
the reason this handles generics, strings containing braces, nested types and
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
""" python3 -m docgen.extractors code --root src/ [--ext .cs] [-o ir.json]"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
p = argparse.ArgumentParser(prog="python3 -m docgen.extractors code")
|
||||
p.add_argument("--root", "-s", required=True, type=Path)
|
||||
p.add_argument("--output", "-o", type=Path)
|
||||
p.add_argument("--ext", action="append", default=[],
|
||||
help="Limit to these extensions. Default: every registered one.")
|
||||
p.add_argument("--exclude", action="append", default=[])
|
||||
args = p.parse_args(argv)
|
||||
|
||||
from .code import LANGUAGES, MissingParser, extract
|
||||
|
||||
try:
|
||||
ir = extract(args.root, suffixes=args.ext or None, exclude=tuple(args.exclude))
|
||||
except MissingParser as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
return 1
|
||||
except (NotADirectoryError, OSError) as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
text = json.dumps(ir.to_dict(), indent=2) + "\n"
|
||||
if args.output:
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.output.write_text(text)
|
||||
from collections import Counter
|
||||
c = Counter(n.kind for n in ir.nodes)
|
||||
print(f"{len(ir.nodes)} nodes -> {args.output} "
|
||||
+ " · ".join(f"{v} {k}" for k, v in sorted(c.items(), key=lambda kv: -kv[1])))
|
||||
else:
|
||||
sys.stdout.write(text)
|
||||
return 0
|
||||
@@ -9,7 +9,7 @@ reading it means this extractor works for every source modelgen supports
|
||||
(Django, SQLAlchemy, OpenAPI, CSV/ODS, a live database) without knowing about
|
||||
any of them.
|
||||
|
||||
python3 -m docgen.extractors.db --schema cfg/sample/.../graphgen/schema.json
|
||||
python3 -m docgen extract db --schema cfg/sample/.../graphgen/schema.json
|
||||
|
||||
Connecting to a live database is **not here**. `modelgen from-db --url ...`
|
||||
reflects via SQLAlchemy's Inspector across dialects and writes the schema.json
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
""" python3 -m docgen.extractors.db --schema path/to/schema.json [-o ir.json]"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from .db import extract
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
p = argparse.ArgumentParser(prog="python3 -m docgen.extractors.db")
|
||||
p.add_argument("--schema", "-s", required=True, type=Path,
|
||||
help="A graphgen-compatible schema.json, as modelgen emits.")
|
||||
p.add_argument("--output", "-o", type=Path)
|
||||
args = p.parse_args(argv)
|
||||
|
||||
try:
|
||||
ir = extract(args.schema)
|
||||
except (OSError, json.JSONDecodeError, KeyError) as e:
|
||||
print(f"Error: could not read {args.schema}: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
text = json.dumps(ir.to_dict(), indent=2) + "\n"
|
||||
if args.output:
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.output.write_text(text)
|
||||
print(f"{len(ir.nodes)} nodes, {len(ir.edges)} edges -> {args.output}")
|
||||
else:
|
||||
sys.stdout.write(text)
|
||||
return 0
|
||||
@@ -5,7 +5,7 @@ Adapts `modelgen/loader/extract/openapi.py`, which already parses OpenAPI 3.x
|
||||
and Swagger 2.0 and resolves `$ref`. This turns its output into IR nodes; it
|
||||
does not re-parse anything.
|
||||
|
||||
python3 -m docgen.extractors.openapi --spec petstore.yaml -o ir.json
|
||||
python3 -m docgen extract openapi --spec petstore.yaml -o ir.json
|
||||
|
||||
## Why this one matters more than it looks
|
||||
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
""" python3 -m docgen.extractors.openapi --spec petstore.yaml [-o ir.json]"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
p = argparse.ArgumentParser(prog="python3 -m docgen.extractors.openapi")
|
||||
p.add_argument("--spec", "-s", required=True, type=Path)
|
||||
p.add_argument("--output", "-o", type=Path)
|
||||
args = p.parse_args(argv)
|
||||
from .openapi import extract
|
||||
|
||||
try:
|
||||
ir = extract(args.spec)
|
||||
except (OSError, ImportError, ValueError) as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
return 1
|
||||
text = json.dumps(ir.to_dict(), indent=2) + "\n"
|
||||
if args.output:
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.output.write_text(text)
|
||||
eps = sum(1 for n in ir.nodes if n.kind == "endpoint")
|
||||
print(f"{len(ir.nodes)} nodes ({eps} endpoints), {len(ir.edges)} edges -> {args.output}")
|
||||
else:
|
||||
sys.stdout.write(text)
|
||||
return 0
|
||||
@@ -1,37 +0,0 @@
|
||||
""" python3 -m docgen.extractors.python --root PATH [--exclude NAME ...]"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from . import extract
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
p = argparse.ArgumentParser(prog="python3 -m docgen.extractors.python")
|
||||
p.add_argument("--root", "-s", required=True, type=Path, help="Tree to read.")
|
||||
p.add_argument("--output", "-o", type=Path, help="Where to write. Default stdout.")
|
||||
p.add_argument("--exclude", action="append", default=[], help="Directory name to skip.")
|
||||
args = p.parse_args(argv)
|
||||
|
||||
try:
|
||||
ir = extract(args.root, exclude=tuple(args.exclude))
|
||||
except (NotADirectoryError, OSError) as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
text = json.dumps(ir.to_dict(), indent=2) + "\n"
|
||||
if args.output:
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.output.write_text(text)
|
||||
skipped = sum(1 for n in ir.nodes if n.attrs.get("error"))
|
||||
print(f"{len(ir.nodes)} nodes, {len(ir.edges)} edges -> {args.output}"
|
||||
+ (f" ({skipped} file(s) unparsed)" if skipped else ""))
|
||||
else:
|
||||
sys.stdout.write(text)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -5,7 +5,7 @@ Reads a **HAR** file — the format browser devtools, mitmproxy, Charles and
|
||||
Insomnia all export. Standard, JSON, stdlib-parseable, and already sitting on
|
||||
most people's disk after ten minutes of using the thing they want documented.
|
||||
|
||||
python3 -m docgen.extractors usage --har session.har -o ir.json
|
||||
python3 -m docgen extract usage --har session.har -o ir.json
|
||||
|
||||
## Why this exists
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
""" python3 -m docgen.extractors usage --har session.har [-o ir.json]"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
p = argparse.ArgumentParser(prog="python3 -m docgen.extractors usage")
|
||||
p.add_argument("--har", "-s", required=True, type=Path,
|
||||
help="A HAR recording, as devtools/mitmproxy/Charles export.")
|
||||
p.add_argument("--output", "-o", type=Path)
|
||||
args = p.parse_args(argv)
|
||||
from .usage import extract
|
||||
|
||||
try:
|
||||
ir = extract(args.har)
|
||||
except (OSError, json.JSONDecodeError, KeyError) as e:
|
||||
print(f"Error: could not read {args.har}: {e}", file=sys.stderr)
|
||||
return 1
|
||||
text = json.dumps(ir.to_dict(), indent=2) + "\n"
|
||||
if args.output:
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.output.write_text(text)
|
||||
eps = sum(1 for n in ir.nodes if n.kind == "endpoint")
|
||||
ops = sum(1 for n in ir.nodes if n.kind == "operation")
|
||||
print(f"{len(ir.nodes)} nodes ({eps} endpoints, {ops} graphql), "
|
||||
f"{len(ir.edges)} sequence edges -> {args.output}")
|
||||
else:
|
||||
sys.stdout.write(text)
|
||||
return 0
|
||||
12
soleprint/atlas2/docgen/fixtures/shop.json
Normal file
12
soleprint/atlas2/docgen/fixtures/shop.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"source": "postgresql",
|
||||
"models": {
|
||||
"users": {"doc": "People who buy.", "fields": {"id": {"type": "int", "pk": true}, "email": {"type": "str"}}},
|
||||
"orders": {"doc": "One purchase.", "fields": {"id": {"type": "int", "pk": true}, "user": {"type": "FK:users"}, "total": {"type": "float"}}},
|
||||
"items": {"doc": "A line on an order.", "fields": {"id": {"type": "int", "pk": true}, "order": {"type": "FK:orders"}, "sku": {"type": "str"}}}
|
||||
},
|
||||
"relationships": [
|
||||
{"from": "orders", "to": "users", "from_field": "user"},
|
||||
{"from": "items", "to": "orders", "from_field": "order"}
|
||||
]
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
""" python3 -m docgen.ir <ir.json> — validate a document at the boundary."""
|
||||
|
||||
import sys
|
||||
|
||||
from .validate import main
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -5,7 +5,7 @@ Called wherever the IR crosses between layers: after an extractor writes one,
|
||||
before an emitter reads one. That is the whole point of having one format — the
|
||||
check is in one place instead of every consumer defending itself.
|
||||
|
||||
python3 -m docgen.ir path/to/ir.json
|
||||
python3 -m docgen validate path/to/ir.json
|
||||
|
||||
Stdlib only. This is not a general JSON Schema engine and does not want to be;
|
||||
it reads the field lists **out of `schema.json`** so the two cannot drift, then
|
||||
@@ -23,7 +23,6 @@ that produce a broken diagram.
|
||||
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
@@ -276,37 +275,3 @@ def check_model_matches_schema() -> list[str]:
|
||||
for extra in actual - declared:
|
||||
problems.append(f"{cls.__name__} has {extra!r}; schema does not declare it")
|
||||
return problems
|
||||
|
||||
|
||||
def main(argv=None) -> int:
|
||||
argv = sys.argv[1:] if argv is None else argv
|
||||
if not argv:
|
||||
print("usage: python3 -m docgen.ir <ir.json>", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
drift = check_model_matches_schema()
|
||||
if drift:
|
||||
print("model.py and schema.json disagree:", file=sys.stderr)
|
||||
for d in drift:
|
||||
print(f" {d}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
path = Path(argv[0])
|
||||
try:
|
||||
data = json.loads(path.read_text())
|
||||
except (OSError, json.JSONDecodeError) as e:
|
||||
print(f"Error: could not read {path}: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
problems = check(data)
|
||||
if problems:
|
||||
print(f"{path}: {len(problems)} problem(s)", file=sys.stderr)
|
||||
for p in problems:
|
||||
print(f" {p}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
print(
|
||||
f"{path}: ok — {len(data['nodes'])} nodes, {len(data['edges'])} edges, "
|
||||
f"schema v{data['meta'].get('schema_version')}"
|
||||
)
|
||||
return 0
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Views over the IR. Filtering is not an emitter concern — it belongs here, once,
|
||||
so the index, the diagram and the diff all narrow the same way.
|
||||
|
||||
python3 -m docgen.ops ir.json --drop-stdlib --only class -o smaller.json
|
||||
python3 -m docgen view ir.json --drop-stdlib --only class -o smaller.json
|
||||
"""
|
||||
|
||||
from .filter import (
|
||||
|
||||
32
soleprint/atlas2/docgen/pyproject.toml
Normal file
32
soleprint/atlas2/docgen/pyproject.toml
Normal file
@@ -0,0 +1,32 @@
|
||||
[project]
|
||||
name = "docgen"
|
||||
version = "0.2.0"
|
||||
description = "Source artifacts into one graph IR, then into diagrams, indexes, notebooks and sites"
|
||||
readme = "README.md"
|
||||
# 3.11 for tomllib, which reads run files. Nothing else needs more than 3.10.
|
||||
requires-python = ">=3.11"
|
||||
# None. The whole structural path — extraction, the IR, views, every emitter but
|
||||
# the rendered diagram, the book and its checks — is the stdlib. Everything below
|
||||
# is optional, and the suite skips rather than fails without it.
|
||||
dependencies = []
|
||||
|
||||
[dependency-groups]
|
||||
# C# and TypeScript, through tree-sitter. Python never needs it: it uses `ast`.
|
||||
code = [
|
||||
"tree-sitter>=0.23",
|
||||
"tree-sitter-c-sharp>=0.23",
|
||||
"tree-sitter-typescript>=0.23",
|
||||
"tree-sitter-python>=0.23",
|
||||
]
|
||||
# Harvesting a theme from exported SVG/PDF diagrams (style/extract.py).
|
||||
harvest = ["lxml>=5.0"]
|
||||
# Reading OpenAPI. Also needs the reference repo's modelgen — see reference.py.
|
||||
openapi = ["pyyaml>=6.0"]
|
||||
# Sanctioned experiments in lab/. Nothing outside lab/ imports it.
|
||||
lab = ["networkx>=3.2"]
|
||||
|
||||
[tool.uv]
|
||||
# A folder of modules run in place, not an installable package — the same choice
|
||||
# dataconvert makes. Copy the folder anywhere and it still works; the lock pins
|
||||
# what the optional groups resolve to.
|
||||
package = false
|
||||
@@ -87,6 +87,17 @@ FIXTURE = {
|
||||
}
|
||||
|
||||
|
||||
|
||||
# docgen's own Python — what a source scan should read. Not `HERE.rglob`: once
|
||||
# `make sync` has run, `.venv/` under this folder holds thousands of third-party
|
||||
# modules, and the standalone check reported lxml's own imports as docgen's.
|
||||
NOT_OURS = {"__pycache__", ".venv", "venv", "node_modules", "out"}
|
||||
|
||||
|
||||
def own_py_files():
|
||||
return sorted(p for p in HERE.rglob("*.py")
|
||||
if not NOT_OURS & set(p.relative_to(HERE).parts))
|
||||
|
||||
def check(name, condition, detail=""):
|
||||
(PASS if condition else FAIL).append(name)
|
||||
print(f" {'ok ' if condition else 'FAIL'} {name}"
|
||||
@@ -1875,7 +1886,7 @@ def _standalone():
|
||||
|
||||
stdlib = set(sys.stdlib_module_names)
|
||||
own = {PKG}
|
||||
files = sorted(p for p in HERE.rglob("*.py") if "__pycache__" not in p.parts)
|
||||
files = own_py_files()
|
||||
|
||||
foreign, seam_leaks = [], []
|
||||
for path in files:
|
||||
@@ -2005,6 +2016,309 @@ def _standalone():
|
||||
_standalone()
|
||||
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
print("\n17. one command line, and library code that has none")
|
||||
|
||||
|
||||
def _layout():
|
||||
"""Library packages hold library code; the command line lives in cli/.
|
||||
|
||||
The rule exists because two kinds of file in one folder — `cli_dot.py` next
|
||||
to `dot.py` — make every folder answer two questions, and the command-line
|
||||
half is the half that grows copies. It decays by accretion: one convenient
|
||||
`argparse` in a library module and the split is gone. So it is read from the
|
||||
source rather than trusted.
|
||||
"""
|
||||
cli_mod = __import__(f"{PKG}.cli", fromlist=["*"])
|
||||
|
||||
# Where command-line code may live. lab/ is sanctioned experiments, and the
|
||||
# suite is itself a script.
|
||||
allowed = {"cli", "lab"}
|
||||
offenders = []
|
||||
for path in own_py_files():
|
||||
rel = path.relative_to(HERE)
|
||||
if rel.parts[0] in allowed or rel.as_posix() in ("__main__.py", "selftest.py"):
|
||||
continue
|
||||
tree = ast.parse(path.read_text())
|
||||
for node in ast.walk(tree):
|
||||
names = []
|
||||
if isinstance(node, ast.Import):
|
||||
names = [a.name for a in node.names]
|
||||
elif isinstance(node, ast.ImportFrom) and not node.level:
|
||||
names = [node.module or ""]
|
||||
if "argparse" in names:
|
||||
offenders.append(rel.as_posix())
|
||||
check(
|
||||
"nothing outside cli/ parses a command line",
|
||||
not offenders,
|
||||
f"{sorted(set(offenders))} import argparse — command-line code belongs in cli/",
|
||||
)
|
||||
|
||||
stray = sorted(
|
||||
p.relative_to(HERE).as_posix() for p in own_py_files()
|
||||
if (p.name == "__main__.py" and p.parent != HERE)
|
||||
or p.name.startswith("cli_") or p.stem.endswith("_main")
|
||||
)
|
||||
check(
|
||||
"one entry point — no __main__.py, cli_*.py or *_main.py in the packages",
|
||||
not stray,
|
||||
f"found {stray}",
|
||||
)
|
||||
|
||||
missing = []
|
||||
for name, (module, _) in cli_mod.COMMANDS.items():
|
||||
try:
|
||||
mod = __import__(f"{PKG}.cli.{module}", fromlist=["*"])
|
||||
except ImportError as e:
|
||||
missing.append(f"{name}: {e}")
|
||||
continue
|
||||
if not callable(getattr(mod, "main", None)):
|
||||
missing.append(f"{name}: no main()")
|
||||
check("every listed command has a module with main()", not missing, "; ".join(missing))
|
||||
|
||||
# How a failure reaches the user is part of the interface: one line on
|
||||
# stderr, exit 1, never a traceback. Run as a real process, the way a shell
|
||||
# or a Makefile sees it.
|
||||
env = dict(__import__("os").environ, PYTHONPATH=str(HERE.parent))
|
||||
run = lambda *a: _sub.run([sys.executable, "-m", PKG, *a], capture_output=True,
|
||||
text=True, env=env)
|
||||
bare = run()
|
||||
check("with no command it prints the commands and exits 2",
|
||||
bare.returncode == 2 and "emit" in bare.stdout and "run" in bare.stdout,
|
||||
f"exit {bare.returncode}")
|
||||
bad = run("validate", str(Path(tmp.name) / "no-such.json"))
|
||||
check(
|
||||
"an expected failure is one line on stderr, exit 1, no traceback",
|
||||
bad.returncode == 1 and bad.stderr.startswith("Error:")
|
||||
and "Traceback" not in bad.stderr and bad.stderr.count("\n") == 1,
|
||||
f"exit {bad.returncode}: {bad.stderr[:120]!r}",
|
||||
)
|
||||
|
||||
# The structure-picks-the-drawing branch used to be written three times —
|
||||
# the `auto` command, the `site` command, the book. Now it is `draw()`, and
|
||||
# the book reaching past it to the concrete emitters would be the first copy.
|
||||
# Parsed, not grepped, for the reason section 2 gives: the docstring naming
|
||||
# `emitters.dot` is prose, and the first version of this check failed on it.
|
||||
imported = set()
|
||||
for node in ast.walk(ast.parse((HERE / "book" / "build.py").read_text())):
|
||||
if isinstance(node, ast.ImportFrom) and node.module:
|
||||
imported |= {f"{node.module}.{a.name}" for a in node.names}
|
||||
check(
|
||||
"the book chooses its drawing through draw(), not by hand",
|
||||
"emitters.auto.draw" in imported
|
||||
and not any(m.startswith(("emitters.erd", "emitters.dot")) for m in imported),
|
||||
f"imports {sorted(m for m in imported if m.startswith('emitters'))}",
|
||||
)
|
||||
|
||||
|
||||
_layout()
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
print("\n18. run files — every book, rebuilt with one command")
|
||||
|
||||
|
||||
def _runfiles():
|
||||
cfg = __import__(f"{PKG}.book.config", fromlist=["*"])
|
||||
build_mod = __import__(f"{PKG}.book.build", fromlist=["*"])
|
||||
ref_mod = __import__(f"{PKG}.reference", fromlist=["*"])
|
||||
import os as _os
|
||||
|
||||
base = Path(tmp.name) / "runfiles"
|
||||
(base / "src" / "app").mkdir(parents=True, exist_ok=True)
|
||||
(base / "src" / "app" / "__init__.py").write_text('"""App."""\n')
|
||||
(base / "src" / "app" / "models.py").write_text('"""Models."""\n\n\nclass User:\n pass\n')
|
||||
(base / "shop.json").write_text((HERE / "fixtures" / "shop.json").read_text())
|
||||
|
||||
def write(text, name="docgen.toml"):
|
||||
path = base / name
|
||||
path.write_text(text)
|
||||
return path
|
||||
|
||||
def problems(text):
|
||||
try:
|
||||
cfg.load(write(text, "bad.toml"))
|
||||
except cfg.ConfigError as e:
|
||||
return e.problems
|
||||
return []
|
||||
|
||||
example = cfg.load(HERE / "docgen.example.toml")
|
||||
check(
|
||||
"the shipped example loads",
|
||||
[b.name for b in example.books] == ["extractors", "schema", "api"],
|
||||
f"got {[b.name for b in example.books]}",
|
||||
)
|
||||
|
||||
good = write(
|
||||
'[defaults]\nout = "books"\nexclude = ["vendor"]\n\n'
|
||||
'[[book]]\nname = "app"\nroot = "src"\n\n'
|
||||
'[[book]]\nname = "shop"\nschema = "shop.json"\n\n'
|
||||
'[[book]]\nname = "narrow"\nroot = "src/app"\nout = "elsewhere/narrow"\nexclude = []\n'
|
||||
)
|
||||
# Relative to the FILE. Loaded from another working directory, a run file
|
||||
# that resolved against cwd would build different books from the same text.
|
||||
previous = _os.getcwd()
|
||||
try:
|
||||
_os.chdir(Path(tmp.name))
|
||||
rf = cfg.load(good)
|
||||
finally:
|
||||
_os.chdir(previous)
|
||||
by = {b.name: b for b in rf.books}
|
||||
check(
|
||||
"paths resolve against the run file, not the working directory",
|
||||
by["app"].source == base / "src" and by["app"].out == base / "books" / "app",
|
||||
f"source {by['app'].source}, out {by['app'].out}",
|
||||
)
|
||||
check("a book's own out overrides <defaults.out>/<name>",
|
||||
by["narrow"].out == base / "elsewhere" / "narrow")
|
||||
check(
|
||||
"a book's value replaces the default — exclude included, no merging",
|
||||
by["app"].exclude == ("vendor",) and by["narrow"].exclude == (),
|
||||
f"app {by['app'].exclude}, narrow {by['narrow'].exclude}",
|
||||
)
|
||||
check(
|
||||
"an inherited exclude does not apply to a non-tree source, and is not an error",
|
||||
by["shop"].exclude == () and by["shop"].kind == "db",
|
||||
)
|
||||
|
||||
# Refused, not ignored — and every problem at once, not the first.
|
||||
found = problems(
|
||||
'colour = "red"\n[defaults]\nstyel = "x"\n\n'
|
||||
'[[book]]\nname = "a"\nroot = "src"\nexlude = ["x"]\n'
|
||||
)
|
||||
check(
|
||||
"unknown keys are refused at every level, all reported together",
|
||||
len(found) == 3 and all("unknown" in f for f in found),
|
||||
f"got {found}",
|
||||
)
|
||||
check(
|
||||
"a book names exactly one source",
|
||||
any("exactly one source" in f for f in problems(
|
||||
'[[book]]\nname = "a"\nroot = "src"\nschema = "shop.json"\n')),
|
||||
)
|
||||
check(
|
||||
"an explicit exclude on a non-tree source is refused",
|
||||
any("only applies to a root" in f for f in problems(
|
||||
'[[book]]\nname = "a"\nschema = "shop.json"\nexclude = ["x"]\n')),
|
||||
)
|
||||
# The next run would read the last run's output: a rebuild that changes on
|
||||
# every rebuild.
|
||||
check(
|
||||
"a book written inside the tree it reads is refused",
|
||||
any("inside the tree it reads" in f for f in problems(
|
||||
'[[book]]\nname = "a"\nroot = "src"\nout = "src/book"\n')),
|
||||
)
|
||||
check(
|
||||
"two books writing to one directory are refused",
|
||||
any("both write to" in f for f in problems(
|
||||
'[[book]]\nname = "a"\nroot = "src"\nout = "same"\n\n'
|
||||
'[[book]]\nname = "b"\nschema = "shop.json"\nout = "same"\n')),
|
||||
"the second would clear the first on every run, silently",
|
||||
)
|
||||
try:
|
||||
rf.select(["app", "nope"])
|
||||
selected = False
|
||||
except cfg.ConfigError:
|
||||
selected = True
|
||||
check("--only with an unknown name is an error, not an empty run", selected)
|
||||
|
||||
# The caller's env beats the file — rig's precedence rule for every setting.
|
||||
saved = _os.environ.pop(ref_mod.ENV_VAR, None)
|
||||
try:
|
||||
with_ref = cfg.load(write(
|
||||
f'reference = "{base}"\n[[book]]\nname = "a"\nroot = "src"\n', "ref.toml"))
|
||||
check("a run file can name the reference repo",
|
||||
cfg.apply_reference(with_ref) == str(base)
|
||||
and _os.environ.get(ref_mod.ENV_VAR) == str(base))
|
||||
_os.environ[ref_mod.ENV_VAR] = "/from/the/environment"
|
||||
check("but the environment wins over the file",
|
||||
cfg.apply_reference(with_ref) is None
|
||||
and _os.environ[ref_mod.ENV_VAR] == "/from/the/environment")
|
||||
finally:
|
||||
_os.environ.pop(ref_mod.ENV_VAR, None)
|
||||
if saved is not None:
|
||||
_os.environ[ref_mod.ENV_VAR] = saved
|
||||
|
||||
# -- running it ----------------------------------------------------------
|
||||
broken = write(
|
||||
'[[book]]\nname = "app"\nroot = "src"\nout = "run/app"\n\n'
|
||||
'[[book]]\nname = "bad"\nhar = "not-a-har.har"\nout = "run/bad"\n\n'
|
||||
'[[book]]\nname = "shop"\nschema = "shop.json"\nout = "run/shop"\n',
|
||||
"run.toml",
|
||||
)
|
||||
(base / "not-a-har.har").write_text("this is not json")
|
||||
results = {r["name"]: r for r in cfg.run(cfg.load(broken), check=True)}
|
||||
check(
|
||||
"one broken book does not stop the others",
|
||||
results["app"]["ok"] and results["shop"]["ok"]
|
||||
and not results["bad"]["ok"] and results["bad"]["error"],
|
||||
{k: (v["ok"], v["error"]) for k, v in results.items()},
|
||||
)
|
||||
check("each built book passed its own level", not results["app"]["checks_failed"])
|
||||
|
||||
# Rerunning is the point of a run file, so a rerun must not leave the last
|
||||
# run's artifacts beside the new ledger, and must not touch what a person wrote.
|
||||
app = base / "run" / "app"
|
||||
(app / "steps" / "stale.svg").write_text("<svg/>")
|
||||
(app / "checks.py").write_text("def checks(book, check, note, skip):\n pass\n")
|
||||
again = {r["name"]: r for r in cfg.run(cfg.load(broken), ["app"])}
|
||||
check(
|
||||
"a rebuild removes the previous build's outputs",
|
||||
again["app"]["ok"] and not (app / "steps" / "stale.svg").exists(),
|
||||
"a stale graph.svg would go on showing in the site, unlisted in the ledger",
|
||||
)
|
||||
check("...and keeps the hand-written checks.py", (app / "checks.py").exists())
|
||||
|
||||
foreign = base / "not-a-book"
|
||||
foreign.mkdir(exist_ok=True)
|
||||
(foreign / "steps").mkdir(exist_ok=True)
|
||||
(foreign / "site").mkdir(exist_ok=True)
|
||||
check(
|
||||
"clear() never touches a directory it did not write",
|
||||
build_mod.clear(foreign) == [] and (foreign / "steps").exists(),
|
||||
"a mistyped `out` must not delete somebody's `site/`",
|
||||
)
|
||||
|
||||
# -- the environment the lock pins ---------------------------------------
|
||||
import tomllib as _toml
|
||||
project = _toml.loads((HERE / "pyproject.toml").read_text())
|
||||
check(
|
||||
"pyproject declares no required dependencies",
|
||||
project["project"]["dependencies"] == [],
|
||||
"the structural path is the stdlib; everything else is an optional group",
|
||||
)
|
||||
check(
|
||||
"it requires the Python that reads run files",
|
||||
project["project"]["requires-python"] == ">=3.11",
|
||||
"tomllib is 3.11+",
|
||||
)
|
||||
# A module the suite allows docgen to import must be a dependency somebody
|
||||
# can install from the lock, or the allow-list and pyproject have drifted.
|
||||
declared = {d.split(">")[0].split("=")[0].strip().lower().replace("-", "_")
|
||||
for group in project["dependency-groups"].values() for d in group}
|
||||
import_to_dist = {"tree_sitter": "tree_sitter", "tree_sitter_c_sharp": "tree_sitter_c_sharp",
|
||||
"tree_sitter_typescript": "tree_sitter_typescript",
|
||||
"tree_sitter_python": "tree_sitter_python",
|
||||
"lxml": "lxml", "yaml": "pyyaml", "networkx": "networkx"}
|
||||
undeclared = sorted(m for m, dist in import_to_dist.items() if dist not in declared)
|
||||
check("every optional import is a declared dependency group", not undeclared,
|
||||
f"{undeclared} are allowed but not in pyproject")
|
||||
lock = HERE / "uv.lock"
|
||||
locked = set()
|
||||
if lock.exists():
|
||||
locked = {pkg["name"].replace("-", "_")
|
||||
for pkg in _toml.loads(lock.read_text()).get("package", [])}
|
||||
check(
|
||||
"uv.lock pins every declared dependency",
|
||||
lock.exists() and declared <= locked,
|
||||
f"not in the lock: {sorted(declared - locked)} — run `make lock`",
|
||||
)
|
||||
|
||||
|
||||
_runfiles()
|
||||
|
||||
|
||||
print(f"{len(PASS)} passed, {len(FAIL)} failed, {len(SKIP)} skipped")
|
||||
if FAIL:
|
||||
print("\nfailed:")
|
||||
|
||||
321
soleprint/atlas2/docgen/uv.lock
generated
Normal file
321
soleprint/atlas2/docgen/uv.lock
generated
Normal file
@@ -0,0 +1,321 @@
|
||||
version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.11"
|
||||
|
||||
[[package]]
|
||||
name = "docgen"
|
||||
version = "0.2.0"
|
||||
source = { virtual = "." }
|
||||
|
||||
[package.dev-dependencies]
|
||||
code = [
|
||||
{ name = "tree-sitter" },
|
||||
{ name = "tree-sitter-c-sharp" },
|
||||
{ name = "tree-sitter-python" },
|
||||
{ name = "tree-sitter-typescript" },
|
||||
]
|
||||
harvest = [
|
||||
{ name = "lxml" },
|
||||
]
|
||||
lab = [
|
||||
{ name = "networkx" },
|
||||
]
|
||||
openapi = [
|
||||
{ name = "pyyaml" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
code = [
|
||||
{ name = "tree-sitter", specifier = ">=0.23" },
|
||||
{ name = "tree-sitter-c-sharp", specifier = ">=0.23" },
|
||||
{ name = "tree-sitter-python", specifier = ">=0.23" },
|
||||
{ name = "tree-sitter-typescript", specifier = ">=0.23" },
|
||||
]
|
||||
harvest = [{ name = "lxml", specifier = ">=5.0" }]
|
||||
lab = [{ name = "networkx", specifier = ">=3.2" }]
|
||||
openapi = [{ name = "pyyaml", specifier = ">=6.0" }]
|
||||
|
||||
[[package]]
|
||||
name = "lxml"
|
||||
version = "6.1.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/23/ad/28ecd7cb894d172f3c9c80a075eeeb2017ac62e3632cee05a5f9493547eb/lxml-6.1.3.tar.gz", hash = "sha256:45222d94ddd511536f3b2f7d9deae3b2339b4ce0f075f1ca25703b07cad9dd21", size = 4211198, upload-time = "2026-09-02T14:48:02.287Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/96/f1/95133bde7af7afb1f5ba6090b674d826b7a518318bba54bbbb633b27865a/lxml-6.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c66f858b82497173f73366795fc6ee8171620e75a338506d6b2e7bc16f5fca11", size = 8563141, upload-time = "2026-09-02T14:46:42.334Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/80/54/5a79ee2181ac773ee13e48205411845feec69e1c3d097e985c1343171712/lxml-6.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:032a0a97eed428bd143c75a11118238546424ceb2fa311cca5f073aa44658dc4", size = 4613690, upload-time = "2026-09-02T14:46:45.253Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/29/8c24672f56807f119312f073f24204368574bd16b384ede861b5104b3a2b/lxml-6.1.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4a579dfb9c835f8ab47f4b8ed33440cbc75b806b73297208e6ec2a33e903740b", size = 4935630, upload-time = "2026-09-02T14:46:48.071Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/71/69/ce2436d854c848c19fc9287143991f3fc76b8b4e9a0dbba8452e51dff264/lxml-6.1.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:49fbc2682a9306135b7ec49e93f97f9c26689b9b7f96ed2742d8d6497e994d13", size = 5079033, upload-time = "2026-09-02T14:46:50.483Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/ec/b66f66f6499ad800265d57540b51e6632e3232d3526f42f2f8fd4b14e0ea/lxml-6.1.3-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ea2c01cdb16dc12156e455007c406dfaaece0c89aa4ba0e3b47586779f951d41", size = 5012298, upload-time = "2026-09-02T14:46:52.603Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/2a/25d128872f4d51753542bfc3feb482c2ea7c8a2d6d81a0bc5c6a00779ed4/lxml-6.1.3-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:527195c188d7d0af748cd48d220ab8cdc5cb99be3d49ac4d9be7324d8abf9bc0", size = 5211431, upload-time = "2026-09-02T14:46:54.722Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/b2/0a41bbef074a556110f84fafb6d8c2998293c7d3bfbe1ce74515bc65393b/lxml-6.1.3-cp311-cp311-manylinux_2_28_i686.whl", hash = "sha256:20384c2bbcbf87180c8c61eb60869699c1ec0cd09b62cfd13804022d860b0867", size = 5343417, upload-time = "2026-09-02T14:46:57.46Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/cd/16116c3f91791aeeeab1cbe6e7eb6e646f127be7b0158b262eb526a21a0c/lxml-6.1.3-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:424aa5657141d306ba9ad1baab4b2c0a0719040075ee6c66aee9bb2dea2b5054", size = 4673219, upload-time = "2026-09-02T14:46:59.604Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dd/bb/4dff849f443ef70221676aec938bc41e8bae6430aa2ca13b041319e14b98/lxml-6.1.3-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4736e6c87e603146d8949d8501da621ad20c31015060d3fcf95ace2859f3e3e6", size = 5281246, upload-time = "2026-09-02T14:47:02.375Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9f/ac/4aa7dd059420bfd35278c7fe819e9d319ee36a0453b7bbde1907a7832d91/lxml-6.1.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6374e9e382e5a98c9c5e66d41b357b470da1c54bce30f17f9dc4bcc58436cc1c", size = 5055451, upload-time = "2026-09-02T14:47:05.883Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/de/44/20d90cf6f4234de9cd9eeb4f519419885fdb087fa80d073c7b57be342021/lxml-6.1.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:22eec57e26c418cde02c051ce9914a365e52a7f135a565c6f0480242aeebab48", size = 4722694, upload-time = "2026-09-02T14:47:08.461Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/0e/6bee12325e53dd6613fe1e107def07583b6182ade03e94bfef8976622e44/lxml-6.1.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:8753b8d51dbc86fd335ee31fcf7f3658e9f5c016d4edfb23f76ad295f4b8c9d0", size = 5269179, upload-time = "2026-09-02T14:47:10.647Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e4/5d/54d269ce5cd0787c0424d9cef449ee794d4097725d13dd2acd6181c44e9c/lxml-6.1.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:207dfc3d47cf0e575e643bbc140dacc8863b39abaa1e5307cd64c7f2365b8a12", size = 5235559, upload-time = "2026-09-02T14:47:13.932Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e4/f7/5a3095f187f1bec293591616a1677781acc265c5b313c009f8a19c471a09/lxml-6.1.3-cp311-cp311-win32.whl", hash = "sha256:18293f8a8d8b6a8e71ef37706b659e3846a4261232158167b1ddf35f6994f633", size = 3600377, upload-time = "2026-09-02T14:47:15.957Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/45/5a/15531a0d307c96282fe8b639b3d74e8bd783e4ab4cb2b0781146ac4161b8/lxml-6.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:7ae4949f212a53b007dbc355884fda122545c5764a54256c9217e419a62a6559", size = 4032700, upload-time = "2026-09-02T14:47:18.566Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/12/f9/8de76314955545ceaaa7c0305017b8aaa217905dee59c62c0e2c1e44a68f/lxml-6.1.3-cp311-cp311-win_arm64.whl", hash = "sha256:2123e5aa075ac20d23c7af489255efd129cbfe190dbe88fd42598cc9df3199b6", size = 3674431, upload-time = "2026-09-02T14:47:22.186Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dd/1f/a180b57d9eeabaab77f9d5aa30356898ea749c4795596a8f66d1eb6bef2e/lxml-6.1.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c0710ac085a157b593c38fbcacd950f15c4afa8e2057527185875ab302752bc", size = 8602094, upload-time = "2026-09-02T14:47:26.054Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/25/070c92013a1c029a602b03560d68772313d918268667fa993da7961759c9/lxml-6.1.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:623c8799c17128753c65699f1c3aa32402657393a9ad6db09ed8b98ddf76611d", size = 4638308, upload-time = "2026-09-02T14:47:29.587Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/1c/722e88883173097a1a375153e3c2447eba3060d0231522cf6596e99f4195/lxml-6.1.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f683dc6300317700025e41d89a43e0276692ded16113a3c43eab704d605c58e5", size = 4939696, upload-time = "2026-09-02T14:47:32.997Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/db/36/aa413bc214dc4f785ad2b2ddd8cc99aae7062d49ab155e91e6011af00daf/lxml-6.1.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:379f8a75cf6eb7eef0af074b55f49ab73b868388a98de14646abcdfa4564bb11", size = 5105247, upload-time = "2026-09-02T14:47:36.734Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/a0/a1f7f1313795bfec67b77f01ef3b1128d49f2d7f66a8413fa55d47f4e25f/lxml-6.1.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b37772102d44bb6628186accca3a121b1fa3a6b3d97518a8c29a5229ca4c0d0a", size = 5011915, upload-time = "2026-09-02T14:47:39.846Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/78/840e7e3f1d0cc7a5cfac5d8505b97e25b6427fd774ac4bae672aaebfb4b5/lxml-6.1.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ddcf547bea2aee967d6a77779376a45e77e610e8465147a1f3d7e20d539d6e32", size = 5638175, upload-time = "2026-09-02T14:47:43.644Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/20/e022dbc6b4753a9bc9fc5fb28a27163430c1731b9913997f6544c1b2518c/lxml-6.1.3-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:909f4e927bb051f7740d6367285fc60cdcfdaf0258c2dba4ff5ba7eadadc250c", size = 5244675, upload-time = "2026-09-02T14:47:47.635Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/83/82cde81d2b5eb38d1539fdfdf318abdd014a7e604f4df01c9cd3deb18f2a/lxml-6.1.3-cp312-cp312-manylinux_2_28_i686.whl", hash = "sha256:a5c18810318303ce9afb3f95e2ddb54834f96fa699a8600433fd5a93dcf44c56", size = 5358205, upload-time = "2026-09-02T14:47:50.306Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/a1/f3b057371c8cb29f2a9c9c44ea320592446e40b74a4b0af68c3d8e65bc73/lxml-6.1.3-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:3e42265103fb385d8642a78672edf376c6f7e1d3598a7a4f9cb1278f2f6b5f6f", size = 4704495, upload-time = "2026-09-02T14:47:53.251Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/a4/230eb28be5d412152ffc3c679b51fe1aeede5a53f3a8eb6e9748f2f4754f/lxml-6.1.3-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:21402998e4b78e7cce237d2788841aaa21ac9a4d1574d04dc2d12ee41ae807b5", size = 5255117, upload-time = "2026-09-02T14:47:55.963Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/18/1969f56763af24ce42ea156007b0b2d73fddea552e283b2010416394f0f4/lxml-6.1.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:38fc4e4e4e084e0bd491949482527d406788045c546d4f8789e93fc527b91385", size = 5054424, upload-time = "2026-09-02T14:47:58.131Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/d4/2a90acc1f6fabaa3a8db9340437822bd8d041b205d626a4b3e8621aaa390/lxml-6.1.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5609efdb0d3c95499c00046bc53648b3482ec2175b5503d6e611b3f0555dc71d", size = 4785572, upload-time = "2026-09-02T14:48:01.029Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/1e/b90e845b1dcd0f2f3f26b98283d857f25909223aacd265eee032c34ab8b1/lxml-6.1.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:97ce49699d87ebf8aad631b55d65b33219a4f1bfefbbf5bff19dc9af160aeaf9", size = 5656516, upload-time = "2026-09-02T14:48:03.419Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/ab/0a1b802c57f3fba5c4efd77d5c6b78adaa8f7b681f0c90456b140fe8bf6c/lxml-6.1.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:48542c9acba9ff9450bd18d871d2c2c8787fdb283572b623d206f1b927cd7d9e", size = 5245982, upload-time = "2026-09-02T14:48:06.109Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/ee/2c016fbceb3778137459292538d9dfa7e3ad9070fe409c15254ddd90d2cc/lxml-6.1.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c55e71a9b1db1f107efb60da49c093689b74c5c31a708e5379e2fd9439d4fbb5", size = 5267340, upload-time = "2026-09-02T14:48:08.374Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/b1/736d18fd6f0835761923b7bac1f0c27d60c1200384e9093f05d8c5100525/lxml-6.1.3-cp312-cp312-win32.whl", hash = "sha256:b3ff39654f0ce6ebd4db154211136dbe7e8157bcc3bed2344c87f32c7c6ecb6c", size = 3602606, upload-time = "2026-09-02T14:48:10.384Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3a/5b/6ed903e4e6278a020c8a6f0dbbe78030d041840a6b4a64ea441a1e414077/lxml-6.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:3e9a00d1c2c30936f7add097c41afc5da6556c580909104aafd382cac92a855c", size = 4005999, upload-time = "2026-09-02T14:48:12.51Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e4/1b/7bcebb7b6332cb3ae85e9c13b139adb6f23f75c71d84041c56a5005d9a29/lxml-6.1.3-cp312-cp312-win_arm64.whl", hash = "sha256:1aeca87830c4fe649dcf93fe2b059525b71c72587f21be4ae4af7103082a79fa", size = 3666631, upload-time = "2026-09-02T14:48:14.567Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/05/3ef45db776baea068044c799bbba68f3ca00a440c0e930a17c572f3d9639/lxml-6.1.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3a48093cdb058a93af842ede9703520e810b05dcd0fc6d7190a06376c3bfb6bd", size = 8590357, upload-time = "2026-09-02T14:48:17.413Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/a5/eee2fc77eee5ea68e4a4334b1def1781a3beaeefd3d98e81b4a38dc447b7/lxml-6.1.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:887c021d9a977cff89cb273047c1352997b772a8908a25c21836861f69b92be1", size = 4632616, upload-time = "2026-09-02T14:48:20.745Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/35/42/df27b56848acd29d8a720acc28977911aab36f2a09df4208d5502e887415/lxml-6.1.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:611a51e61c92f62345a50b0035df6fc0d678f9299f33728826d831598862f59d", size = 4936186, upload-time = "2026-09-02T14:48:22.94Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/8d/8a7b91df0b54d09d25f5f44885d6b3e0a6d6643a8c070191580318d20c42/lxml-6.1.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b477912f42c5c33405a10c759d22f80cf5af043ae02d95b9d8e5e5bc555739ed", size = 5093324, upload-time = "2026-09-02T14:48:25.132Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/7e/8f340ddcd43790332fb0de8a26628d571a492da3300cd191821698407c96/lxml-6.1.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cffe18571ccc51d742cd08cbb3f8b756de9311d18c7ea98f5d92f37b8fb60c2", size = 4998850, upload-time = "2026-09-02T14:48:27.394Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c5/c1/9c5bb572f1f09ec9e4322bd4a4e9f4ad48347fc56ef94cf4df58a5279dc8/lxml-6.1.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:75cc6569e86be5785b6188ef1642670c6adbc984e81ec35e224842ecd9eefcc8", size = 5626813, upload-time = "2026-09-02T14:48:29.61Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/7d/8bf1fd8bae8247743968bb76d027a1ac5bd2c4b44495fba6a71b30d10706/lxml-6.1.3-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d85dfab42dd672f87a7f76e9de7172962aee69fa12044f0d6e1a23cbd53fb80e", size = 5232385, upload-time = "2026-09-02T14:48:31.969Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/2e/6cef69ed81cb7df0d03b0dd09d08e6e2cf5061a743ff6f42f0b741548e9b/lxml-6.1.3-cp313-cp313-manylinux_2_28_i686.whl", hash = "sha256:42632b4024ab24a6b488f559ac851312509888b6b80ae2aa11cf29a646a0d245", size = 5347088, upload-time = "2026-09-02T14:48:34.13Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/e1/8e5fd8ddc8c7d685badb0f2db149e3c9da84eefc2827c01c658df2c4e3cb/lxml-6.1.3-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:febd35ef45f603c2d74b74655efdbf45e14f55fc0aef4ac82b663ca829b283e0", size = 4707227, upload-time = "2026-09-02T14:48:36.62Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/7e/00041382a11be40a88bf405ebff11c8efabd3de79f2691e1638b1c47a8a0/lxml-6.1.3-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a43b3bdf11e477dc7770609d3477316f974354dfc8425d596f64f471cc8daf6e", size = 5240208, upload-time = "2026-09-02T14:48:38.893Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/fe/316538b5cff0936fa63d45d421c655730fcbb5a28dcac728c175083002bc/lxml-6.1.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d582042c69857c364e8153de6e18e0da9b7b515a6a8113caf69a6ec8e0520f2", size = 5050271, upload-time = "2026-09-02T14:48:41.213Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c9/91/455bcccb3ac725373007344d351151810cd19762d1673b64b811f4359a42/lxml-6.1.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8e49a646acfab83c68974f4aa1d0a2acca9e88d7d627ae0fc13201b14b76d310", size = 4780433, upload-time = "2026-09-02T14:48:43.779Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/f6/580440e2f52cf00bba5c5e1080bfa88cdfcde73be71a11d95170ddbb663f/lxml-6.1.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0dee106e9aa97fb00541b1ed7827070564d0549c3d3fba8920e6b20fd980f748", size = 5645928, upload-time = "2026-09-02T14:48:46.187Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/dc/d123c1f244306543d545f62443f794959e4f1ea709fe100f8740d514e74a/lxml-6.1.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:dd5e90f34cffcfed97f36cf066325773d2b6021c60c29942e53a18b028501b1d", size = 5231184, upload-time = "2026-09-02T14:48:48.691Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c3/3c/fe55b2bd5c6113c906511cd88f6a470195c5fbff1124f19970ab706c3477/lxml-6.1.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d9b3e7d71bf6acff341233417abbdface29c647e3113892d9aaedc02eb4aa2bc", size = 5255814, upload-time = "2026-09-02T14:48:50.948Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e7/a7/485df55acf55dc35e4ca89d2f48f03889e5a3241826b18b85102b32ce9d8/lxml-6.1.3-cp313-cp313-win32.whl", hash = "sha256:160fcf381f76c3aeac28a756bec44f48942a8f7245a87aa28e3a523b4d90cd87", size = 3602214, upload-time = "2026-09-02T14:48:53.236Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/28/e46a7702bd95e9043291f7c3539b6184cba66f96cea9936f20939b284eeb/lxml-6.1.3-cp313-cp313-win_amd64.whl", hash = "sha256:e477aca0bc0d19f3b4ae9e4f2a1cfd687c31bf772d78734910658186b40b2477", size = 4004091, upload-time = "2026-09-02T14:48:55.699Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/1d/154c78e20479a43916e63f19cb720d83f44f024b03228be44c92d9a97b24/lxml-6.1.3-cp313-cp313-win_arm64.whl", hash = "sha256:b1cc980905221a5d8b3c476330730b3adb40ff80add71ffbdb6215ba055656f1", size = 3665468, upload-time = "2026-09-02T14:48:57.703Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/15/fc75a70b0af6021d0ea16811f1fc71cc42cd06ce90fe10f007a69b2eed84/lxml-6.1.3-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:2bec13085dc8ef48a3fe62f7dfcacfeda2c785cdf19cc8eeda2bb9ed081da165", size = 8609725, upload-time = "2026-09-02T14:49:00.156Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/84/ef/398fcf9018f881ec9aeaafae1ddd6586dfb13314a35d35e899de373dcae0/lxml-6.1.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:4f4db7c7e954d289d71878938348b3d91b904a3e8210a11939359fb758a58e7d", size = 4639629, upload-time = "2026-09-02T14:49:02.81Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/2d/49b6a6ad7ce8f64b07b9fe852ff0c6d3fcbb26db61bee4f63d4120180a1c/lxml-6.1.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2cae5d5c90a62d9139c512a0cb1aad1d182b022b5740daea2617eb5bf7fc658e", size = 4965074, upload-time = "2026-09-02T14:49:05.133Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/bc/6230cf80e4331c33383b0b6b73dc31a393dd76edd4cb73d761de5123034d/lxml-6.1.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c6c0c13128a32eb04a51357e56a094e13aa8e6d3d1884de2e9ae923f6915e1a8", size = 5099355, upload-time = "2026-09-02T14:49:07.343Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/cf/d1143d9b7717e07a82f158a1fc9ce6e581fdad1226734950af869e3ffde4/lxml-6.1.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2221e88679d1351e9a40aaee54bc65679b9795bbd0160bc3d5e36b163344eb75", size = 5036795, upload-time = "2026-09-02T14:49:09.65Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/6f/194bb00ffb89712c30f5a7e1b8e685590e140fad6c8261fec172c09a3dc0/lxml-6.1.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cfb398886a7eb4c719161c3efcff2a1248febc53a4d8e5072d2d8a87fed84ac9", size = 5658740, upload-time = "2026-09-02T14:49:11.9Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/44/27e3cee3dcdb3b7bc09727b642bdbfcd098490ea77df04611db9060d7722/lxml-6.1.3-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7eb78ba28b187e1e9203a55c60fcf70df2d22cb205fe6d51b9383d6097419f0", size = 5245991, upload-time = "2026-09-02T14:49:14.154Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/e9/8312560579fc980bbd2233a8a673cc46f7d613d3633f2bf08a21e8f4ad13/lxml-6.1.3-cp314-cp314-manylinux_2_28_i686.whl", hash = "sha256:ea6b1e9105b4b24a34c722432d9fb578f9ed83af21fa1abda639011e0f22bbb6", size = 5354136, upload-time = "2026-09-02T14:49:16.459Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/74/d8/eda60f4f73a9c780b5d6e1175484f66e6c81a2c93346e2906a1fec9c7a02/lxml-6.1.3-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:e8b17e23df3e827a69d25af70990ca2420e92668aaffaeeb3cd2351d7916a023", size = 4704379, upload-time = "2026-09-02T14:49:19.032Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/c8/c9cc60057be78ac34bd2b842e45e6e88edbfe5e532e82c3b82381b7aab49/lxml-6.1.3-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1b7c37339d7e75cab9a123a04248e243cefefb302ad6db566ea0c77cbcde421e", size = 5258676, upload-time = "2026-09-02T14:49:21.306Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/7b/66894008fee8d1785b8db129747ae963fd427b68f456918df7f2f24a8b98/lxml-6.1.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:83e3a51e7933db700a0da0db31849db3a24022d9970da9bb73001e1d0326fd92", size = 5090069, upload-time = "2026-09-02T14:49:23.562Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8b/31/c1b60404859f4c3cd1f41f29c65a24e25cea78fde822d9574a21f66810be/lxml-6.1.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:9bde9ae026a55b9a192078dfa6e27dd0ca4a050171ab6272e92f97b757dfdf48", size = 4741958, upload-time = "2026-09-02T14:49:26.037Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/23/b8/6285f0cf546f14da2554cabdeaf7c2c2ff3190c74807f0de2e8810a786f9/lxml-6.1.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:1a635e837b50a1819bebfedaac5916498ea024120969da8790500148fb0a894d", size = 5683245, upload-time = "2026-09-02T14:49:28.438Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d3/f6/2168cab44336dcb15fed0f0b78577225b83297cdf0dee349c95420c3dcb0/lxml-6.1.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d0c5c362bc94f1929dc7e96e715bbe7bd17037f802e6d8f0d1545df9133c0559", size = 5246087, upload-time = "2026-09-02T14:49:30.955Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f5/89/32f5de69a0a31f30e6164981851f87b37ecb2c4ee838e504b88d49d4818e/lxml-6.1.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c59e4265608da6a041f54646ecc0c9ecdbb19aaf14c4c684bb6c2114998cc415", size = 5269352, upload-time = "2026-09-02T14:49:33.502Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/a1/741d952ed3a7ef7a50055c6415aec3f067015e97f72f4389ce77b09657ba/lxml-6.1.3-cp314-cp314-win32.whl", hash = "sha256:2e62c569ec7531b679b184cbfe335c501c1d13c4b363560013019962eb630e6d", size = 3662783, upload-time = "2026-09-02T14:50:23.751Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/bc/5811cc73cac05e324e05ba9b0924e1a163a317a167ede8a9c748b11db30a/lxml-6.1.3-cp314-cp314-win_amd64.whl", hash = "sha256:66299564c046bc7e0cc5de5106601eae907e9fa5904cd68a323380a8502f7861", size = 4073951, upload-time = "2026-09-02T14:50:26.348Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/18/3768c8b01ac3a9bed1914715e6011711b00e2a11628ffa6f7fa37f8e0269/lxml-6.1.3-cp314-cp314-win_arm64.whl", hash = "sha256:ebd054ad1737a68fb7c5c073d405cef2b88bb824e294de3b4a4e995b47f0e376", size = 3749279, upload-time = "2026-09-02T14:50:28.749Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/72/38/84684784738d9451db2b330de2483f496690c3a5c642071df24135739b37/lxml-6.1.3-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:5a143e6207579de8baeded4eaac9134413200359f1969d636f0bfb98ee8c3c8f", size = 8860296, upload-time = "2026-09-02T14:49:36.346Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/b7/fc4c50bb1b38e864010ea396046cabe85129bf9e65b11edcfbc37d356241/lxml-6.1.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:a1cec0f99b9b914d39176347a93b7610dc09324491aee1cbc57cd291a41a1d55", size = 4755190, upload-time = "2026-09-02T14:49:39.872Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/e2/ee9aa6ed2b666b2db1f6f7fd48964ff9da39ebe827ef5eac0ab881f639d9/lxml-6.1.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f6b9d2aad499c769ee8287609ab0e6de99d8bcea99c6e6c2e64945259fd52fb2", size = 4979517, upload-time = "2026-09-02T14:49:42.153Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/29/e3/e7763d1661b283ddd4fa36f91b9a497db6b8d2aff55028b16c7f642e0755/lxml-6.1.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a23fefdb345b2d4d0ff2860571b5ff9a89a28b6a120f720e8fb0324d346626", size = 5115270, upload-time = "2026-09-02T14:49:44.493Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2d/cd/22205d5b4d177e3f4156f780412426ee7c7f8107809f119f0dcc40fa51e3/lxml-6.1.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:545ccc14fb05485f48b4439ec35beb16d5b5280eb6c81c658bd4707a2a119414", size = 5032449, upload-time = "2026-09-02T14:49:46.841Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/43/06a4626c3bb79ef8c501b674afab8100d64e798665bb2a97d1c960636a49/lxml-6.1.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:93476b6514b373fc6ca67d26c442784f7807c86f00635bfe79f935c3eab2af17", size = 5603325, upload-time = "2026-09-02T14:49:49.664Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/9c/733682a0c2de9f5779ba207bbb3f3f6be8c6bda863fc01739b186b38783a/lxml-6.1.3-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8db38ff3fb7aee7d6a82ae4da2eef1178656fe1216841fbd24870062a9d60473", size = 5229023, upload-time = "2026-09-02T14:49:52.447Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/8a/e69cdaca3fd33a647942925664f01b20908d41a6968c182305be9c38fb11/lxml-6.1.3-cp314-cp314t-manylinux_2_28_i686.whl", hash = "sha256:25f4118c438f96bb466e83108506d03d5c31b1bd2387e83e5b070bda6ded9c37", size = 5317811, upload-time = "2026-09-02T14:49:55.25Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/b2/0c397588174403c2ab68fc464abf97e03e7324f9c6cb6a99023104707195/lxml-6.1.3-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:1beb0f9909b26cee938df9ba56b15252a84429b1fc30ce6fca161390b9789a70", size = 4646516, upload-time = "2026-09-02T14:49:57.761Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/56/7e/cfea25afafbe49db8b225764f7f74bb37c2a7f5e717d917d3d4a5e098ed4/lxml-6.1.3-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3a27ac6c780c8b8a1cd231b58407634cafc1c4cc28cd6c7141362df0f36351e7", size = 5240626, upload-time = "2026-09-02T14:50:00.279Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/75/7a587771bb52ebb0e2c57b6dbe9fd96a70fbb54d72ddd97d54c5f8ec18d5/lxml-6.1.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a1932d7ce78a561367512c594fe66eac2b2ec9b9264cfd9b5f950622f4a116e2", size = 5086619, upload-time = "2026-09-02T14:50:03.245Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/01/94c0ebe6d831861542d251e038052e52bf6d33f1d18f1cfffdc82851065a/lxml-6.1.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:7d0f5976aa2701996f759b30172925829867547bb073af0ae67d1307a0f0262c", size = 4758828, upload-time = "2026-09-02T14:50:05.873Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1f/f1/938d67bd0e5b1fdfa52be28aefdffbad57e1f6b8e921c2aab88542c75f40/lxml-6.1.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e7ce578aa8a80910a72a8ca0bbea3baae10100827249001999726a788456d8", size = 5627083, upload-time = "2026-09-02T14:50:08.555Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/65/4e51522f6c214650db0abb7b16ccd11b1238b8a05a8d59aa4ebed59c9f67/lxml-6.1.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d97c5227621af74b111882a290b10f371780a38eef9d9e730408fba2259b52fb", size = 5235170, upload-time = "2026-09-02T14:50:11.255Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/c2/e73d19365665f6b16ef84df21199befc3b06e4c539046ad2d9595f6fb9ea/lxml-6.1.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:da707f14ea3c35ee463d50acd596d6488e4b2b4ae7cf77a5bf93f55c023d63e8", size = 5252273, upload-time = "2026-09-02T14:50:13.782Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/48/a9/7f386c84c9fe2854e1ca6e231c285e1c8f392971ac353c6865e6ec49faff/lxml-6.1.3-cp314-cp314t-win32.whl", hash = "sha256:9efe56a68179f3adc4de41861c9358931db03837c48dd5e1c78077b84dd07f3a", size = 3902712, upload-time = "2026-09-02T14:50:16.171Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/a6/8a3eb793f7900ef01c7f99e6f5fcbcfbdff35251cfaef66b32a4c16352d6/lxml-6.1.3-cp314-cp314t-win_amd64.whl", hash = "sha256:c9389b3784b56c58d933b5e0aecdf28f901b073ff385358d8a7d40907f6e14b2", size = 4400979, upload-time = "2026-09-02T14:50:18.621Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/c4/3807bea283b4fe9e9d9f5dde46a73df91178472b335d2778e10b2a37aa22/lxml-6.1.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32a409be3190b088f960ac92bfedfbef2f86c49ff940765e1548177592d20026", size = 3823401, upload-time = "2026-09-02T14:50:21.119Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/8e/4614fcd65496054cfb7172662f3576a59200278739506433b8c241ea422a/lxml-6.1.3-cp315-cp315-macosx_10_15_universal2.whl", hash = "sha256:6ea2f13dce778ca072ccee598bca46a092ce192e8fd907b6c1f0e52c800529a0", size = 8609378, upload-time = "2026-09-02T14:50:31.772Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f2/51/2cdce3c65fa99a6195dd8fbd512d33407c1000ad99f63e0a285b63d7a8eb/lxml-6.1.3-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:c581b1d68b3845fb86c6b2983e755b29bf001461c59fa411d2c26a911b6559a9", size = 4640022, upload-time = "2026-09-02T14:50:34.41Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/09/0b30084e9eb1c546a4be3d9c56df70058d116b1a320400a59b0f7da87bf0/lxml-6.1.3-cp315-cp315-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e01125896585139453cab8cb235893644d8815d7509520da95ae3ee8d1c1f79", size = 5037928, upload-time = "2026-09-02T14:50:37.007Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/0e/5c37275a3e361f6138dc06db748ea565c1fe8a5f4ee5e2ddd80047c81a89/lxml-6.1.3-cp315-cp315-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:290f66b97ede0e552e1cb44a0fd8a74f9753ee635b50830a0b122fb72788d015", size = 5661932, upload-time = "2026-09-02T14:50:39.777Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/c5/b71ffb289b15e2642e2a3cf6d468c44da39ea119061a99e5b05e3d10f217/lxml-6.1.3-cp315-cp315-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73fc05988ed20809450474ba760a87c8ad4e455fc09783c02195e56ec634b41a", size = 5249209, upload-time = "2026-09-02T14:50:42.141Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/81/ea/9910da149a23932f9301652e57661cd9e42b0df18f12be21159b7255f92b/lxml-6.1.3-cp315-cp315-manylinux_2_31_armv7l.whl", hash = "sha256:dc3a44689eea43eab836e5c98a8ab015dc2419987d1ea6eafc7c590cdff86bed", size = 4704543, upload-time = "2026-09-02T14:50:44.634Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/07/9290329cd188c62e22021f79df04ee0cc33d9a93b0d38bd65ccd452ad9d0/lxml-6.1.3-cp315-cp315-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:209c3ccbfe35a04ac6d24f0611f9d1cbf8025d49991b14acd935236234d6c156", size = 5261298, upload-time = "2026-09-02T14:50:47.301Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c9/0c/aba78bd3401cd99b73a0aed8e2b9b43e14be94fab3603d4bbc8a62365f2a/lxml-6.1.3-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:2f5b2a2b9811b853b39bfa41367c6d78747b8e3e80e07fc5a24aae295c1a4d7d", size = 5090453, upload-time = "2026-09-02T14:50:49.952Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/dc/fa4426c3355aa0216cbeb3911495b5f65a26e0df85859a89928fe28f0396/lxml-6.1.3-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:6a406d0b3cb207b0fa460ed4dc93e866f44f105da0169361cb18ff998a44c7f0", size = 4744709, upload-time = "2026-09-02T14:50:52.394Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/2b/224fe7918658ab7c532ac2412f3c1eb28f71e6364fb07566262d0cc6a7b6/lxml-6.1.3-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:53258656846f5c48996b882fb4b135885e088a3ad3d96b4bc0530f95124d1f69", size = 5685802, upload-time = "2026-09-02T14:50:55.043Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/44/7d480819b9adcae5f84dd8ac529132c6b7a578544398225cd20321adcd91/lxml-6.1.3-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:aa633613ff907ea91b9b0489a1f0da1b8725d8c6ccec6b77e8a1c9c235044bb0", size = 5249019, upload-time = "2026-09-02T14:50:57.985Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/72/83/385a267ea1b6b283f2249dd827ef360a295e9db14e13ef4665a120c60d64/lxml-6.1.3-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:90f709b9accab6b2e4d14f5c8718203877a0486bcb3afd74d8b539ecd1e961d4", size = 5271886, upload-time = "2026-09-02T14:51:01.667Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/0d/f967b0eb172ae876855a402d6d9b11fa86e3e0c89ca9bbfeadf7ffbfa719/lxml-6.1.3-cp315-cp315-win32.whl", hash = "sha256:b4fc6b03b9d9d90557274f571ab30e7fbbfc527955536935d96f98b6817a86e4", size = 3662894, upload-time = "2026-09-02T14:51:45.173Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/48/d8a8c4160a29e663109ad520bac2deb37fcd014756d024561e8bc3e611ec/lxml-6.1.3-cp315-cp315-win_amd64.whl", hash = "sha256:33cadd956b667997e4de1635fce9541f2e8ede2038fcde8cf55aa14d571d1bad", size = 4074626, upload-time = "2026-09-02T14:51:47.77Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/25/20/3e1395d34d19f9254625d0b567b81cf70d37d3417be074f4d63b94a2be3c/lxml-6.1.3-cp315-cp315-win_arm64.whl", hash = "sha256:8a330c0ee5fa318c7b5cbbaad882baeca3f570357e7eb25ab34bf31008150758", size = 3749495, upload-time = "2026-09-02T14:51:50.663Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/c6/7465ffd9c43883526a382df6fa4846c9d8d419214f7effbf65270e795471/lxml-6.1.3-cp315-cp315t-macosx_10_15_universal2.whl", hash = "sha256:0bf5a3e397df2ec4258eb5eea4c1ac6cf013ca1abd04a176903bff20a70021fe", size = 8857677, upload-time = "2026-09-02T14:51:05.109Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/eb/1f3a917e299df43c8162c3e6f64fc2cea3bcf277910f35bff5b8e5d39901/lxml-6.1.3-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:13d22c0d57355366b393936acf6b98a5e0edeadddd3fccbc6a846c50a76b8741", size = 4754522, upload-time = "2026-09-02T14:51:08.137Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/f9/f81b4bdb6efb7a596be29603d8758154d00a5f545db9f3cef9d9041c8f64/lxml-6.1.3-cp315-cp315t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cad7617727a96d189bd6f979d0fadf765198c7934e85f4edaba9bf3ad919a300", size = 5033744, upload-time = "2026-09-02T14:51:10.633Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c8/0f/26d9bfaacb319c86e0eca8a1a0bf1130d36a7afbd318883e23caea63763d/lxml-6.1.3-cp315-cp315t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cae82b5ca24b0c2beedb269f6e2a96f466acd926879ab00ae19f1a65cbf9ffb0", size = 5615269, upload-time = "2026-09-02T14:51:13.357Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/90/73675f3f4141350ed65d6fec533b107d4e802c5caa340cf111771edd86e0/lxml-6.1.3-cp315-cp315t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:69cafd61aea04ebb3502c93c2aaa568b12931ca0802231e0b5de76bf8b6e74bd", size = 5236280, upload-time = "2026-09-02T14:51:16.051Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/be/ed260767e7977de463a0f91f3f4fffcab85c0a2a024a21ffe1fa442c2c79/lxml-6.1.3-cp315-cp315t-manylinux_2_31_armv7l.whl", hash = "sha256:dc205732d593118cf701d986f40e9de7801bb2e371cb189ddbda9b7348f4d97e", size = 4650718, upload-time = "2026-09-02T14:51:19.102Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/fd/e9839d03b1e767f2725cf7d7d81b80d5f3f9fdc10ad8827e2479311b046e/lxml-6.1.3-cp315-cp315t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:88e719b9437f148f7e1465df845c758dd1598618cbea3a2fd1e61a715542f2b2", size = 5243376, upload-time = "2026-09-02T14:51:21.606Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/a5/4606e347e2788c301f677004aa83e28d24da9fe663a24380122af57be6fc/lxml-6.1.3-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:40983eabefd13da003e68170928c7acc011f0d095eefce5871a3c71c9385fb9a", size = 5092340, upload-time = "2026-09-02T14:51:24.21Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ea/99/3314a8661cdf30f493c55a87db283961dfaae08451976a2ca418958e1804/lxml-6.1.3-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:fad67b12ffe0f71e02b4932b04883cbc76a9072bbd30731409d3523cf058b011", size = 4758768, upload-time = "2026-09-02T14:51:26.813Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/58/3bdc577f78ea8b7d72d39a84506f7001d5b28728f43e5b84891e3b7d9a4a/lxml-6.1.3-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:6cd11e7550d89e551a87dcec30f04b1fca32e86b68708aa01a4daa455d8605e5", size = 5649546, upload-time = "2026-09-02T14:51:29.453Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/e4/652633de1a2395949ebb7a8fc7d089aba12a2b45f0fefbc9d29e3e3ab3cf/lxml-6.1.3-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:ca0ec532ad2f5ba1e5ec120ac157769c57f01855b3d8bf37213f5d88abd9ba0a", size = 5234874, upload-time = "2026-09-02T14:51:32.262Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/65/a6/c4581d171de30449304b4859bbd3607e9b40da13c0f88b68e6097c8d785e/lxml-6.1.3-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:e99e09ab7741f1281e2677f4c0058c7f5267d182530b09c87e4f6aa26adf3887", size = 5260043, upload-time = "2026-09-02T14:51:34.841Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/d7/ed6ee6186a89e69ca4ea9658b2a278f46a5efe8b5d4db56c7197f18653fe/lxml-6.1.3-cp315-cp315t-win32.whl", hash = "sha256:ace1d2c83b2bd24db5940600541140e87a325e119cb32d5fa9ad720d7e76648e", size = 3901093, upload-time = "2026-09-02T14:51:37.234Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/9d/11d10257a4a048d04195d638bb61f0246ce2448eb05f682bcbab25a257a8/lxml-6.1.3-cp315-cp315t-win_amd64.whl", hash = "sha256:b49638355ea3bebba70da783ccbc630fd72afa16bc46c54474bfa1f9a915bbc6", size = 4395446, upload-time = "2026-09-02T14:51:39.884Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/b7/44edd7de434181c582892e68d1ffe6775ca403ce14aea07cb5a218a936cf/lxml-6.1.3-cp315-cp315t-win_arm64.whl", hash = "sha256:5a721a98c649855963811b59b55755b30566e7f7fc40bdc9803d66dee9f811cf", size = 3822836, upload-time = "2026-09-02T14:51:42.471Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/c1/2433176de263cc3f51fd2c303f993d5bb7f1da3139a0f7d168116c0bfa7a/lxml-6.1.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d2765c18ce303149ee804b1f3dad11232726dd0a702d73a15cf19179ac8cc962", size = 3942969, upload-time = "2026-09-02T14:46:36.55Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/71/de7759096f480180fd9e43ff7c017860e2d2a9a43741ab093cbdf1820f07/lxml-6.1.3-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d5a748d12dd9b535e0a130f60dae9ddf0adafbabe61e7864f55c7436c84547a", size = 4213008, upload-time = "2026-09-02T14:46:38.784Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/9b/c2d09af47a34fa6c0c27473083812b449a411680bd04bbe609cde291ddc8/lxml-6.1.3-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:41096ec0740a58dad03d3ae0c7486d306d20becefb13ceb1649835ab3eb64167", size = 4322012, upload-time = "2026-09-02T14:46:41.031Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/68/f3/bf56fee0403ebd995be8e78ec9aca566016487d1b3cbf755ebea8ccffbdb/lxml-6.1.3-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:415e3a115c0d510e329020012834d1c0aa1c581ee53a218603e38abbc1dea70a", size = 4257402, upload-time = "2026-09-02T14:46:43.134Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1c/1d/6da9cc086a20d9dd6bcbf7c5d9575f0331cca9a05e67dab02d15e828170b/lxml-6.1.3-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20428910dae17a1a93152a3ff2c0441d2f4932992c0797d65651dd0561f1792f", size = 4410889, upload-time = "2026-09-02T14:46:46.975Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/03/5c/91fe48856f9f8089be3096fa4dbe4b3fb5526f3bf3e852ea9497f399cb9f/lxml-6.1.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:bc8dd3d9c93e70c3df974a201ac2958b6d77b465d813c51d1f15fa8e645763ae", size = 3511258, upload-time = "2026-09-02T14:46:49.046Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "networkx"
|
||||
version = "3.6.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/6a/51/63fe664f3908c97be9d2e4f1158eb633317598cfa6e1fc14af5383f17512/networkx-3.6.1.tar.gz", hash = "sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509", size = 2517025, upload-time = "2025-12-08T17:02:39.908Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyyaml"
|
||||
version = "6.0.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter"
|
||||
version = "0.26.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f7/03/5600b84aff2e6c4fe80cfebb4063fe2f50299521befe5f6092ab8c082f4a/tree_sitter-0.26.0.tar.gz", hash = "sha256:b40c219edccc4564530c96f8f1556f6202b37cda964d1cbd7bd2b7e68b40a245", size = 191423, upload-time = "2026-06-30T12:14:27.933Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/41/18/78aae7e4b5a36daaebb0276e4b07d084d45298758000787838e89329e11f/tree_sitter-0.26.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1d6fe0e8fb4df77b5ee816228e2c4475a63d8cc1d4d3a7ffd7097b2b87fc3e95", size = 148679, upload-time = "2026-06-30T12:13:52.27Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/e4/b371b9553b0e47d130fc2073e56cab94fecc868be04666bf5bbd1fcd1cc9/tree_sitter-0.26.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:514a9bf8993e5210e7970736aaf6020d1759b670e195ef17b1c48f586aa30736", size = 140759, upload-time = "2026-06-30T12:13:53.221Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/7d/266fb0f2c41e6fb00b0f40e7a3338cdf99651e6a6511ca72bc78fc697636/tree_sitter-0.26.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10f0d4eb94aa7242dcb7f554bcd24dd7ba1c114f00d58759ba08c7a46c8ec51a", size = 637206, upload-time = "2026-06-30T12:13:54.334Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/40/9f/47cf22febb47132d5b3a507a27bb99ef89fe5c8ec420a13c6daa9b64f782/tree_sitter-0.26.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:335294ce0504fcefde5245dff596778ffaf820205b98ae0b549c72e48855f1d8", size = 664758, upload-time = "2026-06-30T12:13:55.42Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4c/4d/8d144ca3beb46a62a5102b6deac76bb0da55235c2c7840faf3b12f2e9d97/tree_sitter-0.26.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f9997ba61368c48ed54e715676afadf703947a1542464e39d047764fb3624b01", size = 647438, upload-time = "2026-06-30T12:13:56.523Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/ed/ed1d6e78520c4fb64ed52fec3f2947bf8c1fbad7bc24e282c56193c9ba42/tree_sitter-0.26.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c56581ad256c4195a21bfe449fed5d44a02fe83a4a7d6e70e6ec302c881191c7", size = 661944, upload-time = "2026-06-30T12:13:57.82Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/83/45f5bd43db1b8248d2fd08ef6cbe43e2725c539e09a2cfb8bc2818646788/tree_sitter-0.26.0-cp311-cp311-win_amd64.whl", hash = "sha256:0f8793fd18ad7eec276ed4b51c097b4bf2002b357259b66b0d75db1f3f41c754", size = 129496, upload-time = "2026-06-30T12:13:59.216Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/8d/be68e6c04563eb54145424cc83fe0aa8b0ba6c90d8989cf8a032671b5f16/tree_sitter-0.26.0-cp311-cp311-win_arm64.whl", hash = "sha256:dea4b4e27d49e9ec5b785d4f994da000e6726882fcc6ad05ec98478500c71aef", size = 116484, upload-time = "2026-06-30T12:14:00.147Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/87/ca/565702c44815393e3a973552ad546db4e5ca081ca8698640b4e93d809f51/tree_sitter-0.26.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6cb2bd20efb2544c19ac54486ab7cb8ec7b36f913bbe1ce95df84acb96743d9c", size = 148934, upload-time = "2026-06-30T12:14:01.188Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/6f/8bb61957f16ec1b1d92410a006cdc84a952b6352a7313b2ad299f2d21484/tree_sitter-0.26.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:918d89529786873f0982a0f59c2a303cd065fbfd1b903d71a8e4e1584f67b42e", size = 140820, upload-time = "2026-06-30T12:14:02.087Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/78/0a/8a6f08559182643a814a4ab559948ae817b2851890fd9b995a4fff6541ce/tree_sitter-0.26.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:30a88be89ff1f2755297f81e8080d88b795dd98720c3f9fa2acf93873182cc95", size = 638844, upload-time = "2026-06-30T12:14:03.428Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/2f/6e6781b31677231366cb3cf27bc8269157f6d4b03c9032865a4f5f2bbe7e/tree_sitter-0.26.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a6b333b0282d8bb0af741f9b018bd2523d4eecb2686bf6717066a625fecfaa4", size = 667487, upload-time = "2026-06-30T12:14:04.669Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/02/0b/0483078c8567445557a7015b0e5b187f6d7d4fda73464df9c4bdea7f7f3c/tree_sitter-0.26.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3f3c44339dd34fe8eb2b8d5aa7610660499a795f70376b130bbee7a437337280", size = 647975, upload-time = "2026-06-30T12:14:05.797Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/27/68/da83ca72c984e96ab4eb3bee0db1a6ffb5de1c8c455f92bd9f420cde7f0e/tree_sitter-0.26.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:94550e13b6ae576969da40246f4c4abb206380b5375ad43f26dd9151d55438e3", size = 665018, upload-time = "2026-06-30T12:14:07.278Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/36/4d67927fd47b89af4a00f65f55a7370e28778cd50e972c2430487e3ecc27/tree_sitter-0.26.0-cp312-cp312-win_amd64.whl", hash = "sha256:ca89e361a276dbc934b28a43dd881199e25d34ff5493ee0ce45f3c52a6124a37", size = 129619, upload-time = "2026-06-30T12:14:08.373Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/72/cdefad523eb78710679c6da6a79e3d90f5afd32b1c6aa5a17bac7eef99f6/tree_sitter-0.26.0-cp312-cp312-win_arm64.whl", hash = "sha256:bc6cb01d5ee75c85424aa1f1c72a82d8f07fd52539a0f3c4a6ed3e8721079b84", size = 116545, upload-time = "2026-06-30T12:14:09.273Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/b0/465257cf8f972ad9f9812ec1cbaa8ec210ebebb601ade9a15881aa2436b4/tree_sitter-0.26.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ed0889dbed843ce45ede9f5169c0b2dea2222f12685844a03fadb81f12705867", size = 148893, upload-time = "2026-06-30T12:14:10.541Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/ec/19d093e854b45e807fecfdd26105c266f43aeecc39c4dc97992a7074ad5a/tree_sitter-0.26.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6189c6c340c7384357711e3d92645e96bfb79f7a502f86de1ebdb23eb43f7dab", size = 140829, upload-time = "2026-06-30T12:14:11.626Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9b/ee/87e74671ed63a837e7a1f17ab94aa3913871e033b27523d8e7b83d6f7ad0/tree_sitter-0.26.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8ff2e0750b7daa722302838356d7b65e303829b7eb73c915df127ddba115e1d1", size = 639334, upload-time = "2026-06-30T12:14:12.836Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/e7/f7e04cd9dff6b6ac0adf23922796fbc76accd4cf4bcda50542748d485679/tree_sitter-0.26.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7075ef857ef86f327dbb72d1e2574dda78db5754b3a1fca6506acd7fe5d561a7", size = 668102, upload-time = "2026-06-30T12:14:14.035Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d3/90/0bfb16b7894fea728c774a89d5af421a9368a2f913bbd4e8dcab7caaecfb/tree_sitter-0.26.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:26c996c1edfee86e977bb3f5462e74fcec0d0b0db1e85a3c475875763caa03be", size = 648560, upload-time = "2026-06-30T12:14:15.302Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cd/e6/0fe05ba396e9623b0ae40ccf34171336b8701ec8d7bd0ee9f5224d638665/tree_sitter-0.26.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:00289bfe7978f3e0dc0ce69813a20fa9f44ea4c100b3ec62043e5eb74ccfc3a2", size = 665121, upload-time = "2026-06-30T12:14:16.403Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/d2/a944b1ca35bed6068dc84a9967aaf3049d8cc0b7a36179eea8787270a6ab/tree_sitter-0.26.0-cp313-cp313-win_amd64.whl", hash = "sha256:93e220cab7e6a823efeb2046c49171427de92ef71c7c681c01820d14d8d3721f", size = 129615, upload-time = "2026-06-30T12:14:17.463Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/09/ef/c7ca48293580d2249f36940c4eed5b4ddeb9ce75baf9a4ef30621987e0c7/tree_sitter-0.26.0-cp313-cp313-win_arm64.whl", hash = "sha256:b31a8195d2f224224c530ac814632d98c1dcc123d227442c07c736e86b70d564", size = 116525, upload-time = "2026-06-30T12:14:18.53Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c5/7a/4d84e6f6ae2c3e757490dd84de251712c31e293dfe31f28da1ec019cefa2/tree_sitter-0.26.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:5a3c93a352b7e6f70f73e121bbfa2d0117ba7478bd51114ed35c91b0b78814fa", size = 148901, upload-time = "2026-06-30T12:14:19.452Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b0/d9/efe62ec65dc9d096e834d27b8c058127e2146e42ff3380b822a233f016a6/tree_sitter-0.26.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5fc2f41bf246ff2f70a9cc3690be35ec7580a4923151873d898c8bcb1a4503d3", size = 140805, upload-time = "2026-06-30T12:14:20.478Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/2c/c82326b7b97e3c485c18679883b16f89e5e913c639d3b219d3da70c9e67e/tree_sitter-0.26.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8ea92a255c91671a7ec4625aba3ab7bb5220c423630ffbf83c45d7312abe084", size = 640586, upload-time = "2026-06-30T12:14:21.527Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e2/7a/f56e7d8282859452611024c7cbc623bfba5b24b8cb9b8f8bc88c5219fe9a/tree_sitter-0.26.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f665510f0fcf4636fb9696f1f7853bed7a3bd764b7bb0cb8494e619c14ed5a0c", size = 668300, upload-time = "2026-06-30T12:14:22.728Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/51/240ee81b9d5e9ca0a6cb1528e8605ffa70ab58c89ce126631be96d3e4bae/tree_sitter-0.26.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:253df7ab82cc0a9d311cd65f06e9f99fb3eac55996ae9fc94da22f123a861b90", size = 649627, upload-time = "2026-06-30T12:14:23.819Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/54/760035cefedf9eb44f0f84c4ac22f1322e73155853e272576ee876336312/tree_sitter-0.26.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ff80d4833d330a73184a3ac5132abe93c575d2dea31975c6f15c0d21fef238aa", size = 664885, upload-time = "2026-06-30T12:14:25.064Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c9/1b/0b36fe2a984ecedc4ce6aefd5d56447a6626a8e9b595c4e48658510ce8f8/tree_sitter-0.26.0-cp314-cp314-win_amd64.whl", hash = "sha256:a4033fecc8f606c7f2e8b8014d0057b74668a7f0152763606f7bc25c5f9ec64c", size = 132688, upload-time = "2026-06-30T12:14:26.106Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/74/ebc041a13fbf40144afdb0d4b447e48e0b4012ca866c63de8b48f801f0c1/tree_sitter-0.26.0-cp314-cp314-win_arm64.whl", hash = "sha256:823251c4b6725a7c03ed497a339135ede7ae4bdde75bb8be7ef5e305aeb4ff52", size = 120287, upload-time = "2026-06-30T12:14:26.991Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter-c-sharp"
|
||||
version = "0.23.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/9f/fb/7e2962bc1901daf264e7ce263b168e0139304a5f8f66c9b2baf20e550f87/tree_sitter_c_sharp-0.23.5.tar.gz", hash = "sha256:2635c7d5ec93e59f2e831b571bed99c4cc68a5d183a0994020aa769e1b990a71", size = 1147914, upload-time = "2026-04-14T16:11:22.441Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/c4/86d8d469400a856757a464a6ac01af97d8cdacbb595e62bdb98bf1e9db90/tree_sitter_c_sharp-0.23.5-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:61e1981cf21b09ee547b9c4c68e64fb4394325f8fc8d5f6d50d41471eba923ea", size = 333658, upload-time = "2026-04-14T16:11:11.288Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c8/13/593c8603f834eaf15082b81e079289fc9f062b4c0ab5b9489134084eec06/tree_sitter_c_sharp-0.23.5-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:a75994a11f6fed3f5b8c36ad6a00e5dc43205bd912c43af3a2a54fdf649664eb", size = 376296, upload-time = "2026-04-14T16:11:12.972Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/5a/a8855cbb5bbab28adb29c2c7f0e7be5a9f1d21450c13b3c3e613190d9b8c/tree_sitter_c_sharp-0.23.5-cp310-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:aa88a780204cd153c4c1ae2d59c654cee1402212fa0d069823d6d34301587438", size = 358333, upload-time = "2026-04-14T16:11:14.214Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/c8/e0f391e343f5424d0627e3b6886c77baeb1249a3f10986be00b0b64ecdab/tree_sitter_c_sharp-0.23.5-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ea38fb095d85d360dc5a0bec2fa605e496228876f798c9e089d5f0e72bcef46", size = 359448, upload-time = "2026-04-14T16:11:15.419Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6f/fc/10f807ac79f928241c5e0d827fdaf91e97dfba662fc7e07d7bd664140ec1/tree_sitter_c_sharp-0.23.5-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:05a9256415e7f24d4f133133794a9c224c60d19f677a04e2f6a94c25090b6d65", size = 358144, upload-time = "2026-04-14T16:11:17.087Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/de/2a/6c3e12ef0cf09138717fcc02e1de8b76a3928d1bed65c7e3c2bd3172bcef/tree_sitter_c_sharp-0.23.5-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8636dc70b5a373c35c1036ed5de98e801f2e4d105ae41e2e20b6804c36e3bf33", size = 357525, upload-time = "2026-04-14T16:11:18.214Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/e0/bd287b092d611df95a9149117fd27b5947ce75527113d6898a4b4e2c8858/tree_sitter_c_sharp-0.23.5-cp310-abi3-win_amd64.whl", hash = "sha256:41a28cfa3d9ea50f5629e44550a03188c8fbd5079803dfc03554b6fd594b33fa", size = 338756, upload-time = "2026-04-14T16:11:19.661Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/fb/114ff43fdd256d0befed32f77c1dadee9517867181c70794571f718ed05c/tree_sitter_c_sharp-0.23.5-cp310-abi3-win_arm64.whl", hash = "sha256:2de4ebf95ddc2e92cd3105c8a8e0e7ec646bc82f52bfaf2f3acec0fa2401ec09", size = 337260, upload-time = "2026-04-14T16:11:20.849Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter-python"
|
||||
version = "0.25.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b8/8b/c992ff0e768cb6768d5c96234579bf8842b3a633db641455d86dd30d5dac/tree_sitter_python-0.25.0.tar.gz", hash = "sha256:b13e090f725f5b9c86aa455a268553c65cadf325471ad5b65cd29cac8a1a68ac", size = 159845, upload-time = "2025-09-11T06:47:58.159Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/cf/64/a4e503c78a4eb3ac46d8e72a29c1b1237fa85238d8e972b063e0751f5a94/tree_sitter_python-0.25.0-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:14a79a47ddef72f987d5a2c122d148a812169d7484ff5c75a3db9609d419f361", size = 73790, upload-time = "2025-09-11T06:47:47.652Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/1d/60d8c2a0cc63d6ec4ba4e99ce61b802d2e39ef9db799bdf2a8f932a6cd4b/tree_sitter_python-0.25.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:480c21dbd995b7fe44813e741d71fed10ba695e7caab627fb034e3828469d762", size = 76691, upload-time = "2025-09-11T06:47:49.038Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/cb/d9b0b67d037922d60cbe0359e0c86457c2da721bc714381a63e2c8e35eba/tree_sitter_python-0.25.0-cp310-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:86f118e5eecad616ecdb81d171a36dde9bef5a0b21ed71ea9c3e390813c3baf5", size = 108133, upload-time = "2025-09-11T06:47:50.499Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/40/bd/bf4787f57e6b2860f3f1c8c62f045b39fb32d6bac4b53d7a9e66de968440/tree_sitter_python-0.25.0-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be71650ca2b93b6e9649e5d65c6811aad87a7614c8c1003246b303f6b150f61b", size = 110603, upload-time = "2025-09-11T06:47:51.985Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/25/feff09f5c2f32484fbce15db8b49455c7572346ce61a699a41972dea7318/tree_sitter_python-0.25.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e6d5b5799628cc0f24691ab2a172a8e676f668fe90dc60468bee14084a35c16d", size = 108998, upload-time = "2025-09-11T06:47:53.046Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/69/4946da3d6c0df316ccb938316ce007fb565d08f89d02d854f2d308f0309f/tree_sitter_python-0.25.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:71959832fc5d9642e52c11f2f7d79ae520b461e63334927e93ca46cd61cd9683", size = 107268, upload-time = "2025-09-11T06:47:54.388Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/a2/996fc2dfa1076dc460d3e2f3c75974ea4b8f02f6bc925383aaae519920e8/tree_sitter_python-0.25.0-cp310-abi3-win_amd64.whl", hash = "sha256:9bcde33f18792de54ee579b00e1b4fe186b7926825444766f849bf7181793a76", size = 76073, upload-time = "2025-09-11T06:47:55.773Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/19/4b5569d9b1ebebb5907d11554a96ef3fa09364a30fcfabeff587495b512f/tree_sitter_python-0.25.0-cp310-abi3-win_arm64.whl", hash = "sha256:0fbf6a3774ad7e89ee891851204c2e2c47e12b63a5edbe2e9156997731c128bb", size = 74169, upload-time = "2025-09-11T06:47:56.747Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter-typescript"
|
||||
version = "0.23.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1e/fc/bb52958f7e399250aee093751e9373a6311cadbe76b6e0d109b853757f35/tree_sitter_typescript-0.23.2.tar.gz", hash = "sha256:7b167b5827c882261cb7a50dfa0fb567975f9b315e87ed87ad0a0a3aedb3834d", size = 773053, upload-time = "2024-11-11T02:36:11.396Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/28/95/4c00680866280e008e81dd621fd4d3f54aa3dad1b76b857a19da1b2cc426/tree_sitter_typescript-0.23.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3cd752d70d8e5371fdac6a9a4df9d8924b63b6998d268586f7d374c9fba2a478", size = 286677, upload-time = "2024-11-11T02:35:58.839Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/2f/1f36fda564518d84593f2740d5905ac127d590baf5c5753cef2a88a89c15/tree_sitter_typescript-0.23.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:c7cc1b0ff5d91bac863b0e38b1578d5505e718156c9db577c8baea2557f66de8", size = 302008, upload-time = "2024-11-11T02:36:00.733Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/96/2d/975c2dad292aa9994f982eb0b69cc6fda0223e4b6c4ea714550477d8ec3a/tree_sitter_typescript-0.23.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b1eed5b0b3a8134e86126b00b743d667ec27c63fc9de1b7bb23168803879e31", size = 351987, upload-time = "2024-11-11T02:36:02.669Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/d1/a71c36da6e2b8a4ed5e2970819b86ef13ba77ac40d9e333cb17df6a2c5db/tree_sitter_typescript-0.23.2-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e96d36b85bcacdeb8ff5c2618d75593ef12ebaf1b4eace3477e2bdb2abb1752c", size = 344960, upload-time = "2024-11-11T02:36:04.443Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/cb/f57b149d7beed1a85b8266d0c60ebe4c46e79c9ba56bc17b898e17daf88e/tree_sitter_typescript-0.23.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8d4f0f9bcb61ad7b7509d49a1565ff2cc363863644a234e1e0fe10960e55aea0", size = 340245, upload-time = "2024-11-11T02:36:06.473Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8b/ab/dd84f0e2337296a5f09749f7b5483215d75c8fa9e33738522e5ed81f7254/tree_sitter_typescript-0.23.2-cp39-abi3-win_amd64.whl", hash = "sha256:3f730b66396bc3e11811e4465c41ee45d9e9edd6de355a58bbbc49fa770da8f9", size = 278015, upload-time = "2024-11-11T02:36:07.631Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9f/e4/81f9a935789233cf412a0ed5fe04c883841d2c8fb0b7e075958a35c65032/tree_sitter_typescript-0.23.2-cp39-abi3-win_arm64.whl", hash = "sha256:05db58f70b95ef0ea126db5560f3775692f609589ed6f8dd0af84b7f19f1cbb7", size = 274052, upload-time = "2024-11-11T02:36:09.514Z" },
|
||||
]
|
||||
Reference in New Issue
Block a user