# ============================================================================== # VARIABLES AND FUNCTIONS # ============================================================================== REPO_PATH := $(shell pwd) PRE_COMMIT ?= .venv/bin/pre-commit # 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..."; \ $(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 + docs + 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/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 " 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" @echo " check-fern-docs - Generate local Fern artifacts and run fern check" @echo " check-fern-docs-locally - Install deps, generate Fern artifacts, and run fern check" @echo " serve-fern-docs-locally - Generate local Fern artifacts and serve Fern docs" @echo " serve-docs-locally - Serve legacy MkDocs documentation locally" @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- - Run tests for a specific package" @echo " lint- - Lint a specific package" @echo " lint-fix- - Fix lint issues in a specific package" @echo " format- - Format a specific package" @echo " format-check- - Check formatting for a specific package" @echo " check- - Check format + lint for a specific package" @echo " build- - Build wheel for a specific package" @echo " coverage- - Run tests with coverage for a specific package" @echo "" @echo "โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" @echo "๐Ÿ’ก Tip: Run 'make ' 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- - 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 + docs + notebooks (Jupyter, jupytext, etc.)" uv sync --all-packages --group dev --group docs --group notebooks $(call install-pre-commit-hooks) @echo "โœ… Dev + docs + 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 docs setup 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. DOCS_PYTHON_VERSION ?= 3.13 DOCS_PYTHON ?= .venv/bin/python DOCS_JUPYTEXT ?= .venv/bin/jupytext DOCS_MKDOCS ?= .venv/bin/mkdocs FERN_VERSION ?= $(shell jq -r .version fern/fern.config.json) FERN ?= npx -y fern-api@$(FERN_VERSION) # Route urllib/requests/httpx through certifi's CA bundle. Necessary when uv # resolves $(DOCS_PYTHON_VERSION) 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=$$($(DOCS_PYTHON) -c "import certifi; print(certifi.where())") \ REQUESTS_CA_BUNDLE=$$($(DOCS_PYTHON) -c "import certifi; print(certifi.where())") install-docs-deps: @echo "๐Ÿ“ฆ Installing docs dependencies (Python $(DOCS_PYTHON_VERSION))..." uv sync --python $(DOCS_PYTHON_VERSION) --all-packages --group docs --group notebooks serve-docs-locally: @$(MAKE) install-docs-deps @echo "๐Ÿ“ Building and serving docs (Python $(DOCS_PYTHON_VERSION))..." $(DOCS_MKDOCS) serve --livereload prepare-fern-release: ifndef VERSION $(error VERSION is required, e.g. make prepare-fern-release VERSION=0.5.10) endif $(DOCS_PYTHON) fern/scripts/fern-release-version.py prepare --version $(VERSION) $(if $(FORCE),--force,) check-fern-release-version: ifndef VERSION $(error VERSION is required, e.g. make check-fern-release-version VERSION=0.5.10) endif $(DOCS_PYTHON) fern/scripts/fern-release-version.py check --version $(VERSION) $(if $(REQUIRE_LATEST),--require-latest-matches-release,) prepare-fern-docs: generate-fern-notebooks @echo "โœ… Fern local artifacts ready" check-fern-docs: prepare-fern-docs cd fern && $(FERN) check check-fern-docs-locally: @$(MAKE) install-docs-deps @$(MAKE) check-fern-docs @echo "โœ… Fern docs check complete" serve-fern-docs-locally: @$(MAKE) install-docs-deps @$(MAKE) prepare-fern-docs cd fern && PNPM_CONFIG_DANGEROUSLY_ALLOW_ALL_BUILDS=true $(FERN) docs dev 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 else @echo "๐Ÿ““ Converting Python tutorials to notebooks and executing ($(DOCS_PYTHON))..." @rm -rf docs/notebooks @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"; \ $(DOCS_JUPYTEXT) --to ipynb --execute "$$f" || failed="$$failed\n โ€ข $$f"; \ done; \ 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; \ if [ -n "$$failed" ]; then \ echo ""; \ echo "โŒ Some notebooks failed (often missing API keys for image/audio providers)."; \ printf " Failed:%b\n" "$$failed"; \ exit 1; \ fi' @echo "โœ… Notebooks executed under docs/notebooks/" endif generate-colab-notebooks: @echo "๐Ÿ““ Generating Colab-compatible notebooks ($(DOCS_PYTHON))..." $(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 ($(DOCS_PYTHON))..." @mkdir -p fern/components/notebooks @failed=; tmp_dir=$$(mktemp -d); trap 'rm -rf "$$tmp_dir"' EXIT; \ for src in docs/notebook_source/*.py; do \ [ -f "$$src" ] || continue; \ name=$$(basename "$$src" .py); \ if [ -f "docs/notebooks/$$name.ipynb" ]; then \ input="docs/notebooks/$$name.ipynb"; \ source_label="notebook"; \ else \ input="$$tmp_dir/$$name.ipynb"; \ source_label="source"; \ $(DOCS_JUPYTEXT) --to ipynb --output "$$input" "$$src" >/dev/null || failed=1; \ fi; \ if [ ! -f "$$input" ]; then \ echo "โŒ Missing notebook input for $$name: $$input"; \ failed=1; \ continue; \ fi; \ echo " $$name ($$source_label)"; \ $(DOCS_PYTHON) fern/scripts/ipynb-to-fern-json.py "$$input" -o fern/components/notebooks/$$name.json || failed=1; \ done; \ if [ -n "$$failed" ]; then exit 1; fi @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-fern-docs check-fern-docs-locally check-fern-release-version 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 install-docs-deps \ lint lint-config lint-engine lint-fix lint-fix-config lint-fix-engine lint-fix-interface lint-interface \ perf-import perf-import-runtime prepare-fern-docs prepare-fern-release publish serve-docs-locally serve-fern-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