mammoth-cli 2.2.90__tar.gz → 2.2.92__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.2.90 → mammoth_cli-2.2.92}/PKG-INFO +1 -1
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/__init__.py +1 -1
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/app.py +26 -1
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/SKILL.md +1 -1
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/operations.md +4 -2
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/browse.py +40 -3
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/dashboard.py +31 -1
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/dataset.py +45 -4
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/help_summaries.json +1 -1
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/view_ops.py +137 -22
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/errors/envelope.py +3 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/dataset_health.py +12 -1
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/input_loader.py +42 -4
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/shared.py +1 -3
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/state.py +11 -7
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/strict.py +45 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/validate.py +11 -2
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/coerce.py +48 -4
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/delete_check.py +4 -2
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/field_enums.py +9 -1
- mammoth_cli-2.2.92/mammoth_cli/services/poll.py +22 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/sdk_service.py +32 -2
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/pyproject.toml +1 -1
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/view.yaml +10 -6
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/.gitignore +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/LICENSE +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/README.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/__main__.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/about-mammoth.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/auth.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities-misc.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/command-index.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/activity.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/addon.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/agent.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/ai.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/annotation.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/auth.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/automation.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/batch.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/billing.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/browse.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/calc.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/capabilities.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/capability.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/client-app.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/collection.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/completion.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/config.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/connector.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/context.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-embed.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-published.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-qa.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-style.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-template.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/data-app.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dataset.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/doctor.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/external-key.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/file.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/folder.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/how.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/job.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/link.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/log.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/notification.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/parameter.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/project.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/report.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/resolve.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schedule.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schema.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/skill.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/snippet.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/support.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/template.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/token.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/trash.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/upgrade.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/user.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/version.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/view-transform.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/view.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/webhook.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workflow.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workspace.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/handoff.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/input.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/jobs-drafts.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/machine-output.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/auth-scope.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/build-an-agent.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/cleanup.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/dashboards.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/database-import.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/end-to-end.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/exports.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/file-import.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/index.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/need-action.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/resources.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/rest-api-import.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/scheduling.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/transforms.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/typed-etl-discovery.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/recovery.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/report-checklist.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/retention.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/safety.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/bundled_skill/mammoth-cli/references/task-start.md +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/__init__.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/_lazy.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/activity.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/addon.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/agent.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/ai.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/annotation.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/auth.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/automation.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/batch.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/billing.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/calc.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/capabilities.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/capability.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/client_app.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/completion.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/config.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/connector.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/context.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/data_app.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/doctor.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/external_key.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/file.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/folder.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/how.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/job.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/link.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/notification.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/parameter.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/project.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/registry.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/report.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/resolve.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/schedule.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/schema.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/skill.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/snippet.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/support.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/template.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/trash.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/upgrade.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/user.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/view.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/view_drivers.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/view_explore.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/view_forecast.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/view_profile.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/webhook.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/workflow.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/commands/workspace.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/context/__init__.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/context/credentials.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/context/endpoint.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/context/keyring_backend.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/context/oauth.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/context/profiles.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/context/resolver.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/contracts/__init__.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/contracts/auth.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/discovery/__init__.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/discovery/limitations.json +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/discovery/next_commands.json +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/discovery/recipes.json +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/embed.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/errors/__init__.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/manifest/__init__.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/manifest/loader.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/messages/__init__.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/output/__init__.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/output/envelope.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/output/normalize.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/output/policy.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/output/progress.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/output/render.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/py.typed +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/__init__.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/compact.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/confirm.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/dryrun.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/dryrun_targets.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/embedded.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/executor.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/intent_only.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/invocation.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/labels.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/locked_files.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/new_data.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/next_commands.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/opens.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/options.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/parents.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/runlog.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/session.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/token_scope.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/updates.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/runtime/verify.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/__init__.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/append_blank_columns.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/argspec.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/board_values.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/column_type_guard.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/command_contract.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/conditional_format.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/conditions.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/dashboard_figures.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/dashboard_filters.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/dashboard_pages.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/dashboard_review.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/data_profile.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/data_quality.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/dispatch.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/explore_card_edit.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/explore_cards.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/explore_to_figure.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/explore_to_image.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/factory.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/folder_ids.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/input_fields.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/job_outcome.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/listing.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/local_files.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/local_time.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/mapping.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/openapi_types.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/paging.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/period_analysis.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/positionals.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/protocol.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/read_memo.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/read_queries.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/schema_diff.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/sql_check.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/stored_stats.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/suggest.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/testing.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/text_dates.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/type_system.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/view_analysis.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/view_variants.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/services/write_impact.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/skills/__init__.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/skills/installer.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/skills/steering.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/mammoth_cli/testing.py +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/activity.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/addon.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/agent.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/ai.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/annotation.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/auth.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/automation.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/batch.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/billing.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/browse.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/calc.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/capabilities.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/capability.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/client-app.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/collection.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/completion.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/config.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/connector.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/context.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/dashboard.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/data-app.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/dataset.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/doctor.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/external-key.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/file.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/folder.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/how.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/job.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/link.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/log.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/notification.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/parameter.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/project.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/report.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/resolve.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/schedule.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/schema.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/skill.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/snippet.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/support.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/template.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/token.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/trash.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/upgrade.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/user.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/version.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/webhook.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/workflow.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/commands/workspace.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/edits-target.source.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/openapi-operations.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/schema-v1.json +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/sdk-catalog.source.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/manifests/sdk-methods.yaml +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/openapi/metadata.json +0 -0
- {mammoth_cli-2.2.90 → mammoth_cli-2.2.92}/spec/openapi/openapi.json +0 -0
|
@@ -428,6 +428,29 @@ def _global_option_flags() -> tuple[frozenset[str], frozenset[str]]:
|
|
|
428
428
|
return frozenset(every), frozenset(valued)
|
|
429
429
|
|
|
430
430
|
|
|
431
|
+
def missing_argument_hint(tokens: Sequence[str]) -> str:
|
|
432
|
+
"""The command's usage line and runnable example, for a ``missing_argument`` error.
|
|
433
|
+
|
|
434
|
+
The command is the longest run of leading words that names one; with none, the
|
|
435
|
+
generic pointer to the schema.
|
|
436
|
+
"""
|
|
437
|
+
generic = "Check the command schema with 'mammoth schema get'."
|
|
438
|
+
path_to_command, _ = _command_tree()
|
|
439
|
+
words = [token for token in tokens if not token.startswith("-")]
|
|
440
|
+
for length in range(len(words), 0, -1):
|
|
441
|
+
command_id = path_to_command.get(tuple(words[:length]))
|
|
442
|
+
if command_id is None:
|
|
443
|
+
continue
|
|
444
|
+
slots = " ".join(
|
|
445
|
+
spec.metavar if spec.required else f"[{spec.metavar}]"
|
|
446
|
+
for spec in resolve_positionals(command_id)
|
|
447
|
+
)
|
|
448
|
+
usage = " ".join(part for part in ("mammoth", *words[:length], slots) if part)
|
|
449
|
+
example = (command_by_id(command_id) or {}).get("agent_example")
|
|
450
|
+
return f"Usage: {usage}." + (f" Example: {example}" if example else "")
|
|
451
|
+
return generic
|
|
452
|
+
|
|
453
|
+
|
|
431
454
|
def _corrected_command(tokens: Sequence[str]) -> str | None:
|
|
432
455
|
"""Rebuild an invocation with leading global options moved after the command.
|
|
433
456
|
|
|
@@ -747,7 +770,7 @@ class _EnvelopeGroup(TyperGroup):
|
|
|
747
770
|
code="missing_argument",
|
|
748
771
|
message=error_message,
|
|
749
772
|
exit_status=EXIT_USAGE,
|
|
750
|
-
hint=
|
|
773
|
+
hint=missing_argument_hint(tokens),
|
|
751
774
|
)
|
|
752
775
|
elif isinstance(error, _typer_click_exceptions.NoSuchOption):
|
|
753
776
|
option = getattr(error, "option_name", None) or "unknown"
|
|
@@ -779,6 +802,8 @@ class _EnvelopeGroup(TyperGroup):
|
|
|
779
802
|
executor.emit_error(report, machine=True)
|
|
780
803
|
elif report is None:
|
|
781
804
|
error.show()
|
|
805
|
+
if is_missing_parameter:
|
|
806
|
+
typer.echo(missing_argument_hint(tokens), err=True)
|
|
782
807
|
else:
|
|
783
808
|
# A no-subcommand error arrives with the help text already on
|
|
784
809
|
# screen, so repeating "run --help" below it would be noise.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: mammoth-cli
|
|
3
|
-
version: 2.2.
|
|
3
|
+
version: 2.2.92
|
|
4
4
|
description: "Use Mammoth Analytics from a terminal: install or authenticate the CLI, discover its live command contract, and safely manage projects, data, views, pipelines (join, merge, pivot, filter, clean), dashboards, exports, and handoffs."
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -98,8 +98,10 @@ When several transforms go on the same view in a row (for example filter, sort,
|
|
|
98
98
|
limit-rows), send them in one `view transform batch VIEW_ID --input '{"steps": [{"op":
|
|
99
99
|
"filter", "input": {...}}, ...]}'` instead of one command each: the pipeline runs once and
|
|
100
100
|
one verified outcome comes back (`row_check`, and `tasks` with each new task's status).
|
|
101
|
-
Each `input` is what that `view transform` command takes. A step
|
|
102
|
-
earlier step
|
|
101
|
+
Each `input` is what that `view transform` command takes. A step can use the columns an
|
|
102
|
+
earlier step adds (`split`, `copy-columns`, or the `new_column` of `substring`, `extract-date`,
|
|
103
|
+
`increment-date`). `split`, `unnest` and `pivot` can be
|
|
104
|
+
batch steps too; `unnest` and `pivot` replace the view's columns, so they go last (and no `sort` step before them). If a task fails, the batch's tasks
|
|
103
105
|
are removed and the error names `steps[i]`.
|
|
104
106
|
|
|
105
107
|
Prefer a typed `view transform <operation>` command. Its schema is the
|
|
@@ -17,6 +17,7 @@ from mammoth_cli.errors.envelope import (
|
|
|
17
17
|
CODE_INVALID_ARGUMENT,
|
|
18
18
|
CODE_MISSING_ARGUMENT,
|
|
19
19
|
CODE_MISSING_FIELD,
|
|
20
|
+
CODE_RESOURCE_NOT_FOUND,
|
|
20
21
|
CODE_SDK_SYMBOL_UNRESOLVED,
|
|
21
22
|
EXIT_USAGE,
|
|
22
23
|
CliError,
|
|
@@ -28,6 +29,31 @@ from mammoth_cli.services.folder_ids import FolderIds
|
|
|
28
29
|
|
|
29
30
|
HandlerResult = tuple[Any, dict[str, Any]]
|
|
30
31
|
|
|
32
|
+
#: The route's resource types are datasource, dataview, label, file_object, report and webhook;
|
|
33
|
+
#: these are the names a caller reaches for instead.
|
|
34
|
+
_RESOURCE_TYPE_ALIASES = {"dataset": "datasource", "folder": "label"}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def canonical_resource_type(value: str) -> str:
|
|
38
|
+
"""``value`` (one type, or several joined by commas) with each alias as the route's name."""
|
|
39
|
+
return ",".join(
|
|
40
|
+
_RESOURCE_TYPE_ALIASES.get(part.strip(), part.strip()) for part in value.split(",")
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def ancestors_needs_a_folder(error: CliError) -> CliError:
|
|
45
|
+
"""``error`` (the 404 for an id that is no folder) as a message saying what to pass."""
|
|
46
|
+
return CliError(
|
|
47
|
+
code=error.code,
|
|
48
|
+
message="browse ancestors needs a FOLDER id; this id is not a folder.",
|
|
49
|
+
exit_status=error.exit_status,
|
|
50
|
+
hint=(
|
|
51
|
+
"A dataset or view has no ancestors of its own: run `mammoth browse resource "
|
|
52
|
+
"dataset ID` (or `dataview ID`) and pass the parent_resource_id it returns."
|
|
53
|
+
),
|
|
54
|
+
details=error.details,
|
|
55
|
+
)
|
|
56
|
+
|
|
31
57
|
|
|
32
58
|
def _symbol(invocation: Invocation) -> str:
|
|
33
59
|
"""Return the reviewed backing SDK symbol for this command."""
|
|
@@ -213,7 +239,8 @@ def browse_resource(invocation: Invocation) -> HandlerResult:
|
|
|
213
239
|
)
|
|
214
240
|
with open_service(invocation) as (service, auth):
|
|
215
241
|
folders = FolderIds(service)
|
|
216
|
-
|
|
242
|
+
resource_type = canonical_resource_type(str(resource_type))
|
|
243
|
+
if resource_type == "label":
|
|
217
244
|
object_id = folders.label(project_id, int(object_id))
|
|
218
245
|
data = service.call(
|
|
219
246
|
_symbol(invocation),
|
|
@@ -230,7 +257,14 @@ def browse_ancestors(invocation: Invocation) -> HandlerResult:
|
|
|
230
257
|
project_id = require_project(invocation)
|
|
231
258
|
resource_id = _require_int_positional(invocation, "resource id")
|
|
232
259
|
with open_service(invocation) as (service, auth):
|
|
233
|
-
|
|
260
|
+
try:
|
|
261
|
+
found = service.call(
|
|
262
|
+
_symbol(invocation), resource_id=resource_id, project_id=project_id
|
|
263
|
+
)
|
|
264
|
+
except CliError as exc:
|
|
265
|
+
if exc.code != CODE_RESOURCE_NOT_FOUND:
|
|
266
|
+
raise
|
|
267
|
+
raise ancestors_needs_a_folder(exc) from exc
|
|
234
268
|
data = FolderIds(service).open_data(found, project_id)
|
|
235
269
|
return data, _meta(invocation, auth.workspace_id, project_id)
|
|
236
270
|
|
|
@@ -238,7 +272,8 @@ def browse_ancestors(invocation: Invocation) -> HandlerResult:
|
|
|
238
272
|
def browse_search(invocation: Invocation) -> HandlerResult:
|
|
239
273
|
"""Search resources across every project of the workspace (resources v2).
|
|
240
274
|
|
|
241
|
-
``resource_type`` ``dataset`` means the route's ``datasource
|
|
275
|
+
``resource_type`` ``dataset`` means the route's ``datasource``, ``folder`` its ``label``.
|
|
276
|
+
Each dataset hit
|
|
242
277
|
carries ``dataset_id`` and each view hit ``view_id``: pass those, never the tree ``id``.
|
|
243
278
|
"""
|
|
244
279
|
document = invocation.load_input() or {}
|
|
@@ -246,6 +281,8 @@ def browse_search(invocation: Invocation) -> HandlerResult:
|
|
|
246
281
|
_forward_optional(
|
|
247
282
|
document, kwargs, ("search", "resource_type", "cursor", "limit", "sort", "fields")
|
|
248
283
|
)
|
|
284
|
+
if isinstance(kwargs.get("resource_type"), str):
|
|
285
|
+
kwargs["resource_type"] = canonical_resource_type(kwargs["resource_type"])
|
|
249
286
|
with open_service(invocation) as (service, auth):
|
|
250
287
|
data = FolderIds(service).open_data(service.call(_symbol(invocation), **kwargs), None)
|
|
251
288
|
return _with_object_ids(data), _meta(invocation, auth.workspace_id, None)
|
|
@@ -618,10 +618,13 @@ def dashboard_share(invocation: Invocation) -> HandlerResult:
|
|
|
618
618
|
assert document is not None
|
|
619
619
|
_forward_optional(document, kwargs, ("users",))
|
|
620
620
|
with open_service(invocation) as (service, auth):
|
|
621
|
+
was_published = _was_published(service, dashboard_id)
|
|
622
|
+
if not was_published:
|
|
623
|
+
refuse_viewer_share_before_publish(dashboard_id, type_of_auth, kwargs.get("users"))
|
|
621
624
|
unpublished = (
|
|
622
625
|
" (not published yet: sharing alone does not publish it; run dashboard action "
|
|
623
626
|
'with {"action":"publish-presentation"} to publish)'
|
|
624
|
-
if not
|
|
627
|
+
if not was_published
|
|
625
628
|
else ""
|
|
626
629
|
)
|
|
627
630
|
enforce_confirmation(
|
|
@@ -638,6 +641,33 @@ def dashboard_share(invocation: Invocation) -> HandlerResult:
|
|
|
638
641
|
return data, _meta(invocation, auth.workspace_id)
|
|
639
642
|
|
|
640
643
|
|
|
644
|
+
def refuse_viewer_share_before_publish(
|
|
645
|
+
dashboard_id: int, type_of_auth: str, users: list[dict[str, Any]] | None
|
|
646
|
+
) -> None:
|
|
647
|
+
"""Refuse, as the server does, a ``mammoth`` share that gives viewer access before a publish.
|
|
648
|
+
|
|
649
|
+
The server (``_apply_mammoth_recipients``) refuses the whole request when any user is
|
|
650
|
+
shared as a viewer (the default role) and the board has no published version.
|
|
651
|
+
"""
|
|
652
|
+
if type_of_auth != "mammoth":
|
|
653
|
+
return
|
|
654
|
+
for user in users or []:
|
|
655
|
+
shared = user.get("shared", True)
|
|
656
|
+
shared = shared.lower() in ("true", "1", "yes", "on") if isinstance(shared, str) else shared
|
|
657
|
+
if shared and user.get("role") != "dashboard_editor":
|
|
658
|
+
raise CliError(
|
|
659
|
+
code="dashboard_not_published",
|
|
660
|
+
message=f"Dashboard {dashboard_id} is not published; viewers cannot be invited.",
|
|
661
|
+
exit_status=EXIT_USAGE,
|
|
662
|
+
hint=(
|
|
663
|
+
"Publish it first: mammoth dashboard action "
|
|
664
|
+
f'{dashboard_id} --input \'{{"action": "publish-presentation"}}\' --yes, '
|
|
665
|
+
"then share. Or share only users with role dashboard_editor."
|
|
666
|
+
),
|
|
667
|
+
details={"dashboard_id": dashboard_id},
|
|
668
|
+
)
|
|
669
|
+
|
|
670
|
+
|
|
641
671
|
def _share_readback(service: Any, dashboard_id: int) -> dict[str, Any]:
|
|
642
672
|
"""The board's share state as ``dashboard get`` reports it after a share."""
|
|
643
673
|
board = _dump_model(service.call(_DASHBOARD_GET, dashboard_id=dashboard_id))
|
|
@@ -35,7 +35,7 @@ from mammoth_cli.runtime.confirm import (
|
|
|
35
35
|
)
|
|
36
36
|
from mammoth_cli.runtime.invocation import Invocation
|
|
37
37
|
from mammoth_cli.runtime.new_data import with_file_upload_path
|
|
38
|
-
from mammoth_cli.runtime.session import open_service, require_project
|
|
38
|
+
from mammoth_cli.runtime.session import open_service, require_project, resolved_project
|
|
39
39
|
from mammoth_cli.services.delete_check import ensure_deleted, find_dependents
|
|
40
40
|
from mammoth_cli.services.field_enums import DATA_PULL_FILE_VALUES, allowed_values_text
|
|
41
41
|
from mammoth_cli.services.listing import (
|
|
@@ -761,17 +761,22 @@ def dataset_list(invocation: Invocation) -> HandlerResult:
|
|
|
761
761
|
datasets" never needs paging: read ``total`` with the first page's newest names.
|
|
762
762
|
For a list of names (e.g. "which files can I see?") pass ``names: true``: ONE call
|
|
763
763
|
returns up to 500 bare ``{id, name}`` rows, newest first, with ``total`` and ``more``.
|
|
764
|
+
With no project set it returns ``{project_id, project_name, id, name}`` rows from every
|
|
765
|
+
project the caller can open, from one workspace search (the newest 500 at most).
|
|
764
766
|
``full: true`` returns the raw ``{id, name}`` list instead. ``name`` keeps only datasets
|
|
765
767
|
whose name contains it (case-insensitive) across every page, as short rows without
|
|
766
768
|
column lists; ``limit``/``offset`` then page over the matches.
|
|
767
769
|
"""
|
|
768
|
-
project_id = require_project(invocation)
|
|
769
770
|
document = invocation.load_input() or {}
|
|
771
|
+
name = document.get("name")
|
|
772
|
+
wants_names = document.get("names") and not (isinstance(name, str) and name.strip())
|
|
773
|
+
if wants_names and resolved_project(invocation) is None:
|
|
774
|
+
return _dataset_names_everywhere(invocation)
|
|
775
|
+
project_id = require_project(invocation)
|
|
770
776
|
_validate_paging(document)
|
|
771
777
|
kwargs: dict[str, Any] = {"project_id": project_id}
|
|
772
778
|
_forward_optional(document, kwargs, ("limit", "offset", "sort"))
|
|
773
|
-
|
|
774
|
-
if document.get("names") and not (isinstance(name, str) and name.strip()):
|
|
779
|
+
if wants_names:
|
|
775
780
|
return _dataset_names(invocation, project_id, document)
|
|
776
781
|
if isinstance(name, str) and name.strip():
|
|
777
782
|
return _dataset_name_search(invocation, project_id, name.strip(), document)
|
|
@@ -817,6 +822,42 @@ def _dataset_names(
|
|
|
817
822
|
return result, _meta(invocation, auth.workspace_id, project_id)
|
|
818
823
|
|
|
819
824
|
|
|
825
|
+
def _dataset_names_everywhere(invocation: Invocation) -> HandlerResult:
|
|
826
|
+
"""``dataset list`` with ``names`` and no project: the names of every reachable project.
|
|
827
|
+
|
|
828
|
+
One workspace search (100 hits a page, the route's cap) lists the datasets of the
|
|
829
|
+
projects the caller can open, under the same access rules as ``project list``; one
|
|
830
|
+
``project list`` read supplies the project names. Capped at ``_SEARCH_PAGES`` pages.
|
|
831
|
+
"""
|
|
832
|
+
with open_service(invocation) as (service, auth):
|
|
833
|
+
hits, cut = search_hits(service, "datasource", "", fields="minimal")
|
|
834
|
+
names = {p.get("id"): p.get("name") for p in _visible_projects(service)}
|
|
835
|
+
rows = [
|
|
836
|
+
{
|
|
837
|
+
"project_id": hit["project_id"],
|
|
838
|
+
"project_name": names[hit["project_id"]],
|
|
839
|
+
"id": hit["object_id"],
|
|
840
|
+
"name": hit.get("name"),
|
|
841
|
+
}
|
|
842
|
+
for hit in hits
|
|
843
|
+
if hit.get("project_id") in names
|
|
844
|
+
]
|
|
845
|
+
kept, _cut = fit_budget(rows[:NAMES_MAX_ROWS], budget=NAMES_DATA_BUDGET)
|
|
846
|
+
result: dict[str, Any] = {
|
|
847
|
+
"datasets": kept,
|
|
848
|
+
"shown": len(kept),
|
|
849
|
+
"total": len(rows),
|
|
850
|
+
"projects": len({row["project_id"] for row in rows}),
|
|
851
|
+
}
|
|
852
|
+
if cut or len(kept) < len(rows):
|
|
853
|
+
result["more"] = True
|
|
854
|
+
result["note"] = (
|
|
855
|
+
f"Only the newest {len(kept)} names were read; pass --project to list one "
|
|
856
|
+
"project's names, or name to find one."
|
|
857
|
+
)
|
|
858
|
+
return result, _meta(invocation, auth.workspace_id, None)
|
|
859
|
+
|
|
860
|
+
|
|
820
861
|
def _dataset_total(service: Any, project_id: int, page: dict[str, Any], offset: int) -> int:
|
|
821
862
|
"""The project's whole dataset count. The list route sends none, so a page that
|
|
822
863
|
is the last one counts itself; otherwise the ids are read once, here, in one call."""
|
|
@@ -689,7 +689,7 @@
|
|
|
689
689
|
"view.transform.increment-date": "Increment a date column. 'column'/'delta' required.",
|
|
690
690
|
"view.transform.join": "Join another view. 'foreign_view'/'join_type'/'on'/'select' required.",
|
|
691
691
|
"view.transform.json-extract": "Extract fields from a JSON column. 'column' is required.",
|
|
692
|
-
"view.transform.limit-rows": "Limit the row count. 'n' is required.",
|
|
692
|
+
"view.transform.limit-rows": "Limit the row count. 'n' (or its alias 'limit') is required.",
|
|
693
693
|
"view.transform.lookup": "Look up values from another view. 'source'/'lookup_view_id'/'key'/",
|
|
694
694
|
"view.transform.math": "Evaluate a math expression into a column. 'expression' is required.",
|
|
695
695
|
"view.transform.pivot": "Pivot with aggregations. 'group_by'/'aggregations' required.",
|
|
@@ -68,7 +68,7 @@ from mammoth_cli.runtime.confirm import POLICY_PROMPT_OR_YES, enforce_confirmati
|
|
|
68
68
|
from mammoth_cli.runtime.dryrun import DryRunStop
|
|
69
69
|
from mammoth_cli.runtime.invocation import Invocation
|
|
70
70
|
from mammoth_cli.runtime.session import open_service, resolved_project
|
|
71
|
-
from mammoth_cli.runtime.strict import validate_input_fields
|
|
71
|
+
from mammoth_cli.runtime.strict import apply_input_aliases, validate_input_fields
|
|
72
72
|
from mammoth_cli.runtime.verify import export_stamps, export_stamps_read
|
|
73
73
|
from mammoth_cli.services.column_type_guard import (
|
|
74
74
|
DATE,
|
|
@@ -80,8 +80,9 @@ from mammoth_cli.services.column_type_guard import (
|
|
|
80
80
|
from mammoth_cli.services.command_contract import bind_command_inputs, resolve_command_contract
|
|
81
81
|
from mammoth_cli.services.conditions import CONDITION_KWARG, compile_condition
|
|
82
82
|
from mammoth_cli.services.delete_check import ensure_deleted
|
|
83
|
-
from mammoth_cli.services.field_enums import BATCH_OPS, allowed_values_text
|
|
83
|
+
from mammoth_cli.services.field_enums import BATCH_LAST_OPS, BATCH_OPS, allowed_values_text
|
|
84
84
|
from mammoth_cli.services.input_fields import TASK_COUNT_FIELD
|
|
85
|
+
from mammoth_cli.services.poll import poll_delays
|
|
85
86
|
from mammoth_cli.services.read_memo import prefetch
|
|
86
87
|
from mammoth_cli.services.sql_check import check_sql_binds
|
|
87
88
|
from mammoth_cli.services.suggest import nearest_one
|
|
@@ -484,16 +485,27 @@ def _dispatch_view(
|
|
|
484
485
|
data = {key: value for key, value in data.items() if key != "message"}
|
|
485
486
|
data["status"] = "done"
|
|
486
487
|
data["draft_applied"] = True
|
|
488
|
+
settled = _settled_write(service, data) if dataset_id is not None else None
|
|
489
|
+
if settled is not None:
|
|
490
|
+
_forget_reads(service) # the state read-back must see the view as the write left it
|
|
487
491
|
if after is not None and dataset_id is not None:
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
492
|
+
if settled is not None:
|
|
493
|
+
run: dict[str, Any] | None = {
|
|
494
|
+
"task_id": settled["task_id"],
|
|
495
|
+
"transform_status": settled["task_run_status"],
|
|
496
|
+
}
|
|
497
|
+
run_error = None
|
|
498
|
+
else:
|
|
499
|
+
run, run_error = (
|
|
500
|
+
wait_for_added_task_run(service, int(dataset_id), view_id, task_ids_before)
|
|
501
|
+
if task_ids_before is not None and not _is_staged(data)
|
|
502
|
+
else (None, None)
|
|
503
|
+
)
|
|
493
504
|
reject_unrun_task_with_reference_errors(service, view_id, dataset_id, run_error)
|
|
494
505
|
sdk_ready = sdk_saw_pipeline_ready(data)
|
|
495
506
|
data = after(service, int(dataset_id), state, data)
|
|
496
|
-
|
|
507
|
+
if settled is None:
|
|
508
|
+
_flag_unsettled_pipeline(service, int(dataset_id), view_id, data, sdk_ready)
|
|
497
509
|
if isinstance(data, dict) and run is not None:
|
|
498
510
|
data["run"] = run
|
|
499
511
|
if run_error is not None:
|
|
@@ -508,8 +520,12 @@ def _dispatch_view(
|
|
|
508
520
|
# recomputing and read back no row_count at all; wait for it to
|
|
509
521
|
# settle (bounded) before trusting this one. A staged draft never
|
|
510
522
|
# ran the pipeline, so there is nothing to wait for or read.
|
|
511
|
-
rows_after, pipeline_error =
|
|
512
|
-
|
|
523
|
+
rows_after, pipeline_error = (
|
|
524
|
+
(settled["row_count"], None)
|
|
525
|
+
if settled is not None
|
|
526
|
+
else wait_for_view_row_count(
|
|
527
|
+
service, int(dataset_id), view_id, invocation.project, write_result=data
|
|
528
|
+
)
|
|
513
529
|
)
|
|
514
530
|
data["row_check"] = {"rows_before": rows_before, "rows_after": rows_after}
|
|
515
531
|
if reduces_rows and not invocation.standing_noop:
|
|
@@ -547,6 +563,8 @@ _RUN_FAILED_STATUSES = _RUN_OVER_STATUSES - {_RUN_DONE_STATUS}
|
|
|
547
563
|
#: Bounded wait for the run of a task just added: it starts after the add returns.
|
|
548
564
|
_RUN_ATTEMPTS = 40
|
|
549
565
|
_RUN_RETRY_S = 0.5
|
|
566
|
+
#: Most seconds the wait for a task's run sleeps in all.
|
|
567
|
+
_RUN_WAIT_S = _RUN_ATTEMPTS * _RUN_RETRY_S
|
|
550
568
|
|
|
551
569
|
|
|
552
570
|
def _tasks(service: Any, dataset_id: int, view_id: int) -> list[dict[str, Any]]:
|
|
@@ -603,7 +621,7 @@ def wait_for_added_task_run(
|
|
|
603
621
|
else the pipeline_error that keeps the write from reading verified.
|
|
604
622
|
"""
|
|
605
623
|
run: dict[str, Any] = {}
|
|
606
|
-
for
|
|
624
|
+
for delay in poll_delays(_RUN_WAIT_S, _RUN_RETRY_S):
|
|
607
625
|
added = [
|
|
608
626
|
task
|
|
609
627
|
for task in _tasks(service, dataset_id, view_id)
|
|
@@ -621,7 +639,7 @@ def wait_for_added_task_run(
|
|
|
621
639
|
"task_id": run["task_id"],
|
|
622
640
|
"transform_status": status,
|
|
623
641
|
}
|
|
624
|
-
time.sleep(
|
|
642
|
+
time.sleep(delay)
|
|
625
643
|
return run, {
|
|
626
644
|
"execution_state": UNFINISHED_STATE,
|
|
627
645
|
"task_id": run.get("task_id"),
|
|
@@ -632,6 +650,44 @@ def wait_for_added_task_run(
|
|
|
632
650
|
}
|
|
633
651
|
|
|
634
652
|
|
|
653
|
+
def clean_write_result(job_response: Any) -> dict[str, Any] | None:
|
|
654
|
+
"""The ``write_result`` of a run job when it says the write ran and settled cleanly.
|
|
655
|
+
|
|
656
|
+
A newer server adds it to the run job's response. ``None`` (read the task, the
|
|
657
|
+
pipeline and the row count as before) when it is absent, or says anything but a
|
|
658
|
+
finished task on a ``ready`` pipeline with a row count: those reads name the failure.
|
|
659
|
+
"""
|
|
660
|
+
result = job_response.get("write_result") if isinstance(job_response, dict) else None
|
|
661
|
+
if (
|
|
662
|
+
isinstance(result, dict)
|
|
663
|
+
and result.get("task_id") is not None
|
|
664
|
+
and result.get("task_run_status") == _RUN_DONE_STATUS
|
|
665
|
+
and result.get("pipeline_state") == "ready"
|
|
666
|
+
and result.get("row_count") is not None
|
|
667
|
+
):
|
|
668
|
+
return result
|
|
669
|
+
return None
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
def _settled_write(service: Any, data: Any) -> dict[str, Any] | None:
|
|
673
|
+
"""The clean ``write_result`` of the run job a write names (``future_id``), read once."""
|
|
674
|
+
future_id = data.get("future_id") if isinstance(data, dict) else None
|
|
675
|
+
if not isinstance(future_id, int) or _is_staged(data):
|
|
676
|
+
return None
|
|
677
|
+
try:
|
|
678
|
+
job = service.wait_if_job({"future_id": future_id})
|
|
679
|
+
except CliError:
|
|
680
|
+
return None # the reads that follow report the failed or unfinished job
|
|
681
|
+
return clean_write_result(job)
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
def _forget_reads(service: Any) -> None:
|
|
685
|
+
"""Drop the reads made ahead of a write (see :mod:`mammoth_cli.services.read_memo`)."""
|
|
686
|
+
memo = getattr(service, "memo", None)
|
|
687
|
+
if memo is not None:
|
|
688
|
+
memo.clear()
|
|
689
|
+
|
|
690
|
+
|
|
635
691
|
def _is_staged(data: Any) -> bool:
|
|
636
692
|
"""Whether a write only staged its step in a draft, so no run is to be waited on."""
|
|
637
693
|
return isinstance(data, dict) and data.get("status") == "staged"
|
|
@@ -2059,7 +2115,7 @@ def view_transform_json_extract(invocation: Invocation) -> HandlerResult:
|
|
|
2059
2115
|
|
|
2060
2116
|
|
|
2061
2117
|
def view_transform_limit_rows(invocation: Invocation) -> HandlerResult:
|
|
2062
|
-
"""Limit the row count. ``n`` is required."""
|
|
2118
|
+
"""Limit the row count. ``n`` (or its alias ``limit``) is required."""
|
|
2063
2119
|
view_id = _view_id(invocation)
|
|
2064
2120
|
document = invocation.load_input()
|
|
2065
2121
|
_require_field(document, "n")
|
|
@@ -2079,7 +2135,10 @@ def view_transform_rename_columns(invocation: Invocation) -> HandlerResult:
|
|
|
2079
2135
|
|
|
2080
2136
|
|
|
2081
2137
|
def view_transform_sort(invocation: Invocation) -> HandlerResult:
|
|
2082
|
-
"""Set the view's row order (a display setting, not a task). ``order_by`` is required.
|
|
2138
|
+
"""Set the view's row order (a display setting, not a task). ``order_by`` is required.
|
|
2139
|
+
|
|
2140
|
+
``sort_by`` is accepted as its alias.
|
|
2141
|
+
"""
|
|
2083
2142
|
view_id = _view_id(invocation)
|
|
2084
2143
|
document = invocation.load_input()
|
|
2085
2144
|
_require_field(document, "order_by")
|
|
@@ -2342,9 +2401,9 @@ _TASK_DELETE_SYMBOL = "mammoth.api.pipeline.PipelineAPI.delete_task"
|
|
|
2342
2401
|
CODE_BATCH_STEP_FAILED = "batch_step_failed"
|
|
2343
2402
|
CODE_UNKNOWN_COLUMN = "unknown_column"
|
|
2344
2403
|
_BATCH_COLUMN_HINT = (
|
|
2345
|
-
"A batch is built against the view's columns
|
|
2346
|
-
"
|
|
2347
|
-
"
|
|
2404
|
+
"A batch is built against the view's columns plus the ones the earlier steps of the batch "
|
|
2405
|
+
"add (split, copy-columns, and any new_column of substring, extract-date, increment-date). "
|
|
2406
|
+
"A column in neither is unknown: check its name, or run the step that creates it first."
|
|
2348
2407
|
)
|
|
2349
2408
|
|
|
2350
2409
|
|
|
@@ -2357,6 +2416,9 @@ class _BatchPlan:
|
|
|
2357
2416
|
task_steps: list[tuple[int, str]] = dataclass_field(default_factory=list)
|
|
2358
2417
|
#: The bound ``sort`` inputs, applied after the tasks have run.
|
|
2359
2418
|
sorts: list[dict[str, Any]] = dataclass_field(default_factory=list)
|
|
2419
|
+
#: The columns the tasks add; the sort is built after they ran but on metadata that may not
|
|
2420
|
+
#: list them yet.
|
|
2421
|
+
created: list[dict[str, str]] = dataclass_field(default_factory=list)
|
|
2360
2422
|
|
|
2361
2423
|
|
|
2362
2424
|
def _batch_steps(document: dict[str, Any] | None) -> list[dict[str, Any]]:
|
|
@@ -2386,7 +2448,7 @@ def _batch_steps(document: dict[str, Any] | None) -> list[dict[str, Any]]:
|
|
|
2386
2448
|
exit_status=EXIT_USAGE,
|
|
2387
2449
|
hint=(
|
|
2388
2450
|
f"Allowed ops: {allowed_values_text(_BATCH_OPS)}. Run any other "
|
|
2389
|
-
"transform (
|
|
2451
|
+
"transform (join, math, ...) as its own `view transform` command."
|
|
2390
2452
|
),
|
|
2391
2453
|
details={
|
|
2392
2454
|
"step": index,
|
|
@@ -2395,6 +2457,32 @@ def _batch_steps(document: dict[str, Any] | None) -> list[dict[str, Any]]:
|
|
|
2395
2457
|
"did_you_mean": near,
|
|
2396
2458
|
},
|
|
2397
2459
|
)
|
|
2460
|
+
if step["op"] == _BATCH_SORT_OP and any(
|
|
2461
|
+
isinstance(later, dict) and later.get("op") in BATCH_LAST_OPS
|
|
2462
|
+
for later in steps[index + 1 :]
|
|
2463
|
+
):
|
|
2464
|
+
raise CliError(
|
|
2465
|
+
code=CODE_INVALID_ARGUMENT,
|
|
2466
|
+
message=(
|
|
2467
|
+
f"steps[{index}] (sort) comes before a step that replaces the view's columns, "
|
|
2468
|
+
"so its columns would no longer exist when the sort is applied."
|
|
2469
|
+
),
|
|
2470
|
+
exit_status=EXIT_USAGE,
|
|
2471
|
+
hint="Run the sort after the batch, as its own `view transform sort` command.",
|
|
2472
|
+
details={"step": index, "op": _BATCH_SORT_OP},
|
|
2473
|
+
)
|
|
2474
|
+
if step["op"] in BATCH_LAST_OPS and index != len(steps) - 1:
|
|
2475
|
+
raise CliError(
|
|
2476
|
+
code=CODE_INVALID_ARGUMENT,
|
|
2477
|
+
message=(
|
|
2478
|
+
f"steps[{index}] ({step['op']}) replaces the view's columns, so it must be "
|
|
2479
|
+
"the last step of a batch."
|
|
2480
|
+
),
|
|
2481
|
+
exit_status=EXIT_USAGE,
|
|
2482
|
+
hint=f"Move steps[{index}] to the end, or run the steps after it as their own "
|
|
2483
|
+
"`view transform` commands.",
|
|
2484
|
+
details={"step": index, "op": step["op"]},
|
|
2485
|
+
)
|
|
2398
2486
|
return steps
|
|
2399
2487
|
|
|
2400
2488
|
|
|
@@ -2412,17 +2500,34 @@ def _step_error(index: int, op: str, error: CliError) -> CliError:
|
|
|
2412
2500
|
)
|
|
2413
2501
|
|
|
2414
2502
|
|
|
2503
|
+
def _created_columns(task_spec: dict[str, Any]) -> list[dict[str, str]]:
|
|
2504
|
+
"""The ``{COLUMN, TYPE, INTERNAL_NAME}`` columns a built task adds, from its ``AS`` outputs.
|
|
2505
|
+
|
|
2506
|
+
``AS`` is one column (substring, extract-date, increment-date), a list of them (split) or
|
|
2507
|
+
sits on each item of the task's list (copy-columns).
|
|
2508
|
+
"""
|
|
2509
|
+
columns: list[dict[str, str]] = []
|
|
2510
|
+
for body in task_spec.values():
|
|
2511
|
+
for item in body if isinstance(body, list) else [body]:
|
|
2512
|
+
made = item.get("AS") if isinstance(item, dict) else None
|
|
2513
|
+
if made is not None:
|
|
2514
|
+
columns.extend(made if isinstance(made, list) else [made])
|
|
2515
|
+
return columns
|
|
2516
|
+
|
|
2517
|
+
|
|
2415
2518
|
def _build_batch(
|
|
2416
2519
|
invocation: Invocation, service: Any, view_id: int, dataset_id: int, steps: list[dict[str, Any]]
|
|
2417
2520
|
) -> _BatchPlan:
|
|
2418
2521
|
"""Bind and build every step against the view's current columns; send nothing."""
|
|
2419
2522
|
plan = _BatchPlan()
|
|
2523
|
+
created = plan.created
|
|
2420
2524
|
for index, step in enumerate(steps):
|
|
2421
2525
|
op = step["op"]
|
|
2422
2526
|
command_id = f"view.transform.{op}"
|
|
2423
2527
|
contract = resolve_command_contract(command_id)
|
|
2424
2528
|
assert contract is not None
|
|
2425
2529
|
try:
|
|
2530
|
+
apply_input_aliases(command_id, step["input"])
|
|
2426
2531
|
for spec in contract.fields:
|
|
2427
2532
|
if spec.required:
|
|
2428
2533
|
_require_field(step["input"], spec.name)
|
|
@@ -2438,7 +2543,12 @@ def _build_batch(
|
|
|
2438
2543
|
method = str((command_by_id(command_id) or {})["sdk_symbol"]).rsplit(".", 1)[-1]
|
|
2439
2544
|
try:
|
|
2440
2545
|
built = service.call_view(
|
|
2441
|
-
view_id,
|
|
2546
|
+
view_id,
|
|
2547
|
+
method,
|
|
2548
|
+
dataset_id=dataset_id,
|
|
2549
|
+
build_only=True,
|
|
2550
|
+
added_columns=created,
|
|
2551
|
+
**kwargs,
|
|
2442
2552
|
)
|
|
2443
2553
|
except CliError as exc:
|
|
2444
2554
|
raise _step_error(index, op, exc) from exc
|
|
@@ -2446,6 +2556,7 @@ def _build_batch(
|
|
|
2446
2556
|
plan.sorts.append(kwargs)
|
|
2447
2557
|
else:
|
|
2448
2558
|
plan.specs.append(built["task_spec"])
|
|
2559
|
+
created.extend(_created_columns(built["task_spec"]))
|
|
2449
2560
|
plan.task_steps.append((index, op))
|
|
2450
2561
|
return plan
|
|
2451
2562
|
|
|
@@ -2461,7 +2572,7 @@ def wait_for_added_tasks_run(
|
|
|
2461
2572
|
``count`` may be listed.
|
|
2462
2573
|
"""
|
|
2463
2574
|
runs: list[dict[str, Any]] = []
|
|
2464
|
-
for
|
|
2575
|
+
for delay in poll_delays(_RUN_WAIT_S, _RUN_RETRY_S):
|
|
2465
2576
|
added = sorted(
|
|
2466
2577
|
(t for t in _tasks(service, dataset_id, view_id) if t.get("id") not in task_ids_before),
|
|
2467
2578
|
key=lambda task: task.get("id") or 0,
|
|
@@ -2475,7 +2586,7 @@ def wait_for_added_tasks_run(
|
|
|
2475
2586
|
return runs
|
|
2476
2587
|
if len(runs) >= count and all(status == _RUN_DONE_STATUS for status in statuses):
|
|
2477
2588
|
return runs
|
|
2478
|
-
time.sleep(
|
|
2589
|
+
time.sleep(delay)
|
|
2479
2590
|
return runs
|
|
2480
2591
|
|
|
2481
2592
|
|
|
@@ -2591,7 +2702,11 @@ def _apply_batch(
|
|
|
2591
2702
|
try:
|
|
2592
2703
|
for kwargs in plan.sorts:
|
|
2593
2704
|
data["sort"] = service.call_view(
|
|
2594
|
-
view_id,
|
|
2705
|
+
view_id,
|
|
2706
|
+
_SORT_METHOD,
|
|
2707
|
+
dataset_id=dataset_id,
|
|
2708
|
+
added_columns=plan.created,
|
|
2709
|
+
**kwargs,
|
|
2595
2710
|
)["sort"]
|
|
2596
2711
|
except CliError as exc:
|
|
2597
2712
|
raise _batch_failure(service, dataset_id, view_id, task_ids_before, plan, exc) from exc
|
|
@@ -37,6 +37,7 @@ CODE_INVALID_ARGUMENT = "invalid_argument"
|
|
|
37
37
|
CODE_UPLOAD_REFUSED = "upload_refused"
|
|
38
38
|
CODE_INVALID_ARGUMENTS = "invalid_arguments"
|
|
39
39
|
CODE_INVALID_CONFIG_VALUE = "invalid_config_value"
|
|
40
|
+
CODE_INVALID_INPUT = "invalid_input"
|
|
40
41
|
CODE_INVALID_INPUT_DOCUMENT = "invalid_input_document"
|
|
41
42
|
CODE_INVALID_INPUT_FORMAT = "invalid_input_format"
|
|
42
43
|
CODE_INVALID_WORKSPACE_ID = "invalid_workspace_id"
|
|
@@ -147,6 +148,8 @@ ERROR_SUMMARIES: dict[str, str] = {
|
|
|
147
148
|
"invalid_config_value": _S_SETUP,
|
|
148
149
|
"invalid_credentials": "The sign-in details weren't accepted.",
|
|
149
150
|
"invalid_input_document": _S_BAD_INPUT,
|
|
151
|
+
"invalid_input": _S_BAD_INPUT,
|
|
152
|
+
"dashboard_not_published": "The dashboard has to be published before viewers can be invited.",
|
|
150
153
|
"invalid_input_encoding": _S_BAD_INPUT,
|
|
151
154
|
"invalid_input_field_type": _S_BAD_INPUT,
|
|
152
155
|
"invalid_input_format": _S_BAD_INPUT,
|