mammoth-cli 2.0.81__tar.gz → 2.0.83__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/PKG-INFO +2 -2
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/__init__.py +1 -1
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/app.py +3 -1
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/command-index.md +2 -2
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dataset.md +10 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/dataset.py +12 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/registry.py +1 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/schema.py +18 -1
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/view.py +68 -13
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/view_ops.py +26 -7
- mammoth_cli-2.0.83/mammoth_cli/runtime/dataset_health.py +62 -0
- mammoth_cli-2.0.83/mammoth_cli/runtime/new_data.py +86 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/runtime/verify.py +10 -2
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/services/conditions.py +5 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/services/data_quality.py +139 -14
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/pyproject.toml +2 -2
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/connector.yaml +6 -5
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/dataset.yaml +39 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/sdk-catalog.source.yaml +7 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/sdk-methods.yaml +16 -2
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/.gitignore +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/LICENSE +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/README.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/__main__.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/SKILL.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/about-mammoth.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/auth.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities-misc.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/activity.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/addon.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/agent.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/ai.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/annotation.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/auth.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/automation.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/batch.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/billing.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/browse.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/calc.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/capability.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/client-app.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/completion.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/config.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/connector.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/context.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-qa.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/data-app.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/doctor.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/external-key.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/file.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/folder.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/job.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/log.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/notification.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/parameter.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/project.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/report.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schedule.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schema.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/skill.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/snippet.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/support.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/template.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/trash.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/upgrade.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/user.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/version.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/view-transform.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/view.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/webhook.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workflow.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workspace.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/handoff.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/input.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/jobs-drafts.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/machine-output.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/operations.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/auth-scope.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/cleanup.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/dashboards.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/end-to-end.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/exports.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/index.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/need-action.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/resources.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/scheduling.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/transforms.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/typed-etl-discovery.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/recovery.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/report-checklist.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/retention.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/safety.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/bundled_skill/mammoth-cli/references/task-start.md +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/__init__.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/activity.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/addon.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/agent.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/ai.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/annotation.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/auth.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/automation.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/batch.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/billing.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/browse.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/calc.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/capability.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/client_app.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/completion.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/config.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/connector.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/context.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/dashboard.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/data_app.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/doctor.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/external_key.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/file.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/folder.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/job.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/notification.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/parameter.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/project.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/report.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/schedule.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/skill.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/snippet.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/support.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/template.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/trash.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/upgrade.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/user.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/webhook.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/workflow.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/commands/workspace.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/context/__init__.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/context/credentials.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/context/endpoint.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/context/profiles.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/context/resolver.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/contracts/__init__.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/contracts/auth.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/embed.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/errors/__init__.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/errors/envelope.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/manifest/__init__.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/manifest/loader.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/messages/__init__.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/output/__init__.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/output/envelope.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/output/normalize.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/output/policy.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/output/progress.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/output/render.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/py.typed +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/runtime/__init__.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/runtime/confirm.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/runtime/dryrun.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/runtime/embedded.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/runtime/executor.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/runtime/input_loader.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/runtime/invocation.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/runtime/options.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/runtime/parents.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/runtime/runlog.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/runtime/session.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/runtime/state.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/runtime/strict.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/runtime/updates.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/runtime/validate.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/services/__init__.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/services/argspec.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/services/coerce.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/services/command_contract.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/services/dashboard_pages.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/services/dashboard_review.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/services/dispatch.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/services/factory.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/services/input_fields.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/services/mapping.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/services/openapi_types.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/services/positionals.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/services/protocol.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/services/sdk_service.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/services/testing.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/services/type_system.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/skills/__init__.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/skills/installer.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/skills/steering.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/mammoth_cli/testing.py +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/activity.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/addon.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/agent.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/ai.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/annotation.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/auth.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/automation.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/batch.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/billing.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/browse.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/calc.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/capability.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/client-app.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/completion.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/config.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/context.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/dashboard.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/data-app.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/doctor.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/external-key.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/file.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/folder.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/job.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/log.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/notification.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/parameter.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/project.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/report.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/schedule.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/schema.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/skill.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/snippet.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/support.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/template.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/trash.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/upgrade.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/user.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/version.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/view.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/webhook.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/workflow.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/commands/workspace.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/openapi-operations.yaml +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/manifests/schema-v1.json +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/openapi/metadata.json +0 -0
- {mammoth_cli-2.0.81 → mammoth_cli-2.0.83}/spec/openapi/openapi.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mammoth-cli
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.83
|
|
4
4
|
Summary: Command-line interface for the Mammoth Analytics platform
|
|
5
5
|
Project-URL: homepage, https://mammoth.io
|
|
6
6
|
Project-URL: repository, https://github.com/EdgeMetric/mammothsdk
|
|
@@ -17,7 +17,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
17
17
|
Requires-Python: <3.15,>=3.12
|
|
18
18
|
Requires-Dist: jsonschema>=4.20
|
|
19
19
|
Requires-Dist: keyring<26,>=25.7
|
|
20
|
-
Requires-Dist: mammoth-io<0.8,>=0.7.
|
|
20
|
+
Requires-Dist: mammoth-io<0.8,>=0.7.37
|
|
21
21
|
Requires-Dist: platformdirs<5,>=4.10
|
|
22
22
|
Requires-Dist: pydantic<3,>=2.12.5
|
|
23
23
|
Requires-Dist: pyyaml<7,>=6
|
|
@@ -42,6 +42,8 @@ from mammoth_cli.output.policy import (
|
|
|
42
42
|
resolve_output,
|
|
43
43
|
)
|
|
44
44
|
from mammoth_cli.runtime import executor, validate
|
|
45
|
+
from mammoth_cli.runtime.dataset_health import with_dataset_health
|
|
46
|
+
from mammoth_cli.runtime.new_data import with_new_data_path
|
|
45
47
|
from mammoth_cli.runtime.invocation import Invocation
|
|
46
48
|
from mammoth_cli.runtime.state import with_state
|
|
47
49
|
from mammoth_cli.runtime.strict import validate_extra_args
|
|
@@ -826,7 +828,7 @@ def _execute(invocation: Invocation) -> None:
|
|
|
826
828
|
if invocation.dry_run:
|
|
827
829
|
return _dry_run(handler, invocation)
|
|
828
830
|
data, meta = handler(invocation)
|
|
829
|
-
return _apply_verify(invocation, data), meta
|
|
831
|
+
return with_new_data_path(with_dataset_health(_apply_verify(invocation, data))), meta
|
|
830
832
|
|
|
831
833
|
executor.run(
|
|
832
834
|
invocation.command_id,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Published CLI command catalog
|
|
2
2
|
|
|
3
|
-
This generated catalog is a lookup table for every command in the published CLI manifest, currently
|
|
3
|
+
This generated catalog is a lookup table for every command in the published CLI manifest, currently 574; each entry carries its release status line. It is a command-contract index, not an assertion that every backend/OpenAPI operation has a CLI binding. For an exact local CLI contract, run `mammoth schema get COMMAND_ID`; `mammoth capability list` is an API-binding inventory and can omit typed/local CLI routes. For focused workflows, read the [recipes index](recipes/index.md). Sensitive structured input must come from a private file or pipe; never put secrets in literal argv.
|
|
4
4
|
|
|
5
5
|
Load only the applicable domain file:
|
|
6
6
|
|
|
@@ -24,7 +24,7 @@ Load only the applicable domain file:
|
|
|
24
24
|
- [dashboard-qa](commands/dashboard-qa.md) — 13 published commands
|
|
25
25
|
- [dashboard](commands/dashboard.md) — 100 published commands
|
|
26
26
|
- [data-app](commands/data-app.md) — 12 published commands
|
|
27
|
-
- [dataset](commands/dataset.md) —
|
|
27
|
+
- [dataset](commands/dataset.md) — 18 published commands
|
|
28
28
|
- [doctor](commands/doctor.md) — 1 published commands
|
|
29
29
|
- [external-key](commands/external-key.md) — 4 published commands
|
|
30
30
|
- [file](commands/file.md) — 9 published commands
|
|
@@ -12,6 +12,16 @@ Result: `DatasetBatchDataResult`; mutation `read`, confirmation `none`, wait pol
|
|
|
12
12
|
|
|
13
13
|
Status on release: ran once on CLI 1.1.11 — Published PyPI CLI 1.1.11 / SDK 0.7.1 batch-data read succeeded for an ID observed from retained dataset 29; bounded 50-row page. One observed-ID chain and page; not Full.
|
|
14
14
|
|
|
15
|
+
### `dataset.broken-rows.list`
|
|
16
|
+
|
|
17
|
+
Run: `mammoth dataset broken-rows list`. Exact input fields: `mammoth schema get dataset.broken-rows.list`.
|
|
18
|
+
|
|
19
|
+
Example: `mammoth dataset broken-rows list 123`. Placeholders are illustrative; resolve IDs and input from observed reads.
|
|
20
|
+
|
|
21
|
+
Result: `DatasetBrokenRowsListResult`; mutation `read`, confirmation `none`, wait policy `not_async`.
|
|
22
|
+
|
|
23
|
+
Status on release: untried; no live run recorded.
|
|
24
|
+
|
|
15
25
|
### `dataset.bulk-delete`
|
|
16
26
|
|
|
17
27
|
Run: `mammoth dataset bulk-delete`. Exact input fields: `mammoth schema get dataset.bulk-delete`.
|
|
@@ -28,6 +28,7 @@ from mammoth_cli.runtime.confirm import (
|
|
|
28
28
|
enforce_confirmation,
|
|
29
29
|
)
|
|
30
30
|
from mammoth_cli.runtime.invocation import Invocation
|
|
31
|
+
from mammoth_cli.runtime.new_data import with_file_upload_path
|
|
31
32
|
from mammoth_cli.runtime.session import open_service, require_project
|
|
32
33
|
|
|
33
34
|
HandlerResult = tuple[Any, dict[str, Any]]
|
|
@@ -322,6 +323,17 @@ def dataset_batch_data(invocation: Invocation) -> HandlerResult:
|
|
|
322
323
|
|
|
323
324
|
def dataset_file_settings(invocation: Invocation) -> HandlerResult:
|
|
324
325
|
"""Get file settings (delimiter, header, dates, ...) for a dataset."""
|
|
326
|
+
data, meta = _read_dataset(invocation)
|
|
327
|
+
return with_file_upload_path(data, _require_int_positional(invocation, "dataset id")), meta
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def dataset_broken_rows(invocation: Invocation) -> HandlerResult:
|
|
331
|
+
"""List the lines of a dataset's uploaded file that could not be parsed."""
|
|
332
|
+
return _read_dataset(invocation)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def _read_dataset(invocation: Invocation) -> HandlerResult:
|
|
336
|
+
"""Call this command's SDK read with the DATASET_ID positional."""
|
|
325
337
|
project_id = require_project(invocation)
|
|
326
338
|
dataset_id = _require_int_positional(invocation, "dataset id")
|
|
327
339
|
if dataset_id <= 0:
|
|
@@ -314,6 +314,7 @@ HANDLERS: dict[str, Handler] = {
|
|
|
314
314
|
"dataset.file-settings.get": dataset_cmd.dataset_file_settings,
|
|
315
315
|
"dataset.file-settings.update": dataset_cmd.dataset_file_settings_update,
|
|
316
316
|
"dataset.file-settings.undo": dataset_cmd.dataset_file_settings_undo,
|
|
317
|
+
"dataset.broken-rows.list": dataset_cmd.dataset_broken_rows,
|
|
317
318
|
"dataset.create": dataset_cmd.dataset_create,
|
|
318
319
|
"dataset.create-from-pdf": dataset_cmd.dataset_create_from_pdf,
|
|
319
320
|
"dataset.rename": dataset_cmd.dataset_rename,
|
|
@@ -1402,7 +1402,9 @@ def _schema_common(record: dict[str, Any]) -> dict[str, Any]:
|
|
|
1402
1402
|
contract_level = (
|
|
1403
1403
|
"opaque_expert"
|
|
1404
1404
|
if record["command_id"] in _OPAQUE_EXPERT_COMMANDS
|
|
1405
|
-
else "partially_typed"
|
|
1405
|
+
else "partially_typed"
|
|
1406
|
+
if opaque_fields
|
|
1407
|
+
else "typed"
|
|
1406
1408
|
)
|
|
1407
1409
|
return {
|
|
1408
1410
|
"positionals": _positionals(record["command_id"]),
|
|
@@ -1558,6 +1560,13 @@ def _inline_call_detail(entries: list[dict[str, Any]]) -> None:
|
|
|
1558
1560
|
entry["agent_example"] = record["agent_example"]
|
|
1559
1561
|
|
|
1560
1562
|
|
|
1563
|
+
#: How to drill down from a find: a family's full command list, or every family.
|
|
1564
|
+
_BROWSE_NEXT = (
|
|
1565
|
+
"mammoth schema list FAMILY lists every command in a family; mammoth schema list "
|
|
1566
|
+
"lists the families"
|
|
1567
|
+
)
|
|
1568
|
+
|
|
1569
|
+
|
|
1561
1570
|
def find_schemas(
|
|
1562
1571
|
query: str,
|
|
1563
1572
|
*,
|
|
@@ -1747,9 +1756,17 @@ def find_schemas(
|
|
|
1747
1756
|
if result["suggestions"]
|
|
1748
1757
|
else _NO_MATCH_HINT_NO_SUGGESTIONS
|
|
1749
1758
|
)
|
|
1759
|
+
result["browse"] = _browse(page or result.get("suggestions", []))
|
|
1750
1760
|
return result
|
|
1751
1761
|
|
|
1752
1762
|
|
|
1763
|
+
def _browse(entries: list[dict[str, Any]]) -> dict[str, Any]:
|
|
1764
|
+
"""The families behind *entries* and how to list each one in full: a keyword
|
|
1765
|
+
find surfaces one way to do a thing, its family holds the siblings."""
|
|
1766
|
+
families = list(dict.fromkeys(entry["command_path"].split()[0] for entry in entries))
|
|
1767
|
+
return {"families": families, "next": _BROWSE_NEXT}
|
|
1768
|
+
|
|
1769
|
+
|
|
1753
1770
|
def get_schema(command_id: str) -> dict[str, Any] | None:
|
|
1754
1771
|
record = command_by_id(command_id)
|
|
1755
1772
|
if record is None or record.get("disposition") == "alias":
|
|
@@ -2073,13 +2073,16 @@ def view_pipeline_rerun(invocation: Invocation) -> HandlerResult:
|
|
|
2073
2073
|
kwargs: dict[str, Any] = {"dataview_id": dataview_id}
|
|
2074
2074
|
_forward_optional(document, kwargs, ("from_sequence", "dataset_id"))
|
|
2075
2075
|
with open_service(invocation) as (service, auth):
|
|
2076
|
-
data = service.call(_symbol(invocation), **kwargs)
|
|
2077
2076
|
dataset_id = kwargs.get("dataset_id")
|
|
2078
2077
|
if dataset_id is None:
|
|
2079
2078
|
dataset_id = _resolve_dataset_id_for_settle(
|
|
2080
2079
|
service, invocation, dataview_id, document, 1
|
|
2081
2080
|
)
|
|
2082
|
-
|
|
2081
|
+
before = _rows_before(service, dataset_id, dataview_id, invocation.project)
|
|
2082
|
+
data = service.call(_symbol(invocation), **kwargs)
|
|
2083
|
+
data = _settle_async_view_write(
|
|
2084
|
+
service, dataset_id, dataview_id, invocation.project, data, before
|
|
2085
|
+
)
|
|
2083
2086
|
return data, _meta(invocation, auth.workspace_id, None)
|
|
2084
2087
|
|
|
2085
2088
|
|
|
@@ -2133,13 +2136,16 @@ def view_task_delete(invocation: Invocation) -> HandlerResult:
|
|
|
2133
2136
|
kwargs: dict[str, Any] = {"dataview_id": dataview_id, "task_id": task_id}
|
|
2134
2137
|
_forward_optional(document, kwargs, ("dataset_id",))
|
|
2135
2138
|
with open_service(invocation) as (service, auth):
|
|
2136
|
-
data = service.call(_symbol(invocation), **kwargs)
|
|
2137
2139
|
dataset_id = kwargs.get("dataset_id")
|
|
2138
2140
|
if dataset_id is None:
|
|
2139
2141
|
dataset_id = _resolve_dataset_id_for_settle(
|
|
2140
2142
|
service, invocation, dataview_id, document, 2
|
|
2141
2143
|
)
|
|
2142
|
-
|
|
2144
|
+
before = _rows_before(service, dataset_id, dataview_id, invocation.project)
|
|
2145
|
+
data = service.call(_symbol(invocation), **kwargs)
|
|
2146
|
+
data = _settle_async_view_write(
|
|
2147
|
+
service, dataset_id, dataview_id, invocation.project, data, before
|
|
2148
|
+
)
|
|
2143
2149
|
return data, _meta(invocation, auth.workspace_id, None)
|
|
2144
2150
|
|
|
2145
2151
|
|
|
@@ -2193,13 +2199,16 @@ def view_task_update(invocation: Invocation) -> HandlerResult:
|
|
|
2193
2199
|
assert document is not None
|
|
2194
2200
|
_forward_optional(document, kwargs, ("dataset_id",))
|
|
2195
2201
|
with open_service(invocation) as (service, auth):
|
|
2196
|
-
data = service.call(_symbol(invocation), **kwargs)
|
|
2197
2202
|
dataset_id = kwargs.get("dataset_id")
|
|
2198
2203
|
if dataset_id is None:
|
|
2199
2204
|
dataset_id = _resolve_dataset_id_for_settle(
|
|
2200
2205
|
service, invocation, dataview_id, document, 2
|
|
2201
2206
|
)
|
|
2202
|
-
|
|
2207
|
+
before = _rows_before(service, dataset_id, dataview_id, invocation.project)
|
|
2208
|
+
data = service.call(_symbol(invocation), **kwargs)
|
|
2209
|
+
data = _settle_async_view_write(
|
|
2210
|
+
service, dataset_id, dataview_id, invocation.project, data, before
|
|
2211
|
+
)
|
|
2203
2212
|
return data, _meta(invocation, auth.workspace_id, None)
|
|
2204
2213
|
|
|
2205
2214
|
|
|
@@ -2509,6 +2518,33 @@ _SPECIAL_EXPORT_COMMON_FIELDS = frozenset(
|
|
|
2509
2518
|
)
|
|
2510
2519
|
|
|
2511
2520
|
|
|
2521
|
+
def _reject_export_into_draft(service: Any, dataview_id: int, dataset_id: int) -> None:
|
|
2522
|
+
"""Refuse a dataset export on a view whose changes are held in a draft.
|
|
2523
|
+
|
|
2524
|
+
With auto-run off the view keeps new pipeline changes in a draft, so the
|
|
2525
|
+
export would only be staged and write nothing; the SDK then waits out its
|
|
2526
|
+
whole timeout for a write that cannot happen (eval T1-O-11).
|
|
2527
|
+
"""
|
|
2528
|
+
pipeline = service.call(_PIPELINE_GET_SYMBOL, dataview_id=dataview_id, dataset_id=dataset_id)
|
|
2529
|
+
draft_mode = pipeline.get("draft_mode") if isinstance(pipeline, dict) else None
|
|
2530
|
+
if draft_mode in (None, "off"):
|
|
2531
|
+
return
|
|
2532
|
+
raise CliError(
|
|
2533
|
+
code="view_in_draft",
|
|
2534
|
+
message=(
|
|
2535
|
+
f"View {dataview_id} holds its changes in a draft (auto-run is off), so an "
|
|
2536
|
+
"export added now would be staged and write nothing."
|
|
2537
|
+
),
|
|
2538
|
+
exit_status=EXIT_USAGE,
|
|
2539
|
+
hint=(
|
|
2540
|
+
f"Turn auto-run on with mammoth view draft auto-run {dataview_id} --input "
|
|
2541
|
+
"'{\"enabled\": true}', add the export, then turn auto-run off again if the "
|
|
2542
|
+
f"dataset should only update when asked (mammoth view pipeline rerun {dataview_id})."
|
|
2543
|
+
),
|
|
2544
|
+
details={"dataview_id": dataview_id, "draft_mode": draft_mode},
|
|
2545
|
+
)
|
|
2546
|
+
|
|
2547
|
+
|
|
2512
2548
|
def view_export_specialized(invocation: Invocation) -> HandlerResult:
|
|
2513
2549
|
"""Run one of the SDK's typed ``View.export`` destination helpers."""
|
|
2514
2550
|
route = _SPECIAL_EXPORTS.get(invocation.command_id)
|
|
@@ -2596,6 +2632,8 @@ def view_export_specialized(invocation: Invocation) -> HandlerResult:
|
|
|
2596
2632
|
),
|
|
2597
2633
|
details={"dataset_id": dataset_id, "target_ds_id": int(target_ds_id)},
|
|
2598
2634
|
)
|
|
2635
|
+
if is_dataset_route:
|
|
2636
|
+
_reject_export_into_draft(service, dataview_id, dataset_id)
|
|
2599
2637
|
target_view_before = None
|
|
2600
2638
|
target_only_columns: list[str] = []
|
|
2601
2639
|
if target_ds_id is not None:
|
|
@@ -2999,8 +3037,30 @@ def _row_count_now(service: Any, dataset_id: int, view_id: int, project_id: int
|
|
|
2999
3037
|
return info.get("row_count") if isinstance(info, dict) else None
|
|
3000
3038
|
|
|
3001
3039
|
|
|
3040
|
+
def _rows_before(
|
|
3041
|
+
service: Any, dataset_id: Any, view_id: int, project_id: int | None
|
|
3042
|
+
) -> dict[str, Any] | None:
|
|
3043
|
+
"""The view's row count read BEFORE an async write is sent.
|
|
3044
|
+
|
|
3045
|
+
Read after the call, a small view may already have recomputed, so the
|
|
3046
|
+
"before" would be the new count and a real change would look like none.
|
|
3047
|
+
None when the parent dataset is unknown (the settle step is skipped then).
|
|
3048
|
+
"""
|
|
3049
|
+
if dataset_id is None:
|
|
3050
|
+
return None
|
|
3051
|
+
try:
|
|
3052
|
+
return {"rows_before": _row_count_now(service, int(dataset_id), view_id, project_id)}
|
|
3053
|
+
except CliError as exc:
|
|
3054
|
+
return {"rows_before": None, "rows_before_error": f"{type(exc).__name__}: {exc}"}
|
|
3055
|
+
|
|
3056
|
+
|
|
3002
3057
|
def _settle_async_view_write(
|
|
3003
|
-
service: Any,
|
|
3058
|
+
service: Any,
|
|
3059
|
+
dataset_id: Any,
|
|
3060
|
+
view_id: int,
|
|
3061
|
+
project_id: int | None,
|
|
3062
|
+
data: Any,
|
|
3063
|
+
before: dict[str, Any] | None,
|
|
3004
3064
|
) -> Any:
|
|
3005
3065
|
"""Turn an async view write's immediate response into a final one.
|
|
3006
3066
|
|
|
@@ -3017,12 +3077,7 @@ def _settle_async_view_write(
|
|
|
3017
3077
|
if dataset_id is None or not isinstance(data, dict):
|
|
3018
3078
|
return data
|
|
3019
3079
|
dataset_id = int(dataset_id)
|
|
3020
|
-
|
|
3021
|
-
row_check: dict[str, Any] = {
|
|
3022
|
-
"rows_before": _row_count_now(service, dataset_id, view_id, project_id)
|
|
3023
|
-
}
|
|
3024
|
-
except CliError as exc:
|
|
3025
|
-
row_check = {"rows_before": None, "rows_before_error": f"{type(exc).__name__}: {exc}"}
|
|
3080
|
+
row_check: dict[str, Any] = dict(before or {"rows_before": None})
|
|
3026
3081
|
rows_after, pipeline_error = wait_for_view_row_count(service, dataset_id, view_id, project_id)
|
|
3027
3082
|
row_check["rows_after"] = rows_after
|
|
3028
3083
|
data = {**data, "row_check": row_check}
|
|
@@ -674,6 +674,23 @@ def _require_clone_from_same_dataset(service: Any, clone_from: int, dataset_id:
|
|
|
674
674
|
)
|
|
675
675
|
|
|
676
676
|
|
|
677
|
+
_DASHBOARDS_LIST_SYMBOL = "mammoth.api.dashboards.DashboardsAPI.list"
|
|
678
|
+
|
|
679
|
+
|
|
680
|
+
def _with_dashboards(service: Any, view_id: int, record: Any) -> Any:
|
|
681
|
+
"""Add the dashboards built on this view, so a user on the view's page who
|
|
682
|
+
says "this board" is understood (eval T1-D-22); unchanged when none."""
|
|
683
|
+
if not isinstance(record, dict):
|
|
684
|
+
return record
|
|
685
|
+
boards = service.call(_DASHBOARDS_LIST_SYMBOL)
|
|
686
|
+
built_on = [
|
|
687
|
+
{"id": board.get("id"), "title": board.get("title")}
|
|
688
|
+
for board in (boards if isinstance(boards, list) else [])
|
|
689
|
+
if isinstance(board, dict) and view_id in (board.get("sources") or [])
|
|
690
|
+
]
|
|
691
|
+
return {**record, "dashboards": built_on} if built_on else record
|
|
692
|
+
|
|
693
|
+
|
|
677
694
|
def view_get(invocation: Invocation) -> HandlerResult:
|
|
678
695
|
"""Get one view by id, optionally scoped to an exact dataset parent."""
|
|
679
696
|
view_id = _view_id(invocation)
|
|
@@ -699,7 +716,8 @@ def view_get(invocation: Invocation) -> HandlerResult:
|
|
|
699
716
|
with open_service(invocation) as (service, auth):
|
|
700
717
|
data = service.call("mammoth.api.dataviews.DataviewsAPI.get", **kwargs)
|
|
701
718
|
parents.remember(_profile_name(invocation), auth.workspace_id, {view_id: dataset_id})
|
|
702
|
-
|
|
719
|
+
data = apply_column_renames(data) if document.get("fields") else brief_view_record(data)
|
|
720
|
+
data = _with_dashboards(service, view_id, data)
|
|
703
721
|
return data, _meta(invocation, auth.workspace_id)
|
|
704
722
|
context: dict[str, Any] = {"view_id": view_id}
|
|
705
723
|
if dataset_id is not None:
|
|
@@ -718,12 +736,13 @@ def view_get(invocation: Invocation) -> HandlerResult:
|
|
|
718
736
|
data = service.call(_symbol(invocation), **kwargs)
|
|
719
737
|
payload = _view_payload(data)
|
|
720
738
|
parents.remember_records(_profile_name(invocation), auth.workspace_id, payload)
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
739
|
+
if not document.get("fields"):
|
|
740
|
+
# The discovery path returns the standard record; trim it to the same
|
|
741
|
+
# brief shape the exact path asks the server for.
|
|
742
|
+
payload = brief_view_record(payload)
|
|
743
|
+
else:
|
|
744
|
+
payload = apply_column_renames(payload)
|
|
745
|
+
payload = _with_dashboards(service, view_id, payload)
|
|
727
746
|
return payload, _meta(invocation, auth.workspace_id)
|
|
728
747
|
|
|
729
748
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Dataset health, stated wherever a dataset appears in a result.
|
|
2
|
+
|
|
3
|
+
A dataset's ``status`` can say it did not load cleanly, but a bare status word
|
|
4
|
+
reads as fine to an agent that is looking for rows. :func:`with_dataset_health`
|
|
5
|
+
turns each such status into a ``dataset_health`` entry that says what it means
|
|
6
|
+
and which command fixes it. It runs on every result, read or write, and never
|
|
7
|
+
makes a request.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from collections.abc import Iterator
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
#: Status to (what it means, which command to run first) -- ``{id}`` is filled in.
|
|
16
|
+
_UNHEALTHY: dict[str, tuple[str, str]] = {
|
|
17
|
+
"has_unstructured_data": (
|
|
18
|
+
"Some rows of this file could not be split into columns, so they are held "
|
|
19
|
+
"apart and the dataset may have few or no usable rows. The usual cause is "
|
|
20
|
+
"the wrong delimiter or quote character.",
|
|
21
|
+
"mammoth dataset broken-rows list {id} shows the rows and why each does "
|
|
22
|
+
"not fit; then mammoth dataset file-settings get {id} and mammoth dataset "
|
|
23
|
+
"file-settings update {id} with the right delimiter or quote character",
|
|
24
|
+
),
|
|
25
|
+
}
|
|
26
|
+
#: Nesting to search: a result, a listing inside it, a record in the listing.
|
|
27
|
+
_MAX_DEPTH = 3
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def with_dataset_health(data: Any) -> Any:
|
|
31
|
+
"""Return ``data`` with a ``dataset_health`` list when any dataset in it is
|
|
32
|
+
unhealthy; anything else is returned unchanged."""
|
|
33
|
+
if not isinstance(data, dict):
|
|
34
|
+
return data
|
|
35
|
+
health = [_entry(record) for record in _unhealthy(data, 0)]
|
|
36
|
+
if not health:
|
|
37
|
+
return data
|
|
38
|
+
return {**data, "dataset_health": health}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _unhealthy(value: Any, depth: int) -> Iterator[dict[str, Any]]:
|
|
42
|
+
if depth > _MAX_DEPTH:
|
|
43
|
+
return
|
|
44
|
+
if isinstance(value, dict):
|
|
45
|
+
if value.get("status") in _UNHEALTHY and isinstance(value.get("id"), int):
|
|
46
|
+
yield value
|
|
47
|
+
for child in value.values():
|
|
48
|
+
yield from _unhealthy(child, depth + 1)
|
|
49
|
+
elif isinstance(value, list):
|
|
50
|
+
for child in value:
|
|
51
|
+
yield from _unhealthy(child, depth + 1)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _entry(record: dict[str, Any]) -> dict[str, Any]:
|
|
55
|
+
detail, fix = _UNHEALTHY[record["status"]]
|
|
56
|
+
return {
|
|
57
|
+
"dataset_id": record["id"],
|
|
58
|
+
"name": record.get("name"),
|
|
59
|
+
"status": record["status"],
|
|
60
|
+
"detail": detail,
|
|
61
|
+
"fix": fix.format(id=record["id"]),
|
|
62
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""How new data reaches a dataset, stated wherever such a dataset appears.
|
|
2
|
+
|
|
3
|
+
A dataset made from an uploaded file reads as a one-time snapshot, so an agent
|
|
4
|
+
asked for a recurring report concludes nothing new will ever arrive; the next
|
|
5
|
+
file appends to it as a new batch and its views re-run. A dataset written by a
|
|
6
|
+
view's export reads as a standalone copy, so an agent cannot tell what writes it
|
|
7
|
+
or what deleting it takes with it. :func:`with_new_data_path`
|
|
8
|
+
states either path; it never makes a request.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from collections.abc import Iterator
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
_FROM_FILE = (
|
|
17
|
+
"Made from an uploaded file; the next period's file joins this dataset as a "
|
|
18
|
+
"new batch with mammoth file upload FILE --input '{{\"append_to_ds_id\": {id}}}'. "
|
|
19
|
+
"Its views re-run on the added rows, so a scheduled automation on a view "
|
|
20
|
+
"sends the updated data without anyone rebuilding the pipeline."
|
|
21
|
+
)
|
|
22
|
+
_FROM_EXPORT = (
|
|
23
|
+
"Written by export {export_id} in view {view_id}'s pipeline, which fills it "
|
|
24
|
+
"again on every run of that view. Deleting this dataset also removes that "
|
|
25
|
+
"export; to keep the dataset but stop the updates, run mammoth view export "
|
|
26
|
+
"delete {view_id} {export_id}."
|
|
27
|
+
)
|
|
28
|
+
#: Nesting to search: a result, a listing inside it, a record in the listing.
|
|
29
|
+
_MAX_DEPTH = 3
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def with_new_data_path(data: Any) -> Any:
|
|
33
|
+
"""Return ``data`` with a ``new_data`` list when any dataset in it was made
|
|
34
|
+
from an uploaded file or is written by a view's export; anything else is
|
|
35
|
+
returned unchanged."""
|
|
36
|
+
if not isinstance(data, dict):
|
|
37
|
+
return data
|
|
38
|
+
paths = [
|
|
39
|
+
{"dataset_id": record["id"], "name": record.get("name"), "how": how}
|
|
40
|
+
for record, how in _fed_datasets(data, 0)
|
|
41
|
+
]
|
|
42
|
+
if not paths:
|
|
43
|
+
return data
|
|
44
|
+
return {**data, "new_data": paths}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def with_file_upload_path(data: Any, dataset_id: int) -> Any:
|
|
48
|
+
"""Return file settings with a ``new_data`` entry: settings with a delimiter
|
|
49
|
+
exist only for a parsed upload, which the next period's file can join."""
|
|
50
|
+
info = data.get("info") if isinstance(data, dict) else None
|
|
51
|
+
if not isinstance(info, dict) or not info.get("delimiter"):
|
|
52
|
+
return data
|
|
53
|
+
how = _FROM_FILE.format(id=dataset_id)
|
|
54
|
+
return {**data, "new_data": [{"dataset_id": dataset_id, "name": None, "how": how}]}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _fed_datasets(value: Any, depth: int) -> Iterator[tuple[dict[str, Any], str]]:
|
|
58
|
+
if depth > _MAX_DEPTH:
|
|
59
|
+
return
|
|
60
|
+
if isinstance(value, dict):
|
|
61
|
+
how = _how(value)
|
|
62
|
+
if how is not None:
|
|
63
|
+
yield value, how
|
|
64
|
+
for child in value.values():
|
|
65
|
+
yield from _fed_datasets(child, depth + 1)
|
|
66
|
+
elif isinstance(value, list):
|
|
67
|
+
for child in value:
|
|
68
|
+
yield from _fed_datasets(child, depth + 1)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _how(record: dict[str, Any]) -> str | None:
|
|
72
|
+
if not isinstance(record.get("id"), int):
|
|
73
|
+
return None
|
|
74
|
+
info = record.get("additional_info")
|
|
75
|
+
if (
|
|
76
|
+
isinstance(info, dict)
|
|
77
|
+
and isinstance(info.get("DATAVIEW_ID"), int)
|
|
78
|
+
and isinstance(info.get("TRIGGER_ID"), int)
|
|
79
|
+
):
|
|
80
|
+
return _FROM_EXPORT.format(view_id=info["DATAVIEW_ID"], export_id=info["TRIGGER_ID"])
|
|
81
|
+
sources = record.get("sources")
|
|
82
|
+
if isinstance(sources, list) and any(
|
|
83
|
+
isinstance(s, dict) and s.get("type") == "file" for s in sources
|
|
84
|
+
):
|
|
85
|
+
return _FROM_FILE.format(id=record["id"])
|
|
86
|
+
return None
|
|
@@ -22,6 +22,11 @@ JOIN_MATCH_RATE_THRESHOLD = 0.8
|
|
|
22
22
|
#: view write can carry that runs a pipeline -- the only kind that can leave a
|
|
23
23
|
#: downstream export referencing something the write just changed or removed.
|
|
24
24
|
_VIEW_PIPELINE_MUTATION_CLASS = "reversible_pipeline"
|
|
25
|
+
#: Pipeline writes outside that class that can still drop or rename a column
|
|
26
|
+
#: a saved export reads: deleting a step, renaming, editing the pipeline.
|
|
27
|
+
_EXPORT_BREAKING_COMMANDS = frozenset(
|
|
28
|
+
{"view.task.delete", "view.transform.rename-columns", "view.pipeline.edit"}
|
|
29
|
+
)
|
|
25
30
|
|
|
26
31
|
_VIEW_EXPORT_LIST_COMMAND = "view.export.list"
|
|
27
32
|
|
|
@@ -336,11 +341,14 @@ def _apply_downstream_export_check(verify: dict[str, Any], invocation: Invocatio
|
|
|
336
341
|
|
|
337
342
|
|
|
338
343
|
def _pipeline_view_id(invocation: Invocation) -> int | None:
|
|
339
|
-
"""The view id a
|
|
344
|
+
"""The view id a write that can break an export acted on, or None otherwise."""
|
|
340
345
|
from mammoth_cli.manifest.loader import command_by_id
|
|
341
346
|
|
|
342
347
|
record = command_by_id(invocation.command_id) or {}
|
|
343
|
-
if
|
|
348
|
+
if (
|
|
349
|
+
record.get("mutation_class") != _VIEW_PIPELINE_MUTATION_CLASS
|
|
350
|
+
and invocation.command_id not in _EXPORT_BREAKING_COMMANDS
|
|
351
|
+
):
|
|
344
352
|
return None
|
|
345
353
|
for name in ("view_id", "dataview_id"):
|
|
346
354
|
value = invocation.positional(name)
|
|
@@ -101,6 +101,11 @@ def compile_condition(spec: Any) -> _ConditionResult:
|
|
|
101
101
|
if not isinstance(spec, dict):
|
|
102
102
|
raise _invalid("A condition must be a mapping.")
|
|
103
103
|
|
|
104
|
+
compound = [key for key in ("and", "or", "not") if key in spec]
|
|
105
|
+
if compound and len(spec) != 1:
|
|
106
|
+
raise _invalid(
|
|
107
|
+
f"'{compound[0]}' must be the condition's only key; nest the others inside it."
|
|
108
|
+
)
|
|
104
109
|
if "and" in spec or "or" in spec:
|
|
105
110
|
key = "and" if "and" in spec else "or"
|
|
106
111
|
branches = spec[key]
|