DataDesigner/Makefile
Lawrence Lane 7b5854ca36
docs: migrate documentation from MkDocs to Fern (#581)
* docs: migrate documentation from MkDocs to Fern

Adds a Fern Docs build under fern/ alongside the existing mkdocs site.
Production target docs.nvidia.com/nemo/datadesigner with floating-latest
pointer (latest.yml symlink) at v0.5.8. Migrated all concept, recipe, plugin,
dev-note, and tutorial pages to MDX with NVIDIA theme and custom components
(Authors, MetricsTable, TrajectoryViewer, NotebookViewer, BadgeLinks).
Tutorial notebooks now render via NotebookViewer with captured outputs (text,
DataFrames, inline images) - new make targets generate-fern-notebooks and
generate-fern-notebooks-with-outputs drive the .py -> executed .ipynb -> Fern
JSON+TS pipeline, pinning docs to Python 3.13 to dodge pyarrow wheel issues
on 3.14. Python API reference is configured via Fern libraries: pointing at
data-designer-config; output is gitignored and regenerated locally with
'fern docs md generate'.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Lawrence Lane <llane@nvidia.com>

* docs: add datadesigner-docs agent skill

Captures the patterns established in the Fern migration so agents (and humans)
can maintain fern/ confidently. Modeled after NVIDIA-NeMo/Gym's
nemo-gym-docs SKILL.md, adapted for our floating-latest versioning,
notebook-with-outputs pipeline, dev-notes kit components, and the MDX gotchas
hit during migration (pymdown attr_list, --8<-- snippet syntax, frontmatter
authors-as-JSX-scope-variable, etc.). Routes triggers like "edit docs", "add
doc page", "regenerate notebooks", "update dev note", "add API reference" to
this skill.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Lawrence Lane <llane@nvidia.com>

* docs: address PR review for Fern migration

- Delete stale fern/versions/_nav_order.yml (references non-existent
  ./versions/latest/pages/ — paths were never updated when latest/ was
  renamed to v0.5.8/, no consumer found in docs.yml or v0.5.8.yml).
- Remove unused custom components: Tag.tsx, CustomCard.tsx, Include.tsx
  (had its own untested markdown parser), ExpandableCode.tsx (broken in
  Fern SSR runtime). Drop expandable-code.css from docs.yml. Authors,
  BadgeLinks, MetricsTable, NotebookViewer, TrajectoryViewer remain
  (each has at least one call site).
- BadgeLinks: remove DEFAULT_BADGES with placeholder URLs; make `badges`
  prop required so we can never accidentally ship 'your-org/your-repo'.
- NotebookViewer: document the XSS trust boundary on output cells of
  format: "html". Outputs flow .py source → jupytext --execute → committed
  *.ts (review boundary). Add an inline comment at the dangerouslySetInnerHTML
  call site pointing back to the trust-model section.
- README: add Windows caveat on the latest.yml symlink — Windows users need
  core.symlinks=true before clone or Fern will reject the version config.
- Makefile: tighten generate-fern-notebooks source probe from `ls .../*.ipynb`
  (which can return success on non-file errors) to `[ -f docs/notebooks/1-the-basics.ipynb ]`,
  matching the reviewer's suggestion.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Lawrence Lane <llane@nvidia.com>

* docs: address @aschilling-nv review on fern/docs.yml

Three suggestions from the Fern review, all matching Curator's docs.yml
conventions:

- instances[0].url: drop the https:// protocol prefix to match Curator's
  shape (e.g. nemo-curator.docs.buildwithfern.com/nemo/curator).
- logo.href: was '/'; now points at /nemo/datadesigner/getting-started/welcome
  (the actual landing page) so clicking the logo lands on real content
  instead of the bare basepath.
- experimental.basepath-aware: true — opts into Fern's basepath-aware
  routing so internal links don't double-prefix the /nemo/datadesigner
  segment.
- redirects: also fix /nemo/datadesigner/index.html → getting-started/welcome
  (was bouncing to /latest, which is just the version slug); add
  /getting-started → /getting-started/welcome to mirror Curator's
  /home → /home/welcome convention.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Lawrence Lane <llane@nvidia.com>

* docs: put dev notes overview timestamps on separate lines

Signed-off-by: Kirit93 <kthadaka@nvidia.com>
Made-with: Cursor

* docs: redesign dev-notes index with BlogCard component

Replaces the generic <CardGroup>/<Card> grid (same green icon × 10, date
glued to bottom of description) with a purpose-built BlogCard for the
dev-notes landing page.

Each card now has:
- Hero image (16:9, lazy-loaded, click-to-zoom via Fern's rmiz wrapper)
- ALL-CAPS date eyebrow as proper subtitle styling
- Title, 3-line clamped description
- Author byline at the bottom: avatar stack (overlapping) + first author
  name + "+N", pulling from the existing devnotes/.authors.yml registry
- Hover: NVIDIA-green border + subtle lift

Posts without a hero image fall back to a deterministic hash-based
gradient placeholder + monogram (DJB2 hash of href → HSL hue, with the
muddy-yellow band 40–90° remapped). Same post always gets the same look.

Notes:
- Image prop is React.ReactNode (not string) — pass <img> JSX from MDX
  so Fern's link rewriter can resolve the src to /_local/... in dev and
  /nemo/datadesigner/assets/... in prod. Raw string props bypass the
  rewriter and 404 in dev.
- Card href runs through a small withBasepath() helper since the <a>
  also bypasses Fern's link rewriter.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Lawrence Lane <llane@nvidia.com>

* docs: flush blog-card hero images to the top of the card

Fern's prose stylesheet applies a top margin to <img> tags, and the
click-to-zoom wrapper Fern injects around each image (<span data-rmiz>)
inherits that margin too. Result: a ~1rem gap between the card's top
edge and the hero image.

Reset margin/padding on the rmiz wrapper spans + the img itself inside
.blog-card__media so the image renders flush against the top border.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Lawrence Lane <llane@nvidia.com>

* docs: stop blog-card hero from opening Fern's click-to-zoom modal

When an <img> appears in MDX, Fern auto-wraps it with a click-to-zoom
shell (<span data-rmiz>...). On the dev-notes index that shell intercepts
clicks meant for the card's <a> wrapper, so clicking a hero opens a
lightbox AND tries to navigate.

Set pointer-events: none on the rmiz spans + img inside .blog-card__media
so clicks bubble straight to the parent <a> and the card behaves as a
single, predictable link target. Hover still works because pointer-events
on children doesn't block :hover on the ancestor <a>.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Lawrence Lane <llane@nvidia.com>

* docs: render notebook markdown at build time with markdown-it-py

Replaces NotebookViewer's hand-rolled JS markdown parser (the one with
the ^@BR^@ sentinel the reviewer flagged as fragile) with build-time
rendering in the converter.

ipynb-to-fern-json.py now uses markdown-it-py (CommonMark + tables +
strikethrough + raw HTML) to render each markdown cell's source into
source_html, mirroring how code cells already store Pygments-highlighted
source_html. NotebookViewer's markdown branch becomes a single
dangerouslySetInnerHTML on the pre-rendered HTML, with a plain-escape
fallback for old snapshots.

Removes the dead JS helpers (renderMarkdown, isSafeUrl, UL_CLASS,
OL_CLASS) — ~60 lines of brittle regex-based markdown parsing.

Fixes broken rendering of:
- Blockquotes (showed literal > characters before)
- Nested content inside blockquotes (e.g. blockquote with bullet list)
- Fenced code blocks
- Tables
- Multi-paragraph list items

Includes regenerated fern/components/notebooks/*.{json,ts} for all 6
tutorials.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Lawrence Lane <llane@nvidia.com>

* docs: rewrite recipes index + replace octicons download links with Fern Info callouts

The recipes/cards.mdx page was still in MkDocs Material format:
- <div class="grid cards" markdown> wrapper (no-op in MDX)
- :material-snake:, :material-database:, :material-tools:, etc. (rendered
  as literal text — Fern uses Font Awesome, not Material icons)
- !!! tip Prerequisite (mkdocs admonition syntax)
- [:material-book-open-page-variant: View Recipe] / [Download Code
  :octicons-download-24:] links with embedded icon shortcodes

Rewrite using Fern's native components: <CardGroup cols={2}> with <Card
title icon href> grouped by category (Code Generation, QA and Chat,
Trace Ingestion, MCP and Tool Use, Plugin Development). Each card has
one primary action (the recipe page); download lives on the recipe page
itself.

Replace the trailing "Download Code :octicons-download-24:" link on
every recipe page (and 2 dev notes) with a <Info title="Download Recipe">
callout pointing at the GitHub blob URL — matching PR #215's
convention. 12 occurrences across 12 files.

Also fixes 6 recipe pages whose frontmatter title was "Untitled"
(unfilled placeholder from auto-migration): text_to_python, basic_mcp,
pdf_qa, multi_turn_chat, product_info_qa, agent_rollout_distillation.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Lawrence Lane <llane@nvidia.com>

* docs(fern): mirror main's content updates into v0.5.8 MDX pages

Forward-port the doc changes that landed in main since this branch was
cut, translating MkDocs admonition syntax to Fern components. Three
product changes drove the updates:

PR #594 — deprecate implicit default-provider routing:
- concepts/models/configure-model-settings-with-the-cli.mdx: deprecate
  "Change default provider" workflow + inline mark on `data-designer
  config list` output
- concepts/models/custom-model-settings.mdx: warning that `provider=`
  is now required on every ModelConfig
- concepts/models/default-model-settings.mdx: warning that the
  registry-level default-provider concept is deprecated
- concepts/models/model-providers.mdx: same warning at the top of the
  ModelProvider overview
- concepts/models/inference-parameters.mdx: add explicit `provider=
  "openai"` to the dalle ModelConfig example

PR #592 — async engine becomes the default:
- concepts/architecture-and-performance.mdx: rewrite Execution Model
  intro to mention both engines, qualify "How It Works" as sync-engine
  semantics, update Concurrency Formula and Throttle notes from "Sync
  engine caveat" to "Engine paths", and add a full new "## Async
  Engine" section (per-model timeouts, run outcomes / Early Shutdown,
  opt-out via DATA_DESIGNER_ASYNC_ENGINE=0). Add `provider="nvidia"`
  to the my-model example.
- concepts/custom_columns.mdx: note that sync `cell_by_cell`
  generators dispatch concurrently under the async engine; mock with
  `MagicMock(spec=ModelFacade)` so async methods are auto-detected.
- concepts/processors.mdx: warning that the async engine enforces
  row-count invariance in process_before/after_batch.
- devnotes/posts/async-all-the-way-down.mdx: append an "Update" callout
  noting the engine is now default, with a link to the Architecture
  page anchor.

All `!!! warning|note|tip "Title"` admonitions converted to Fern
<Warning|Note|Tip title="..."> components. Internal links to mkdocs
relative paths (`../../concepts/foo.md#anchor`) rewritten to canonical
Fern URLs (`/concepts/foo#anchor`).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Lawrence Lane <llane@nvidia.com>

* docs(fern): address @andreatgretel review comments

Four issues from Andre's review pass:

1. /devnotes 404 (index.mdx:23) — section slug is /dev-notes, page slug
   is /dev-notes/overview. Fix the link in the landing page so visitors
   actually reach the dev notes index.

2. TrajectoryViewer.tsx final-answer body shown as literal markdown
   (line 66) — the renderer uses dangerouslySetInnerHTML but
   example-marcia.ts shipped raw markdown (**bold**, \n\n breaks). Visible
   on the deep-research devnote where the trajectory is defaultOpen.
   Pre-render body to HTML in the fixture (matches the original hand-coded
   format pre-migration); document the convention in the ToolCall.body
   doc comment so future fixtures don't regress.

3. Tutorials 5/6 (image generation/editing) ship with 0 captured outputs
   because Flux runs through OpenRouter and OPENROUTER_API_KEY isn't set
   at build time. Cannot regenerate without the key, so add a <Note> at
   the top of each wrapper page pointing readers at the Colab link to
   execute the cells live and see the generated images. Maintainers with
   the key in their environment should re-run
   `make generate-fern-notebooks-with-outputs` before merge to capture
   the snapshots.

4. Legacy nvidia-nemo.github.io/DataDesigner/* URLs in MDX prose (8
   occurrences across 5 files) rewritten to canonical Fern paths so
   visitors don't get sent back to the legacy GitHub Pages site once
   docs.nvidia.com/nemo/datadesigner becomes the production URL:
   - The single deep link in data-designer-got-skills.mdx →
     /concepts/models/default-model-settings
   - All other "documentation home" links (CONTRIBUTING ×2,
     async-all-the-way-down ×2, owning-the-model-stack, design-principles
     ×2) → /getting-started/welcome (the canonical landing slug, matches
     logo.href in docs.yml)

   Notebook .py source URLs are tracked separately as part of the
   notebook-regen work.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Lawrence Lane <llane@nvidia.com>

* docs(fern): regenerate notebook snapshots with Flux outputs captured

Re-ran make generate-fern-notebooks-with-outputs with NVIDIA_API_KEY +
OPENROUTER_API_KEY set, now that we have a NVIDIA key with permission
on nemotron-3-nano-30b-a3b. All 6 tutorials regenerated; the two image
tutorials (5 and 6) which had been shipping with 0 outputs now have
captured Flux generations:

  1 the-basics:                12/15 outputs
  2 structured-outputs:        13/17 outputs
  3 seeding-with-a-dataset:    10/13 outputs
  4 providing-images:          13/17 outputs (1 image)
  5 generating-images:          8/10 outputs (2 images) ← was 0/12
  6 image-to-image-editing:     9/12 outputs (10 images) ← was 0/14

The two `<Note title="Run in Colab to see ...">` workarounds I added on
the 5/6 wrapper pages are no longer needed — outputs render inline now.
NotebookViewer's own "Run in Google Colab" banner is still rendered
from the wrapper's `colabUrl` prop, so the live-execute path stays one
click away.

Bumps the diff size noticeably (notebook 6 .ts is ~22MB of base64-
encoded PNGs from 10 edited images), but that's intentional — these
images are the proof points for what the Flux/MCP image-context
tutorials actually produce.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Lawrence Lane <llane@nvidia.com>

* docs(fern): unbreak SSR — shrink notebook image outputs + fix BlogCard React import

Two server-side render bugs surfaced when running `fern docs md generate &&
fern docs dev` (the static-preview path):

1. The 22 MB notebook 6 .ts module (full-resolution Flux PNGs from 10 edited
   images) tripped Fern's SSR module-evaluation step. Once that module
   failed to evaluate, the shared component bundle failed to load on every
   page, replacing each MDX body with `<span data-intent="error">Something
   went wrong!</span>` while the layout chrome continued to render.

   Fix in fern/scripts/ipynb-to-fern-json.py: after extracting an
   image/png output, pass it through Pillow to (a) downscale so the
   longest edge is at most 800 px, (b) re-encode as JPEG q=82 progressive
   (Flux outputs are photographic — JPEG compresses 5–10× better than PNG
   for this content). NotebookViewer's CellOutput interface gains a
   `mime` field so the data URL uses the actual encoded MIME type. Result:

       notebook 6: 22 MB → 4.6 MB
       notebook 5: 3.8 MB → 1.8 MB
       notebook 4: 514 KB → 116 KB
       (notebooks 1–3 unaffected — no image outputs)

2. fern/components/BlogCard.tsx referenced `React.ReactNode` twice without
   importing React. Other components in the kit use `import type
   { ReactNode } from "react"`; BlogCard was the outlier. Aligned the
   import style — even though this didn't end up being the trigger, leaving
   the dangling reference would have eventually caused a strict-mode SSR
   regression.

Sweep test against http://localhost:3000/nemo/datadesigner/* — landing,
concepts, tutorials (including 5/6 image notebooks), dev notes, recipes,
and code-reference topic pages all render with their content; no error
spans.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Lawrence Lane <llane@nvidia.com>

* docs(fern): add MkDocs-shape redirects for legacy URLs

The legacy site at https://nvidia-nemo.github.io/DataDesigner/ used
MkDocs-Material conventions (mkdocstrings + blog plugin + mkdocs-jupyter
+ directory URLs). Several path segments and page slugs differ from
Fern's slugified-title routing — search-engine indexed links and
copy-pasted bookmarks land on 404 without redirects.

Adds 30+ specific redirect rules covering every renamed surface:

- Tutorials: /notebooks/<filename>/ -> /tutorials/<title-slug>
  (page-title slugs differ from .ipynb filenames; one rule per notebook
   plus a README -> overview alias).

- Recipes: /recipes/<snake_subsection>/<snake_page>/ ->
  /recipes/<kebab-subsection>/<kebab-page>. Per-page rules for each of
  the 10 recipes (page titles diverged from .py filenames — e.g.
  basic_mcp -> basic-mcp-tool-use, search_agent -> nemotron-super-search-agent),
  followed by subsection :rest* fallbacks.

- Concepts: /concepts/mcp/* -> /concepts/tool-use-mcp/* (subsection
  rename, with & dropped, not -and-). Per-page rules for safety-and-limits
  -> safety-limits and configure-mcp-cli -> cli-configuration where
  page titles diverged from filenames.

- Code Reference: /code_reference/<module>/ ->
  /code-reference/topic-overviews/<module>. Per-page rules for the six
  underscored modules (column_configs, config_builder, run_config,
  sampler_params, validator_params, data_designer_config) since Fern's
  page-slug rule kebabs underscores.

- Plugins: filesystem_seed_reader -> file-system-seed-reader-plugins
  (Fern inserts hyphens between CamelCase words). example -> example-plugin,
  available -> available-plugin-list (page-title slugs).

- Dev Notes: blog plugin's /devnotes/posts/<slug>/ -> /dev-notes/<slug>.
  Per-page rules for text-to-sql -> text-to-sql-for-nemotron-super and
  rqa -> rqa-dataset (post titles diverged from filenames).

- /devnotes -> /dev-notes/overview (section landing).

MkDocs's directory-URL trailing-slash convention is handled natively by
Fern's runtime (both /foo and /foo/ return the same page), so no
explicit slash-strip rule is needed.

Smoke-tested all 34 legacy URLs against http://localhost:3000 — every
one resolves to a 200 page on the new structure.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Lawrence Lane <llane@nvidia.com>

---------

Signed-off-by: Lawrence Lane <llane@nvidia.com>
Signed-off-by: Kirit93 <kthadaka@nvidia.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Kirit93 <kthadaka@nvidia.com>
Co-authored-by: Andre Manoel <165937436+andreatgretel@users.noreply.github.com>
2026-05-07 14:12:58 -03:00

692 lines
32 KiB
Makefile

# ==============================================================================
# VARIABLES AND FUNCTIONS
# ==============================================================================
REPO_PATH := $(shell pwd)
# Package directories
CONFIG_PKG := packages/data-designer-config
ENGINE_PKG := packages/data-designer-engine
INTERFACE_PKG := packages/data-designer
# Package source and test paths
CONFIG_PATHS := $(CONFIG_PKG)/src $(CONFIG_PKG)/tests
ENGINE_PATHS := $(ENGINE_PKG)/src $(ENGINE_PKG)/tests
INTERFACE_PATHS := $(INTERFACE_PKG)/src $(INTERFACE_PKG)/tests $(INTERFACE_PKG)/dev-tools
ALL_PKG_PATHS := packages/ scripts/ tests_e2e/
# Test directories
CONFIG_TESTS := $(CONFIG_PKG)/tests
ENGINE_TESTS := $(ENGINE_PKG)/tests
INTERFACE_TESTS := $(INTERFACE_PKG)/tests
define install-pre-commit-hooks
@if [ ! -f $(REPO_PATH)/.git/hooks/pre-commit ]; then \
echo "🪝 Installing pre-commit hooks..."; \
uv run pre-commit install; \
else \
echo "👍 Pre-commit hooks already installed"; \
fi
endef
# ==============================================================================
# HELP
# ==============================================================================
help:
@echo ""
@echo "🚀 DataDesigner Makefile Commands"
@echo "═════════════════════════════════════════════════════════════"
@echo ""
@echo "📦 Installation (uv workspace - all packages in editable mode):"
@echo " install - Install all packages (config → engine → interface)"
@echo " install-dev - Install all packages + dev tools (pytest, etc.)"
@echo " install-dev-notebooks - Install all packages + dev + notebook tools"
@echo " install-dev-recipes - Install all packages + dev + recipe dependencies"
@echo ""
@echo "🧪 Testing (all packages):"
@echo " test - Run all unit tests"
@echo " coverage - Run tests with coverage report"
@echo " test-e2e - Run e2e plugin tests"
@echo " health-checks - Run provider health checks"
@echo " test-run-tutorials - Run tutorial notebooks as e2e tests"
@echo " test-run-recipes - Run recipe scripts as e2e tests"
@echo " test-run-all-examples - Run all tutorials and recipes as e2e tests"
@echo ""
@echo "🔬 Isolated Testing (mirrors CI - uses temp venv):"
@echo " test-isolated - Run all isolated tests (config → engine → interface)"
@echo " test-config-isolated - Test config with ONLY config installed"
@echo " test-engine-isolated - Test engine with ONLY engine+config installed"
@echo " test-interface-isolated - Test interface with full package installed"
@echo ""
@echo "✨ Code Quality (all packages):"
@echo " format - Format all code with ruff"
@echo " format-check - Check code formatting without making changes"
@echo " lint - Lint all code with ruff"
@echo " lint-fix - Fix linting issues automatically"
@echo " build - Build all package wheels"
@echo ""
@echo "🔍 Combined Checks:"
@echo " check-all - Run all checks (format-check + lint)"
@echo " check-all-fix - Run all checks with autofix (format + lint-fix)"
@echo ""
@echo "🛠️ Utilities:"
@echo " clean - Remove coverage reports, cache files, and dist"
@echo " clean-dist - Remove dist directories from all packages"
@echo " verify-imports - Verify all package imports work"
@echo " show-versions - Show versions of all packages"
@echo " convert-execute-notebooks - Convert notebooks from .py to .ipynb using jupytext (USE_CACHE=1 to skip unchanged)"
@echo " generate-colab-notebooks - Generate Colab-compatible notebooks"
@echo " generate-fern-notebooks - Convert docs/colab_notebooks/*.ipynb → fern/components/notebooks/{json,ts}"
@echo " generate-fern-notebooks-with-outputs - Full pipeline: execute notebooks (needs API key), colabify, convert to Fern"
@echo " serve-docs-locally - Serve documentation locally"
@echo " (For Fern preview: 'cd fern && fern docs md generate && fern docs dev'.)"
@echo " check-license-headers - Check if all files have license headers"
@echo " update-license-headers - Add license headers to all files"
@echo ""
@echo "⚡ Performance:"
@echo " perf-import - Profile pure import time and show summary"
@echo " perf-import CLEAN=1 - Clean cache, then profile pure import time"
@echo " perf-import NOFILE=1 - Profile pure import without writing to file (for CI)"
@echo " perf-import-runtime - Profile runtime init time (constructors included)"
@echo " bench-cli-startup - Benchmark CLI startup (isolated venv)"
@echo " bench-cli-startup-verbose - Benchmark CLI startup with import trace"
@echo ""
@echo "🚀 Publish:"
@echo " publish VERSION=X.Y.Z - Publish all packages to PyPI"
@echo " publish VERSION=X.Y.Z DRY_RUN=1 - Dry run (no tags or uploads)"
@echo " publish VERSION=X.Y.Z TEST_PYPI=1 - Publish to TestPyPI"
@echo " publish VERSION=X.Y.Z ALLOW_BRANCH=1 - Publish from non-main branch"
@echo " publish VERSION=X.Y.Z FORCE_TAG=1 - Overwrite existing git tag"
@echo ""
@echo "📦 Per-Package Commands (use suffix: -config, -engine, -interface):"
@echo " test-<pkg> - Run tests for a specific package"
@echo " lint-<pkg> - Lint a specific package"
@echo " lint-fix-<pkg> - Fix lint issues in a specific package"
@echo " format-<pkg> - Format a specific package"
@echo " format-check-<pkg> - Check formatting for a specific package"
@echo " check-<pkg> - Check format + lint for a specific package"
@echo " build-<pkg> - Build wheel for a specific package"
@echo " coverage-<pkg> - Run tests with coverage for a specific package"
@echo ""
@echo "═════════════════════════════════════════════════════════════"
@echo "💡 Tip: Run 'make <command>' to execute any command above"
@echo ""
# ==============================================================================
# INSTALLATION
# ==============================================================================
install:
@echo "📦 Installing DataDesigner workspace (all packages in editable mode)..."
@echo " Packages: data-designer-config → data-designer-engine → data-designer"
uv sync --all-packages
@echo "✅ Installation complete!"
@echo ""
@echo "💡 Run 'make verify-imports' to verify all packages are working"
install-dev:
@echo "📦 Installing DataDesigner workspace in development mode..."
@echo " Packages: data-designer-config → data-designer-engine → data-designer"
@echo " Groups: dev (pytest, coverage, etc.)"
uv sync --all-packages --group dev
$(call install-pre-commit-hooks)
@echo ""
@echo "✅ All packages installed in development mode!"
@echo ""
@echo "📁 Workspace structure:"
@echo " packages/data-designer-config/ - Configuration layer (lightweight)"
@echo " packages/data-designer-engine/ - Generation engine (heavy deps)"
@echo " packages/data-designer/ - Full package with CLI"
@echo ""
@echo "💡 Next steps:"
@echo " make verify-imports - Verify all packages are working"
@echo " make test - Run all tests across packages"
@echo " make test-<pkg> - Run tests for specific package (config, engine, interface)"
@echo " make lint - Lint all code"
@echo " make build - Build all package wheels"
install-dev-notebooks:
@echo "📦 Installing DataDesigner workspace with notebook dependencies..."
@echo " Packages: data-designer-config → data-designer-engine → data-designer"
@echo " Groups: dev + notebooks (Jupyter, jupytext, etc.)"
uv sync --all-packages --group dev --group notebooks
$(call install-pre-commit-hooks)
@echo "✅ Dev + notebooks installation complete!"
@echo ""
@echo "💡 Run 'make test-run-tutorials' to test notebook tutorials"
install-dev-recipes:
@echo "📦 Installing DataDesigner workspace with recipe dependencies..."
@echo " Packages: data-designer-config → data-designer-engine → data-designer"
@echo " Groups: dev + recipes (bm25s, pymupdf, etc.)"
uv sync --all-packages --group dev --group recipes
$(call install-pre-commit-hooks)
@echo "✅ Dev + recipes installation complete!"
@echo ""
@echo "💡 Run 'make test-run-recipes' to test recipe scripts"
# ==============================================================================
# TESTING
# ==============================================================================
test: test-config test-engine test-interface
@echo "✅ All package tests complete!"
test-config:
@echo "🧪 Testing data-designer-config..."
uv run --group dev pytest $(CONFIG_TESTS)
test-engine:
@echo "🧪 Testing data-designer-engine..."
uv run --group dev pytest $(ENGINE_TESTS)
test-interface:
@echo "🧪 Testing data-designer (interface)..."
uv run --group dev pytest $(INTERFACE_TESTS)
# ------------------------------------------------------------------------------
# Isolated Testing (mirrors CI behavior)
# Each package is installed independently to verify dependency boundaries
# Uses temporary virtual environments to avoid affecting the main dev environment
# ------------------------------------------------------------------------------
# Test dependencies added via --with since workspace groups aren't available with --package
TEST_DEPS := --with pytest --with pytest-asyncio --with pytest-httpx --with pytest-env
test-isolated:
@echo "🧪 Running all isolated package tests..."
@echo ""
@CONFIG_RESULT=0; ENGINE_RESULT=0; INTERFACE_RESULT=0; \
$(MAKE) test-config-isolated || CONFIG_RESULT=1; \
echo ""; \
$(MAKE) test-engine-isolated || ENGINE_RESULT=1; \
echo ""; \
$(MAKE) test-interface-isolated || INTERFACE_RESULT=1; \
echo ""; \
echo "═══════════════════════════════════════════════════════════"; \
echo "📊 Isolated Test Summary:"; \
if [ $$CONFIG_RESULT -eq 0 ]; then echo " ✅ Config tests passed"; else echo " ❌ Config tests FAILED"; fi; \
if [ $$ENGINE_RESULT -eq 0 ]; then echo " ✅ Engine tests passed"; else echo " ❌ Engine tests FAILED"; fi; \
if [ $$INTERFACE_RESULT -eq 0 ]; then echo " ✅ Interface tests passed"; else echo " ❌ Interface tests FAILED"; fi; \
echo "═══════════════════════════════════════════════════════════"; \
if [ $$CONFIG_RESULT -ne 0 ] || [ $$ENGINE_RESULT -ne 0 ] || [ $$INTERFACE_RESULT -ne 0 ]; then \
echo "❌ Some isolated tests FAILED!"; \
exit 1; \
fi; \
echo "✅ All isolated package tests passed!"
test-config-isolated:
@echo "🧪 Testing data-designer-config in isolation..."
@ISOLATED_VENV=$$(mktemp -d); \
trap "rm -rf $$ISOLATED_VENV" EXIT; \
echo " Creating isolated environment in $$ISOLATED_VENV..."; \
echo " Installing config package only (no engine/interface)..."; \
UV_PROJECT_ENVIRONMENT="$$ISOLATED_VENV" uv sync --package data-designer-config && \
UV_PROJECT_ENVIRONMENT="$$ISOLATED_VENV" uv run $(TEST_DEPS) pytest -v $(CONFIG_TESTS) && \
echo "✅ Config tests passed in isolation!" || \
{ echo "❌ Config tests FAILED in isolation!"; exit 1; }
test-engine-isolated:
@echo "🧪 Testing data-designer-engine in isolation..."
@ISOLATED_VENV=$$(mktemp -d); \
trap "rm -rf $$ISOLATED_VENV" EXIT; \
echo " Creating isolated environment in $$ISOLATED_VENV..."; \
echo " Installing engine package only (auto-includes config)..."; \
UV_PROJECT_ENVIRONMENT="$$ISOLATED_VENV" uv sync --package data-designer-engine && \
UV_PROJECT_ENVIRONMENT="$$ISOLATED_VENV" uv run $(TEST_DEPS) pytest -v $(ENGINE_TESTS) && \
echo "✅ Engine tests passed in isolation!" || \
{ echo "❌ Engine tests FAILED in isolation!"; exit 1; }
test-interface-isolated:
@echo "🧪 Testing data-designer (interface) in isolation..."
@ISOLATED_VENV=$$(mktemp -d); \
trap "rm -rf $$ISOLATED_VENV" EXIT; \
echo " Creating isolated environment in $$ISOLATED_VENV..."; \
echo " Installing interface package (auto-includes config + engine)..."; \
UV_PROJECT_ENVIRONMENT="$$ISOLATED_VENV" uv sync --package data-designer && \
UV_PROJECT_ENVIRONMENT="$$ISOLATED_VENV" uv run $(TEST_DEPS) pytest -v $(INTERFACE_TESTS) && \
echo "✅ Interface tests passed in isolation!" || \
{ echo "❌ Interface tests FAILED in isolation!"; exit 1; }
# Note: coverage runs all tests in a single pytest invocation for combined coverage reporting.
# This is intentionally different from calling coverage-config/engine/interface individually.
coverage:
@echo "📊 Running tests with coverage analysis (all packages)..."
uv run --group dev pytest \
$(CONFIG_TESTS) \
$(ENGINE_TESTS) \
$(INTERFACE_TESTS) \
--cov=data_designer \
--cov-report=term-missing \
--cov-report=html
@echo "✅ Coverage report generated in htmlcov/index.html"
coverage-config:
@echo "📊 Running config tests with coverage..."
uv run --group dev pytest $(CONFIG_TESTS) --cov=data_designer --cov-report=term-missing --cov-report=html
coverage-engine:
@echo "📊 Running engine tests with coverage..."
uv run --group dev pytest $(ENGINE_TESTS) --cov=data_designer --cov-report=term-missing --cov-report=html
coverage-interface:
@echo "📊 Running interface tests with coverage..."
uv run --group dev pytest $(INTERFACE_TESTS) --cov=data_designer --cov-report=term-missing --cov-report=html
test-e2e:
@echo "🧹 Cleaning e2e test environment..."
rm -rf tests_e2e/uv.lock tests_e2e/__pycache__ tests_e2e/.venv
@echo "🧪 Running e2e tests..."
uv run --no-cache --refresh --directory tests_e2e pytest -s
health-checks:
@echo "🏥 Running provider health checks..."
uv run --group dev python scripts/health_checks.py
test-run-tutorials:
@echo "🧪 Running tutorials as e2e tests..."
@TUTORIAL_WORKDIR=$$(mktemp -d); \
trap "rm -rf $$TUTORIAL_WORKDIR" EXIT; \
for f in docs/notebook_source/*.py; do \
echo " 📓 Running $$f..."; \
(cd "$$TUTORIAL_WORKDIR" && uv run --project "$(REPO_PATH)" --group notebooks python "$(REPO_PATH)/$$f") || exit 1; \
done; \
echo "🧹 Cleaning up tutorial artifacts..."; \
rm -rf "$$TUTORIAL_WORKDIR"; \
echo "✅ All tutorials completed successfully!"
test-run-recipes:
@echo "🧪 Running recipes as e2e tests..."
@RECIPE_WORKDIR=$$(mktemp -d); \
trap "rm -rf $$RECIPE_WORKDIR" EXIT; \
for f in docs/assets/recipes/**/*.py; do \
echo " 📜 Running $$f..."; \
(cd "$$RECIPE_WORKDIR" && uv run --project "$(REPO_PATH)" --group notebooks --group recipes python "$(REPO_PATH)/$$f" --model-alias nvidia-text --artifact-path "$$RECIPE_WORKDIR" --num-records 5) || exit 1; \
done; \
echo "🧹 Cleaning up recipe artifacts..."; \
rm -rf "$$RECIPE_WORKDIR"; \
echo "✅ All recipes completed successfully!"
test-run-all-examples: test-run-tutorials test-run-recipes
@echo "✅ All examples (tutorials + recipes) completed successfully!"
# ==============================================================================
# CODE QUALITY - FORMATTING
# ==============================================================================
format: format-config format-engine format-interface
@echo "📐 Formatting scripts and tests_e2e..."
uv run ruff format scripts/ tests_e2e/
@echo "✅ Formatting complete!"
format-check: format-check-config format-check-engine format-check-interface
@echo "📐 Checking scripts and tests_e2e formatting..."
uv run ruff format --check scripts/ tests_e2e/
@echo "✅ Formatting check complete! Run 'make format' to auto-fix issues."
format-config:
@echo "📐 Formatting data-designer-config..."
uv run ruff format $(CONFIG_PATHS) --exclude '**/_version.py'
format-engine:
@echo "📐 Formatting data-designer-engine..."
uv run ruff format $(ENGINE_PATHS) --exclude '**/_version.py'
format-interface:
@echo "📐 Formatting data-designer (interface)..."
uv run ruff format $(INTERFACE_PATHS) --exclude '**/_version.py'
format-check-config:
@echo "📐 Checking data-designer-config formatting..."
uv run ruff format --check $(CONFIG_PATHS) --exclude '**/_version.py'
format-check-engine:
@echo "📐 Checking data-designer-engine formatting..."
uv run ruff format --check $(ENGINE_PATHS) --exclude '**/_version.py'
format-check-interface:
@echo "📐 Checking data-designer (interface) formatting..."
uv run ruff format --check $(INTERFACE_PATHS) --exclude '**/_version.py'
# ==============================================================================
# CODE QUALITY - LINTING
# ==============================================================================
lint: lint-config lint-engine lint-interface
@echo "🔍 Linting scripts and tests_e2e..."
uv run ruff check --output-format=full scripts/ tests_e2e/
@echo "✅ Linting complete! Run 'make lint-fix' to auto-fix issues."
lint-fix: lint-fix-config lint-fix-engine lint-fix-interface
@echo "🔍 Fixing lint issues in scripts and tests_e2e..."
uv run ruff check --fix scripts/ tests_e2e/
@echo "✅ Linting with autofix complete!"
lint-config:
@echo "🔍 Linting data-designer-config..."
uv run ruff check --output-format=full $(CONFIG_PATHS) --exclude '**/_version.py'
lint-engine:
@echo "🔍 Linting data-designer-engine..."
uv run ruff check --output-format=full $(ENGINE_PATHS) --exclude '**/_version.py'
lint-interface:
@echo "🔍 Linting data-designer (interface)..."
uv run ruff check --output-format=full $(INTERFACE_PATHS) --exclude '**/_version.py'
lint-fix-config:
@echo "🔍 Fixing lint issues in data-designer-config..."
uv run ruff check --fix $(CONFIG_PATHS) --exclude '**/_version.py'
lint-fix-engine:
@echo "🔍 Fixing lint issues in data-designer-engine..."
uv run ruff check --fix $(ENGINE_PATHS) --exclude '**/_version.py'
lint-fix-interface:
@echo "🔍 Fixing lint issues in data-designer (interface)..."
uv run ruff check --fix $(INTERFACE_PATHS) --exclude '**/_version.py'
# ==============================================================================
# CODE QUALITY - COMBINED CHECKS
# ==============================================================================
check-all: format-check lint
@echo "✅ All checks complete!"
check-all-fix: format lint-fix
@echo "✅ All checks with autofix complete!"
check-config: format-check-config lint-config
@echo "✅ Checks complete for data-designer-config!"
check-engine: format-check-engine lint-engine
@echo "✅ Checks complete for data-designer-engine!"
check-interface: format-check-interface lint-interface
@echo "✅ Checks complete for data-designer (interface)!"
# ==============================================================================
# BUILD
# ==============================================================================
build: build-config build-engine build-interface
@echo "✅ All packages built!"
build-config:
@echo "🏗️ Building data-designer-config..."
cd $(CONFIG_PKG) && uv build -o dist
build-engine:
@echo "🏗️ Building data-designer-engine..."
cd $(ENGINE_PKG) && uv build -o dist
build-interface:
@echo "🏗️ Building data-designer (interface)..."
cd $(INTERFACE_PKG) && uv build -o dist
# ==============================================================================
# UTILITIES
# ==============================================================================
verify-imports:
@echo "🔍 Verifying package imports..."
uv run python -c "from data_designer.config.config_builder import DataDesignerConfigBuilder; print(' ✓ config')"
uv run python -c "from data_designer.engine.compiler import compile_data_designer_config; print(' ✓ engine')"
uv run python -c "from data_designer.interface.data_designer import DataDesigner; print(' ✓ interface')"
@echo "✅ All imports verified!"
show-versions:
@echo "📦 Package versions:"
@uv run python -c "from data_designer.config._version import __version__; print(f' data-designer-config: {__version__}')" 2>/dev/null || echo " data-designer-config: (not installed)"
@uv run python -c "from data_designer.engine._version import __version__; print(f' data-designer-engine: {__version__}')" 2>/dev/null || echo " data-designer-engine: (not installed)"
@uv run python -c "from data_designer.interface._version import __version__; print(f' data-designer: {__version__}')" 2>/dev/null || echo " data-designer: (not installed)"
# ==============================================================================
# LICENSE HEADERS
# ==============================================================================
check-license-headers:
@echo "🔍 Checking license headers in all files..."
uv run python $(REPO_PATH)/scripts/update_license_headers.py --check
update-license-headers:
@echo "🔍 Updating license headers in all files..."
uv run python $(REPO_PATH)/scripts/update_license_headers.py
# ==============================================================================
# DOCUMENTATION
# ==============================================================================
# Pin the docs/notebook toolchain to a Python with prebuilt pyarrow wheels.
# pyarrow doesn't yet ship wheels for Python 3.14+, so docs builds fall back to
# a from-source compile (cmake + Apache Arrow C++) on those interpreters and fail.
# Override per-invocation: `DOCS_PYTHON=3.12 make generate-fern-notebooks-with-outputs`.
# uv auto-installs the requested version if it isn't present locally.
DOCS_PYTHON ?= 3.13
UV_DOCS := uv run --python $(DOCS_PYTHON)
# Route urllib/requests/httpx through certifi's CA bundle. Necessary when uv
# resolves $(DOCS_PYTHON) to a python.org installer build, which ships without
# populated CA certs (notebook 3 downloads a CSV over HTTPS at exec time).
DOCS_CERTS = SSL_CERT_FILE=$$($(UV_DOCS) --group docs python -c "import certifi; print(certifi.where())") \
REQUESTS_CA_BUNDLE=$$($(UV_DOCS) --group docs python -c "import certifi; print(certifi.where())")
serve-docs-locally:
@echo "📝 Building and serving docs (Python $(DOCS_PYTHON))..."
uv sync --python $(DOCS_PYTHON) --group docs
$(UV_DOCS) mkdocs serve --livereload
convert-execute-notebooks:
ifeq ($(USE_CACHE),1)
@echo "📓 Converting Python tutorials to notebooks (with caching)..."
@bash docs/scripts/build_notebooks_cached.sh
else
@echo "📓 Converting Python tutorials to notebooks and executing (Python $(DOCS_PYTHON))..."
@mkdir -p docs/notebooks
cp docs/notebook_source/_README.md docs/notebooks/README.md
cp docs/notebook_source/_pyproject.toml docs/notebooks/pyproject.toml
@$(DOCS_CERTS) bash -c '\
failed=""; \
for f in docs/notebook_source/*.py; do \
[ -f "$$f" ] || continue; \
echo "▶ executing $$f"; \
$(UV_DOCS) --all-packages --group notebooks --group docs jupytext --to ipynb --execute "$$f" || failed="$$failed\n • $$f"; \
done; \
if [ -n "$$failed" ]; then \
echo ""; \
echo "⚠️ Some notebooks failed (often missing API keys for image/audio providers)."; \
printf " Successful notebooks captured outputs; failed ones fall back to their existing snapshot.\n Failed:%b\n" "$$failed"; \
fi'
@for f in docs/notebook_source/*.ipynb; do [ -f "$$f" ] && mv "$$f" docs/notebooks/; done
@rm -rf docs/notebook_source/artifacts
@rm -f docs/notebook_source/*.csv
@echo "✅ Notebooks executed under docs/notebooks/"
endif
generate-colab-notebooks:
@echo "📓 Generating Colab-compatible notebooks (Python $(DOCS_PYTHON))..."
$(UV_DOCS) --group docs python docs/scripts/generate_colab_notebooks.py
@echo "✅ Colab notebooks created in docs/colab_notebooks/"
generate-fern-notebooks:
@echo "📓 Converting notebooks to Fern format for NotebookViewer (Python $(DOCS_PYTHON))..."
@mkdir -p fern/components/notebooks
@SOURCE_DIR=docs/colab_notebooks; \
if [ -f docs/notebooks/1-the-basics.ipynb ]; then \
SOURCE_DIR=docs/notebooks; \
echo " Source: $$SOURCE_DIR (executed; outputs preserved)"; \
else \
echo " Source: $$SOURCE_DIR (un-executed; no cell outputs — run 'make generate-fern-notebooks-with-outputs' to capture them)"; \
fi; \
for f in $$SOURCE_DIR/*.ipynb; do \
[ -f "$$f" ] || continue; \
name=$$(basename "$$f" .ipynb); \
$(UV_DOCS) --group docs python fern/scripts/ipynb-to-fern-json.py "$$f" -o fern/components/notebooks/$$name.json; \
done
@echo "✅ Fern notebooks created in fern/components/notebooks/"
generate-fern-notebooks-with-outputs: convert-execute-notebooks generate-colab-notebooks generate-fern-notebooks
@echo "✅ Full notebook pipeline complete (executed → colab → fern)"
# ==============================================================================
# PERFORMANCE
# ==============================================================================
perf-import:
ifdef CLEAN
@$(MAKE) clean-pycache
endif
@echo "⚡ Profiling pure import time for data_designer.config and DataDesigner symbol..."
ifdef NOFILE
@PERF_OUTPUT=$$(uv run python -X importtime -c "import data_designer.config as dd; from data_designer.interface import DataDesigner" 2>&1); \
echo "$$PERF_OUTPUT"; \
echo ""; \
echo "Summary:"; \
echo "$$PERF_OUTPUT" | tail -1 | awk '{printf " Total: %.3fs\n", $$5/1000000}'; \
echo ""; \
echo "💡 Top 10 slowest imports:"; \
printf "%-12s %-12s %s\n" "Self (s)" "Cumulative (s)" "Module"; \
printf "%-12s %-12s %s\n" "--------" "--------------" "------"; \
echo "$$PERF_OUTPUT" | grep "import time:" | sort -rn -k5 | head -10 | awk '{printf "%-12.3f %-12.3f %s", $$3/1000000, $$5/1000000, $$7; for(i=8;i<=NF;i++) printf " %s", $$i; printf "\n"}'
else
@PERF_FILE="perf_import_$$(date +%Y%m%d_%H%M%S).txt"; \
uv run python -X importtime -c "import data_designer.config as dd; from data_designer.interface import DataDesigner" > "$$PERF_FILE" 2>&1; \
echo "📊 Import profile saved to $$PERF_FILE"; \
echo ""; \
echo "Summary:"; \
tail -1 "$$PERF_FILE" | awk '{printf " Total: %.3fs\n", $$5/1000000}'; \
echo ""; \
echo "💡 Top 10 slowest imports:"; \
printf "%-12s %-12s %s\n" "Self (s)" "Cumulative (s)" "Module"; \
printf "%-12s %-12s %s\n" "--------" "--------------" "------"; \
grep "import time:" "$$PERF_FILE" | sort -rn -k5 | head -10 | awk '{printf "%-12.3f %-12.3f %s", $$3/1000000, $$5/1000000, $$7; for(i=8;i<=NF;i++) printf " %s", $$i; printf "\n"}'
endif
perf-import-runtime:
ifdef CLEAN
@$(MAKE) clean-pycache
endif
@echo "⚡ Profiling runtime initialization time (DataDesigner + DataDesignerConfigBuilder constructors)..."
ifdef NOFILE
@PERF_OUTPUT=$$(uv run python -X importtime -c "import data_designer.config as dd; from data_designer.interface import DataDesigner; DataDesigner(); dd.DataDesignerConfigBuilder()" 2>&1); \
echo "$$PERF_OUTPUT"; \
echo ""; \
echo "Summary:"; \
echo "$$PERF_OUTPUT" | tail -1 | awk '{printf " Total: %.3fs\n", $$5/1000000}'; \
echo ""; \
echo "💡 Top 10 slowest imports:"; \
printf "%-12s %-12s %s\n" "Self (s)" "Cumulative (s)" "Module"; \
printf "%-12s %-12s %s\n" "--------" "--------------" "------"; \
echo "$$PERF_OUTPUT" | grep "import time:" | sort -rn -k5 | head -10 | awk '{printf "%-12.3f %-12.3f %s", $$3/1000000, $$5/1000000, $$7; for(i=8;i<=NF;i++) printf " %s", $$i; printf "\n"}'
else
@PERF_FILE="perf_import_runtime_$$(date +%Y%m%d_%H%M%S).txt"; \
uv run python -X importtime -c "import data_designer.config as dd; from data_designer.interface import DataDesigner; DataDesigner(); dd.DataDesignerConfigBuilder()" > "$$PERF_FILE" 2>&1; \
echo "📊 Runtime import profile saved to $$PERF_FILE"; \
echo ""; \
echo "Summary:"; \
tail -1 "$$PERF_FILE" | awk '{printf " Total: %.3fs\n", $$5/1000000}'; \
echo ""; \
echo "💡 Top 10 slowest imports:"; \
printf "%-12s %-12s %s\n" "Self (s)" "Cumulative (s)" "Module"; \
printf "%-12s %-12s %s\n" "--------" "--------------" "------"; \
grep "import time:" "$$PERF_FILE" | sort -rn -k5 | head -10 | awk '{printf "%-12.3f %-12.3f %s", $$3/1000000, $$5/1000000, $$7; for(i=8;i<=NF;i++) printf " %s", $$i; printf "\n"}'
endif
BENCH_CLI_ARGS ?=
bench-cli-startup:
@echo "⚡ Benchmarking CLI startup time (isolated venv)..."
uv run python scripts/benchmarks/benchmark_cli_startup.py $(BENCH_CLI_ARGS)
bench-cli-startup-verbose:
@echo "⚡ Benchmarking CLI startup time (isolated + import trace)..."
uv run python scripts/benchmarks/benchmark_cli_startup.py --verbose $(BENCH_CLI_ARGS)
# ==============================================================================
# PUBLISH
# ==============================================================================
# Build publish flags based on options
PUBLISH_FLAGS :=
ifdef DRY_RUN
PUBLISH_FLAGS += --dry-run
endif
ifdef TEST_PYPI
PUBLISH_FLAGS += --test-pypi
endif
ifdef ALLOW_BRANCH
PUBLISH_FLAGS += --allow-branch
endif
ifdef FORCE_TAG
PUBLISH_FLAGS += --force-tag
endif
publish:
ifndef VERSION
$(error VERSION is required. Usage: make publish VERSION=0.3.9rc1 [DRY_RUN=1] [TEST_PYPI=1] [ALLOW_BRANCH=1] [FORCE_TAG=1])
endif
ifdef TEST_PYPI
@echo "🚀 Publishing version $(VERSION) to TestPyPI..."
else
ifdef DRY_RUN
@echo "🚀 Running publish dry-run for version $(VERSION)..."
else
@echo "🚀 Publishing version $(VERSION) to PyPI..."
endif
endif
$(REPO_PATH)/scripts/publish.sh $(VERSION) $(PUBLISH_FLAGS)
# ==============================================================================
# CLEANUP
# ==============================================================================
clean: clean-pycache clean-dist clean-notebooks clean-test-coverage
@echo "✅ Cleaned!"
clean-pycache:
@echo "🧹 Cleaning up Python cache files..."
find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
find . -type f -name "*.pyc" -delete 2>/dev/null || true
@echo "✅ Cache cleaned!"
clean-dist:
@echo "🧹 Cleaning dist directories..."
rm -rf $(CONFIG_PKG)/dist
rm -rf $(ENGINE_PKG)/dist
rm -rf $(INTERFACE_PKG)/dist
rm -f packages/*/src/data_designer/*/_version.py
@echo "✅ Dist directories cleaned!"
clean-notebooks:
@echo "🧹 Cleaning up notebooks..."
rm -rf docs/notebooks
@echo "✅ Notebooks cleaned!"
clean-test-coverage:
@echo "🧹 Cleaning up test coverage..."
rm -rf htmlcov .coverage .pytest_cache
@echo "✅ Test coverage cleaned!"
# ==============================================================================
# PHONY TARGETS
# ==============================================================================
.PHONY: bench-cli-startup bench-cli-startup-verbose \
build build-config build-engine build-interface \
check-all check-all-fix check-config check-engine check-interface \
check-license-headers \
clean clean-dist clean-notebooks clean-pycache clean-test-coverage \
convert-execute-notebooks \
coverage coverage-config coverage-engine coverage-interface \
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 \
lint lint-config lint-engine lint-fix lint-fix-config lint-fix-engine lint-fix-interface lint-interface \
perf-import perf-import-runtime publish serve-docs-locally show-versions \
health-checks \
test test-config test-config-isolated test-e2e test-engine test-engine-isolated \
test-interface test-interface-isolated test-isolated \
test-run-all-examples test-run-recipes test-run-tutorials \
update-license-headers verify-imports