Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .agents/requirements-graphify.in
Original file line number Diff line number Diff line change
@@ -1 +1 @@
graphifyy==0.9.96
graphifyy==0.4.23
9 changes: 1 addition & 8 deletions .agents/requirements-graphify.txt
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
graphifyy==0.9.96
graphifyy==0.4.23
networkx==3.6.1
numpy==2.4.6
pyyaml==6.0.3
rapidfuzz==3.14.6
tree-sitter==0.25.2
tree-sitter-bash==0.25.1
tree-sitter-c==0.24.2
tree-sitter-c-sharp==0.23.5
tree-sitter-cpp==0.23.4
tree-sitter-elixir==0.3.5
tree-sitter-fortran==0.6.0
tree-sitter-go==0.25.0
tree-sitter-groovy==0.1.2
tree-sitter-java==0.23.5
tree-sitter-javascript==0.25.0
tree-sitter-json==0.24.8
tree-sitter-julia==0.23.1
tree-sitter-kotlin==1.1.0
tree-sitter-lua==0.5.0
Expand Down
2 changes: 1 addition & 1 deletion .agents/skills/datadesigner-docs/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ Notebook tutorials are JS-driven via `<NotebookViewer>` rendering converted `.ip

```
docs/notebook_source/*.py (jupytext format — canonical source, edit here)
│ make convert-execute-notebooks # jupytext --execute (needs NVIDIA_API_KEY)
│ make convert-execute-notebooks # jupytext → jupyter-execute (needs NVIDIA_API_KEY)
▼
docs/notebooks/*.ipynb (executed; outputs captured)
│
Expand Down
14 changes: 11 additions & 3 deletions .agents/tests/test_structural_impact.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,15 @@
EXPORT_FAILURE = """
import runpy
import sys
from pathlib import Path
from unittest.mock import patch

def fail_export(graph, communities, output_path):
Path(output_path).write_text('{')
raise OSError("graph export failed")

sys.argv = sys.argv[1:]
with patch("graphify.export.to_json", return_value=False):
with patch("graphify.export.to_json", side_effect=fail_export):
runpy.run_path(sys.argv[0], run_name="__main__")
"""

Expand Down Expand Up @@ -99,7 +104,7 @@ def test_full_graph_round_trip(repo_root: Path, run_tool: Callable[..., subproce
assert "**no changes**" in run_tool("--full", "--previous-graph", str(graph_path)).stdout


@pytest.mark.parametrize("metadata", [{}, {"graphify_version": "0.4.23"}, {"schema_version": -1}])
@pytest.mark.parametrize("metadata", [{}, {"graphify_version": "0.9.96"}, {"schema_version": -1}])
def test_incompatible_baseline_is_reset(
repo_root: Path, run_tool: Callable[..., subprocess.CompletedProcess[str]], metadata: dict[str, object]
) -> None:
Expand Down Expand Up @@ -139,13 +144,16 @@ def test_rejected_export_preserves_baselines(
run_tool("--full")
baselines = repo_root / "graphify-out/baselines.json"
previous = baselines.read_bytes()
graph_path = baselines.with_name("graph.json")
previous_graph = graph_path.read_bytes()
(repo_root / INTERFACE).unlink()

result = run_tool("--full", reject_export=True, check=False)

assert result.returncode != 0
assert "baselines were not updated" in result.stderr
assert "graph export failed" in result.stderr
assert baselines.read_bytes() == previous
assert graph_path.read_bytes() == previous_graph


def test_empty_scan_preserves_baselines(
Expand Down
19 changes: 15 additions & 4 deletions .agents/tools/structural_impact.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@
from graphify.analyze import god_nodes, graph_diff
from graphify.build import build_from_json
from graphify.cluster import cluster, score_all
from graphify.export import GRAPH_SCHEMA_VERSION, to_json
from graphify.export import to_json
from graphify.extract import extract
from networkx.readwrite import json_graph

_REPO_ROOT_DEFAULT = Path(__file__).resolve().parent.parent.parent
_REPO_ROOT = _REPO_ROOT_DEFAULT
_GRAPHIFY_VERSION = version("graphifyy")
# Graphify 0.4.x does not stamp its exports, so version our saved report format.
GRAPH_SCHEMA_VERSION = 1

# DD layering: interface -> engine -> config (left depends on right).
_LEGAL_DIRECTIONS = {("interface", "engine"), ("interface", "config"), ("engine", "config")}
Expand Down Expand Up @@ -111,8 +113,12 @@ def _build_graph(files: list[Path]) -> _Analysis:
"""Extract, build directed graph, cluster, and find god nodes."""
if not files:
raise ValueError(f"No Python source files found under {_REPO_ROOT}")
ext = extract(files, root=_REPO_ROOT, cache_root=_REPO_ROOT)
ext = extract(files, cache_root=_REPO_ROOT)
G = build_from_json(ext, directed=True)
G.graph.update(graphify_version=_GRAPHIFY_VERSION, schema_version=GRAPH_SCHEMA_VERSION)
for _, node in G.nodes(data=True):
if node.get("source_file"):
node["source_file"] = _rel(node["source_file"])
comms = cluster(G)
return _Analysis(graph=G, communities=comms, cohesion=score_all(G, comms), god_nodes=god_nodes(G, top_n=15))

Expand Down Expand Up @@ -370,8 +376,13 @@ def _full_mode(previous_graph_path: str | None = None) -> str:
out_dir = _REPO_ROOT / "graphify-out"
out_dir.mkdir(exist_ok=True)
# This is a complete source snapshot, so deletions must replace the old graph.
if not to_json(G, communities, str(out_dir / "graph.json"), force=True):
raise RuntimeError("Could not save the structural graph; baselines were not updated")
graph_path = out_dir / "graph.json"
export_path = graph_path.with_suffix(".tmp")
try:
to_json(G, communities, str(export_path))
export_path.replace(graph_path)
finally:
export_path.unlink(missing_ok=True)
(out_dir / "baselines.json").write_text(
json.dumps(
{
Expand Down
7 changes: 7 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ updates:
directory: /.agents
schedule:
interval: weekly
# Hold routine upgrades for the 0.4 adapter; keep security updates enabled.
ignore:
- dependency-name: graphifyy
update-types:
- version-update:semver-major
- version-update:semver-minor
- version-update:semver-patch
groups:
graphify:
patterns:
Expand Down
7 changes: 3 additions & 4 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,12 @@ cd DataDesigner
# Install with dev dependencies
make install-dev

# Or, if you use Jupyter / IPython for development
# Or, to execute the tutorial and documentation notebooks
make install-dev-notebooks
```

Notebook setup uses the patched nbconvert PyPI release, including its HTML stylesheets.
The `install-notebook-css` target reuses existing stylesheets and can restore missing assets from a
checksum-pinned wheel. Use `NOTEBOOK_CSS=0` to skip that restoration check in execution-only environments.
Notebook setup installs the kernel and execution tools used by Jupytext and the Fern notebook pipeline.
Install a Jupyter frontend separately if you want to edit notebooks in its browser interface.

### Verify Your Setup

Expand Down
25 changes: 8 additions & 17 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ help:
@echo " generate-fern-notebooks - Convert docs/notebook_source/*.py → fern/components/notebooks/{json,ts}"
@echo " generate-fern-notebooks-with-outputs - Full pipeline: execute notebooks (needs API key), colabify, convert to Fern"
@echo " install-docs-deps - Install docs and notebook dependencies"
@echo " install-notebook-css - Restore nbconvert HTML export stylesheets"
@echo " prepare-fern-release VERSION=X.Y.Z - Add or refresh Fern version files for release preview"
@echo " check-fern-release-version VERSION=X.Y.Z - Verify Fern has a version entry for release publishing"
@echo " prepare-fern-docs - Generate local Fern artifacts"
Expand Down Expand Up @@ -179,9 +178,8 @@ test-graphify: install-graphify
install-dev-notebooks:
@echo "📦 Installing DataDesigner workspace with notebook dependencies..."
@echo " Packages: data-designer-config → data-designer-engine → data-designer"
@echo " Groups: dev + docs + notebooks (Jupyter, jupytext, etc.)"
@echo " Groups: dev + docs + notebooks (Jupytext, kernel, execution tools)"
uv sync --all-packages --group dev --group docs --group notebooks
@$(MAKE) install-notebook-css
$(call install-pre-commit-hooks)
@echo "✅ Dev + docs + notebooks installation complete!"
@echo ""
Expand Down Expand Up @@ -511,7 +509,7 @@ update-license-headers:
DOCS_PYTHON_VERSION ?= 3.13
DOCS_PYTHON ?= .venv/bin/python
DOCS_JUPYTEXT ?= .venv/bin/jupytext
NOTEBOOK_CSS ?= 1
DOCS_NBCLIENT ?= $(if $(findstring /,$(DOCS_JUPYTEXT)),$(dir $(DOCS_JUPYTEXT)),)jupyter-execute
FERN_VERSION ?= $(shell jq -r .version fern/fern.config.json)
FERN ?= npx -y fern-api@$(FERN_VERSION)
FERN_ORG ?= $(shell jq -r .organization fern/fern.config.json)
Expand All @@ -526,16 +524,6 @@ DOCS_CERTS = SSL_CERT_FILE=$$($(DOCS_PYTHON) -c "import certifi; print(certifi.w
install-docs-deps:
@echo "📦 Installing docs dependencies (Python $(DOCS_PYTHON_VERSION))..."
uv sync --python $(DOCS_PYTHON_VERSION) --all-packages --group docs --group notebooks
@$(MAKE) install-notebook-css

install-notebook-css:
ifeq ($(NOTEBOOK_CSS),1)
$(DOCS_CERTS) $(DOCS_PYTHON) docs/scripts/prepare_nbconvert_css.py
else ifeq ($(NOTEBOOK_CSS),0)
@echo "Skipping nbconvert CSS (notebook execution only)."
else
$(error NOTEBOOK_CSS must be 0 or 1)
endif

prepare-fern-release:
ifndef VERSION
Expand Down Expand Up @@ -599,7 +587,7 @@ serve-fern-docs-local-theme:
convert-execute-notebooks:
ifeq ($(USE_CACHE),1)
@echo "📓 Converting Python tutorials to notebooks (with caching)..."
@$(DOCS_CERTS) DOCS_JUPYTEXT=$(DOCS_JUPYTEXT) bash docs/scripts/build_notebooks_cached.sh
@$(DOCS_CERTS) DOCS_JUPYTEXT=$(DOCS_JUPYTEXT) DOCS_NBCLIENT=$(DOCS_NBCLIENT) bash docs/scripts/build_notebooks_cached.sh
else
@echo "📓 Converting Python tutorials to notebooks and executing ($(DOCS_PYTHON))..."
@rm -rf docs/notebooks
Expand All @@ -611,7 +599,10 @@ else
for f in docs/notebook_source/*.py; do \
[ -f "$$f" ] || continue; \
echo "▶ executing $$f"; \
$(DOCS_JUPYTEXT) --to ipynb --execute "$$f" || failed="$$failed\n • $$f"; \
if ! { $(DOCS_JUPYTEXT) --to ipynb "$$f" && $(DOCS_NBCLIENT) --inplace "$${f%.py}.ipynb"; }; then \
rm -f "$${f%.py}.ipynb"; \
failed="$$failed\n • $$f"; \
fi; \
done; \
for f in docs/notebook_source/*.ipynb; do [ -f "$$f" ] && mv "$$f" docs/notebooks/; done; \
rm -rf docs/notebook_source/artifacts; \
Expand Down Expand Up @@ -818,7 +809,7 @@ clean-test-coverage:
format format-check format-check-config format-check-engine format-check-interface \
format-config format-engine format-interface \
generate-colab-notebooks generate-fern-notebooks generate-fern-notebooks-with-outputs help \
install install-dev install-dev-notebooks install-dev-recipes install-docs-deps install-graphify install-notebook-css \
install install-dev install-dev-notebooks install-dev-recipes install-docs-deps install-graphify \
lint lint-config lint-engine lint-fix lint-fix-config lint-fix-engine lint-fix-interface lint-interface lock-graphify \
perf-import perf-import-runtime prepare-fern-docs prepare-fern-release publish serve-fern-docs-dev serve-fern-docs-local-theme serve-fern-docs-locally show-versions \
health-checks \
Expand Down
1 change: 0 additions & 1 deletion constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
# uv pip install data-designer -c constraints.txt
# uv add data-designer -c constraints.txt
anyio>=4.14.2
bleach>=6.4.0
cryptography>=50.0.0
filelock>=4.2.1
idna>=3.15
Expand Down
15 changes: 9 additions & 6 deletions docs/scripts/build_notebooks_cached.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ SOURCE_DIR="$REPO_ROOT/docs/notebook_source"
OUTPUT_DIR="$REPO_ROOT/docs/notebooks"
CACHE_DIR="${1:-$REPO_ROOT/.notebook-cache}"
DOCS_JUPYTEXT="${DOCS_JUPYTEXT:-$REPO_ROOT/.venv/bin/jupytext}"
DOCS_NBCLIENT="${DOCS_NBCLIENT:-$(dirname "$DOCS_JUPYTEXT")/jupyter-execute}"
NOTEBOOK_EXECUTION_ATTEMPTS="${NOTEBOOK_EXECUTION_ATTEMPTS:-1}"
NOTEBOOK_RETRY_DELAY_SECONDS="${NOTEBOOK_RETRY_DELAY_SECONDS:-15}"

Expand All @@ -37,11 +38,13 @@ if [[ ! "$NOTEBOOK_RETRY_DELAY_SECONDS" =~ ^[0-9]+$ ]]; then
exit 1
fi

if [ ! -x "$DOCS_JUPYTEXT" ]; then
echo "❌ Missing jupytext executable: $DOCS_JUPYTEXT"
echo "Run 'make install-dev-notebooks' first."
exit 1
fi
for notebook_tool in "$DOCS_JUPYTEXT" "$DOCS_NBCLIENT"; do
if [ ! -x "$notebook_tool" ]; then
echo "❌ Missing notebook executable: $notebook_tool"
echo "Run 'make install-dev-notebooks' first."
exit 1
fi
done

execute_notebook() {
local src="$1"
Expand All @@ -51,7 +54,7 @@ execute_notebook() {

for ((attempt = 1; attempt <= NOTEBOOK_EXECUTION_ATTEMPTS; attempt++)); do
rm -f "$output"
if "$DOCS_JUPYTEXT" --to ipynb --execute "$src"; then
if "$DOCS_JUPYTEXT" --to ipynb "$src" && "$DOCS_NBCLIENT" --inplace "$output"; then
return 0
fi
rm -f "$output"
Expand Down
76 changes: 0 additions & 76 deletions docs/scripts/prepare_nbconvert_css.py

This file was deleted.

2 changes: 1 addition & 1 deletion fern/components/NotebookViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import type { ReactNode } from "react";
* The trust boundary is the converter pipeline:
*
* docs/notebook_source/*.py (jupytext source — code-reviewed at PR time)
* └─> jupytext --execute (runs in CI/maintainer shell with NVIDIA_API_KEY)
* └─> jupytext + jupyter-execute (runs in CI/maintainer shell with NVIDIA_API_KEY)
* └─> *.ipynb (real outputs captured)
* └─> fern/scripts/ipynb-to-fern-json.py
* └─> fern/components/notebooks/*.{json,ts} (committed)
Expand Down
Loading
Loading