feat(cli): add plugin catalog core#618
Conversation
Code Review: PR #618 — feat(cli): add plugin catalog coreSummaryAdds a Overall the PR is well-structured, strictly validated, and thoughtfully tested. Comments below are mostly minor; one high-value item (entry point group constant usage) and a few smaller polish items. FindingsCorrectness
Schema validation
Security
Tests
Style / minor
VerdictApprove with minor requests. The architecture is sound, the schema validation is appropriately strict for a v2 contract freeze, and the test coverage is solid. Action items in priority order:
|
Greptile SummaryThis PR adds the
|
| Filename | Overview |
|---|---|
| packages/data-designer/src/data_designer/cli/plugin_catalog.py | New file: schema v2 catalog models with strict validation; duplicate package names checked by canonical form and duplicate runtime plugin names by enum-key normalization; install requirement consistency with declared specifier and marker is enforced. |
| packages/data-designer/src/data_designer/cli/services/plugin_install_service.py | New file: resolves uv/pip install targets, builds protection constraints via --constraint - stdin for uv-environment and temp-file for pip, --no-install-package for uv-project; entry-point verification uses importlib.metadata directly; uv minimum version pinned at 0.10.0. |
| packages/data-designer/src/data_designer/cli/repositories/plugin_catalog_repository.py | New file: catalog persistence with atomic cache writes (PID-scoped temp + replace), stale-cache fallback when source unavailable, GitHub repo/tree/blob URL normalization including subdirectory preservation, and case-insensitive alias management. |
| packages/data-designer/src/data_designer/cli/controllers/plugin_catalog_controller.py | New file: orchestrates catalog commands; run_install fetches with include_incompatible=True and applies the compatibility/versioned-install gate before plan building, making the guard reachable; dry-run exits 1 for blocked-compatibility installs. |
| packages/data-designer/src/data_designer/cli/services/plugin_catalog_service.py | New file: compatibility evaluation with marker and specifier checks, package alias resolution, version discovery via simple index (3-second timeout, per-call cache), and installed plugin enumeration via entry_points metadata without importing plugin code. |
| packages/data-designer/src/data_designer/cli/commands/plugin.py | New file: Typer command functions for list/search/info/install/uninstall/installed and catalog add/remove/list; propagates parent --catalog option through context traversal. |
| packages/data-designer/src/data_designer/cli/main.py | Adds plugin_app and plugin_catalog_app lazy Typer groups wired into the main app under the Setup panel; plugin_callback stores the parent --catalog option for subcommand propagation. |
| packages/data-designer/tests/cli/services/test_plugin_install_service.py | New file: comprehensive coverage of uv-project, uv-environment, pip-environment install/uninstall plan generation, old-uv fallback, Data Designer constraint generation, versioned requirements, and entry-point verification including catalog-name vs entry-point-name mismatch. |
Sequence Diagram
sequenceDiagram
participant User
participant CLI as plugin.py (CLI)
participant Ctrl as PluginCatalogController
participant Svc as PluginCatalogService
participant Repo as PluginCatalogRepository
participant IS as PluginInstallService
User->>CLI: data-designer plugin install PACKAGE
CLI->>Ctrl: run_install(package_name, catalog_alias, ...)
Ctrl->>Svc: get_catalog(alias)
Svc->>Repo: get_catalog(alias)
Repo-->>Ctrl: PluginCatalogConfig
Ctrl->>Svc: "get_package_entries(package, include_incompatible=True)"
Svc->>Repo: load_catalog(alias, refresh)
alt Cache fresh
Repo-->>Svc: PluginCatalog (from cache)
else Cache stale / missing
Repo->>Repo: _fetch_catalog_payload(url)
Repo->>Repo: _validate_catalog(payload)
Repo->>Repo: _save_catalog_cache (atomic)
Repo-->>Svc: PluginCatalog
end
Svc-->>Ctrl: list[PluginCatalogEntry]
Ctrl->>Svc: evaluate_compatibility(entry)
Svc-->>Ctrl: CompatibilityResult
alt Incompatible and not versioned install and not dry_run
Ctrl-->>User: error + exit(1)
end
Ctrl->>IS: build_install_plan(entry, catalog, manager, version_specifier)
IS->>IS: _resolve_install_target()
IS->>IS: _installed_data_designer_distribution_versions()
IS->>IS: _data_designer_protection_args()
IS-->>Ctrl: InstallPlan
Ctrl-->>User: display metadata + confirm prompt
Ctrl->>IS: install(plan)
IS->>IS: _materialized_install_command
IS->>IS: _run_subprocess(command, stdin)
IS-->>Ctrl: return code
Ctrl->>IS: verify_entry_points(package_entries)
IS->>IS: importlib.metadata.entry_points(group)
IS->>IS: _matching_entry_point_loads_plugin()
IS-->>Ctrl: bool
Ctrl-->>User: success or warning message
Reviews (32): Last reviewed commit: "Merge branch 'main' into johnny/feat/617..." | Re-trigger Greptile
4549bd7 to
3916648
Compare
|
Greptile follow-up addressed in 955a675. What changed:
Verified with:
|
|
While testing the plugin install flow, I hit one more install-safety issue. The plugin package installs successfully, but the resolver can also replace the Data Designer packages in the current environment. In my test, installing A simple approach for the and include it in the install plan: uv pip install \
--python <current-python> \
--excludes <protected-packages.txt> \
--default-index https://pypi.org/simple/ \
--index <catalog-index> \
<plugin-requirement>I tried that shape locally with For |
|
@eric-tramel thanks, this install-safety issue is now addressed in the latest pushed commits. What changed:
Coverage added/verified:
I did not add a separate pre/post mutation guard in code because the resolver commands now carry the protection directly, and pip has the equivalent constraints protection for the pip-only case. Happy to add an extra post-install belt-and-suspenders version check later if we decide the extra noise is worth it, but I don't think it should block this PR now. |
ff50a1e to
13a1c9b
Compare
2a91d21 to
9dbe7ab
Compare
andreatgretel
left a comment
There was a problem hiding this comment.
Requesting changes for two catalog edge cases that still reproduce on the current head.
2400389 to
cb2e98a
Compare
andreatgretel
left a comment
There was a problem hiding this comment.
I reran the review against the validated GitHub PR diff and added real smoke coverage: local pip install/uninstall, local uv env install/uninstall, uv project install/uninstall, production catalog fetch, and a live install/uninstall of data-designer-github from the NVIDIA catalog. The happy paths look good, but I found three warning-level issues worth fixing before approval.
Add typed catalog and tap models, persistent tap storage, cached catalog loading, compatibility evaluation, install plan generation, and runtime plugin discovery helpers. Refs #617
- Escape catalog-provided Rich markup before rendering CLI output - Reject runtime plugin names that collide after enum-key normalization - Load installed runtime entry points in a subprocess before reporting success
Load matching entry points directly after install instead of spawning a separate Python process. This keeps the check package-scoped while still catching broken entry-point targets and non-Plugin objects.
Use uv >= 0.10.0 as the single supported uv requirement for plugin package commands. Auto mode now falls back to a pip plan with an upgrade warning when uv is unavailable or too old, while explicit uv selection remains strict.
- Preserve catalog requirement constraints for versioned installs - Remove stale install-plan metadata fields - Expand parser, uv, controller, and local-catalog dry-run coverage
830fc45 to
2717873
Compare
Plugin CLI e2e battle-test reportI ran a fresh end-to-end simulation suite against this branch using a temporary mock plugin catalog repo served over local HTTP. The mock repo included a catalog JSON file, a PEP 503-style simple package index, and real wheel files for multiple plugin packages and versions. Result: 57 workflows passed, 0 failed. Data Designer version under test: Covered:
The HTML report was generated locally at |
Add package version metadata support for plugin catalogs and resolve current versions from exact requirements or simple indexes when catalog entries omit them. Update plugin list/info/install metadata to show the plugin package version and Data Designer compatibility requirement while removing the separate Data Designer version line.
Signed-off-by: Johnny Greco <jogreco@nvidia.com>
|
MkDocs preview: https://81e56767.dd-docs-preview.pages.dev Fern preview: https://nvidia-preview-pr-618.docs.buildwithfern.com/nemo/datadesigner
|
Summary
This PR adds the client-side plugin package workflow for Data Designer. The new
data-designer plugincommand discovers package-first catalogs, shows compatibility-aware package metadata, installs and uninstalls plugin packages, and verifies the runtime plugin entry points exposed by those packages.The implementation follows the current
NVIDIA-NeMo/DataDesignerPluginscatalog contract and uses the stable NVIDIA catalog athttps://nvidia-nemo.github.io/DataDesignerPlugins/catalog/plugins.jsonas the built-in default catalog.Related Issue
Closes #617
Changes
Public CLI
data-designer plugincommand group withlist,search,info,install,uninstall, andinstalled.data-designer plugin catalog list/add/remove.data-designer-calculator, or its package alias, such ascalculator.PACKAGE==VERSIONor--version VERSION, while keeping the installed Data Designer package family fixed as the source of truth.plugin infoandplugin installon the same streamlined metadata renderer: catalog, version, runtime plugins, compatibility, requirement, index URL, and install strategy.plugin installedpackage-first by grouping installed runtime entry points under their owning distribution and version.Catalog Contract And Discovery
nvidiacatalog, user-managed catalog names inplugin_catalogs.yaml, andDATA_DESIGNER_DEFAULT_PLUGIN_CATALOG_URLfor QA/staging overrides.catalog/plugins.jsonlayout used by the plugin repo.Compatibility And Package Management
uvproject installs,uv pipenvironment installs, and pip-only environments.uv add --activewhen the user is in an active virtual environment with a userpyproject.toml, so plugin packages are recorded in the project.uvversion for uv-managed plugin plans and falls back to pip in auto mode when uv is unavailable or too old, provided pip is available.uvis unavailable.data-designer,data-designer-config, anddata-designer-engine) from being reinstalled or upgraded as plugin package dependencies.Docs And Tests
packaginglockfile entry used by the new catalog/compatibility code.Review Focus
plugin_catalog.py: schema v2 validation and the package-first compatibility boundary with DataDesignerPlugins.plugin_install_service.py: uv/pip command construction, active-project detection, Data Designer package-family protection, versioned installs, and post-mutation verification.plugin_catalog_repository.py: catalog persistence, source normalization, cache keying, and stale-cache behavior.plugin_catalog_controller.pyandcommands/plugin.py: user-facing package/runtime distinction, prompts, dry runs, and table output.Testing
Local verification:
uv run --package data-designer pytest packages/data-designer/tests/cli -q(762 passed,1 skipped,86 warnings)193 passed,1 skipped; targeted plugin CLI module coverage88%)uv run ruff checkon changed plugin CLI test filesuv run ruff format --checkon changed plugin CLI test filesgit diff --check145 checks)Checklist
Description updated with AI