mammoth-cli 2.0.37__tar.gz → 2.0.39__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.37 → mammoth_cli-2.0.39}/PKG-INFO +2 -2
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/__init__.py +1 -1
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/SKILL.md +38 -2
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/about-mammoth.md +22 -11
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities.md +1 -1
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/command-index.md +2 -2
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/view.md +20 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/end-to-end.md +5 -2
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/transforms.md +35 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/task-start.md +4 -2
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/registry.py +2 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/schema.py +16 -4
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/view.py +200 -15
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/view_ops.py +64 -6
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/runtime/strict.py +14 -1
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/services/command_contract.py +4 -1
- mammoth_cli-2.0.39/mammoth_cli/services/data_quality.py +136 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/services/input_fields.py +3 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/pyproject.toml +2 -2
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/view.yaml +82 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/sdk-catalog.source.yaml +14 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/sdk-methods.yaml +24 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/.gitignore +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/LICENSE +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/README.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/__main__.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/app.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/auth.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities-misc.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/activity.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/addon.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/agent.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/ai.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/annotation.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/auth.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/automation.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/batch.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/billing.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/browse.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/capability.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/client-app.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/completion.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/config.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/connector.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/context.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/data-app.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dataset.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/doctor.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/external-key.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/file.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/folder.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/job.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/log.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/notification.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/parameter.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/project.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/report.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schedule.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schema.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/skill.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/snippet.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/support.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/template.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/trash.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/upgrade.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/user.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/version.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/webhook.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workflow.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workspace.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/handoff.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/input.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/jobs-drafts.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/machine-output.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/operations.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/auth-scope.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/cleanup.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/dashboards.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/exports.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/index.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/need-action.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/resources.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/typed-etl-discovery.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/recovery.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/report-checklist.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/retention.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/bundled_skill/mammoth-cli/references/safety.md +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/__init__.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/activity.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/addon.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/agent.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/ai.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/annotation.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/auth.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/automation.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/batch.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/billing.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/browse.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/capability.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/client_app.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/completion.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/config.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/connector.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/context.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/dashboard.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/data_app.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/dataset.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/doctor.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/external_key.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/file.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/folder.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/job.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/notification.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/parameter.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/project.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/report.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/schedule.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/skill.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/snippet.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/support.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/template.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/trash.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/upgrade.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/user.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/webhook.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/workflow.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/commands/workspace.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/context/__init__.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/context/credentials.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/context/endpoint.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/context/profiles.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/context/resolver.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/contracts/__init__.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/contracts/auth.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/errors/__init__.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/errors/envelope.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/manifest/__init__.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/manifest/loader.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/messages/__init__.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/output/__init__.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/output/envelope.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/output/normalize.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/output/policy.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/output/progress.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/output/render.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/py.typed +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/runtime/__init__.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/runtime/confirm.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/runtime/dryrun.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/runtime/executor.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/runtime/input_loader.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/runtime/invocation.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/runtime/options.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/runtime/parents.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/runtime/runlog.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/runtime/session.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/runtime/updates.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/runtime/validate.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/services/__init__.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/services/argspec.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/services/coerce.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/services/conditions.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/services/dispatch.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/services/factory.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/services/mapping.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/services/openapi_types.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/services/positionals.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/services/protocol.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/services/sdk_service.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/services/testing.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/services/type_system.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/skills/__init__.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/skills/installer.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/skills/steering.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/mammoth_cli/testing.py +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/activity.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/addon.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/agent.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/ai.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/annotation.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/auth.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/automation.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/batch.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/billing.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/browse.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/capability.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/client-app.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/completion.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/config.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/connector.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/context.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/dashboard.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/data-app.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/dataset.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/doctor.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/external-key.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/file.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/folder.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/job.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/log.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/notification.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/parameter.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/project.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/report.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/schedule.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/schema.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/skill.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/snippet.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/support.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/template.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/trash.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/upgrade.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/user.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/version.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/webhook.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/workflow.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/commands/workspace.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/openapi-operations.yaml +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/manifests/schema-v1.json +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/spec/openapi/metadata.json +0 -0
- {mammoth_cli-2.0.37 → mammoth_cli-2.0.39}/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.39
|
|
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.17
|
|
21
21
|
Requires-Dist: platformdirs<5,>=4.10
|
|
22
22
|
Requires-Dist: pydantic<3,>=2.13
|
|
23
23
|
Requires-Dist: pyyaml<7,>=6
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: mammoth-cli
|
|
3
|
-
version: 2.0.
|
|
3
|
+
version: 2.0.39
|
|
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
|
|
|
@@ -76,17 +76,49 @@ mammoth view transform --help # every data transformation
|
|
|
76
76
|
| Blanks to a constant, or to the previous row's value | `view transform set-values` (`IS_EMPTY`), `view transform fill-missing` |
|
|
77
77
|
| Clean text | `view transform text`, `replace`, `bulk-replace` |
|
|
78
78
|
| Change a column's type | `view transform convert-type` |
|
|
79
|
+
| Rename a column, sort the rows (view settings, not tasks) | `view transform rename-columns`, `view transform sort` |
|
|
79
80
|
| Rank, running total, previous row | `view transform window` |
|
|
80
81
|
| A dashboard | `dashboard create-blank` ([dashboards](references/recipes/dashboards.md)) |
|
|
81
82
|
| Deliver the rows | `view export csv`, `view export postgres` (and other destinations), `view export dataset` |
|
|
82
83
|
|
|
83
84
|
A search with no full match returns `suggestions` and a `hint`. Before you
|
|
84
85
|
conclude the CLI cannot do something the web app does, check
|
|
85
|
-
`view transform --help` and "
|
|
86
|
+
`view transform --help` and "View settings, and what has no command" in
|
|
86
87
|
[about Mammoth](references/about-mammoth.md). Do not switch to the web app
|
|
87
88
|
in a browser, or compute the result locally, for work the CLI covers;
|
|
88
89
|
report a real gap with the command you tried.
|
|
89
90
|
|
|
91
|
+
## Several files, one deliverable
|
|
92
|
+
|
|
93
|
+
Users often upload related files without saying how they relate ("make a
|
|
94
|
+
dashboard from t_a and t_b"). Work it out from the data before you build:
|
|
95
|
+
|
|
96
|
+
1. Upload every file, then read every view in Mammoth (not the local
|
|
97
|
+
files): `view get VIEW_ID` (columns, types, row count) and `view data get
|
|
98
|
+
VIEW_ID`. The data read lists `column_warnings`: numbers or dates stored
|
|
99
|
+
as text, and blanks, each with the fix.
|
|
100
|
+
2. Find the keys. A column in one view whose values appear in a column of
|
|
101
|
+
the other (`customer_id` and `id`, `order_ref` and `order_no`) is a
|
|
102
|
+
foreign key; the view with many rows per key is the main one.
|
|
103
|
+
3. Make the keys match before the join: same type (`convert-type`), same
|
|
104
|
+
case and padding (`text`), no blanks (`set-values`, `filter`).
|
|
105
|
+
4. Act on every `column_warnings` entry for a column the deliverable uses:
|
|
106
|
+
run its `fix` (`convert-type` to `NUMERIC` or `DATE`; the values that are
|
|
107
|
+
not numbers become empty), then decide on blanks (fill, filter, or keep and
|
|
108
|
+
say so). A text `price` cannot be summed on a dashboard.
|
|
109
|
+
5. `view transform join` the lookup view into the main view (`LEFT`). The
|
|
110
|
+
result's `join_check` gives `match_rate`, `unmatched_rows` and
|
|
111
|
+
`unmatched_keys`; put them in your report, and stop to compare the keys
|
|
112
|
+
if more than a few rows found no match.
|
|
113
|
+
6. Build the dashboard from the joined view
|
|
114
|
+
([dashboards](references/recipes/dashboards.md)).
|
|
115
|
+
|
|
116
|
+
For the defaults that most pipelines use (new column or overwrite, `LEFT`
|
|
117
|
+
joins, date steps), see
|
|
118
|
+
[transforms](references/recipes/transforms.md#what-most-pipelines-look-like).
|
|
119
|
+
Say what you inferred (which columns you joined on, what you converted) in
|
|
120
|
+
your report. If no column links the files, ask before you combine them.
|
|
121
|
+
|
|
90
122
|
## Calling a command
|
|
91
123
|
|
|
92
124
|
- Ids are positionals; request fields are one `--input '{...}'` document;
|
|
@@ -125,6 +157,10 @@ report a real gap with the command you tried.
|
|
|
125
157
|
target column *before* the change so the after-read has a comparison.
|
|
126
158
|
- A uniform result (every amount 0, every region "Unknown", most join rows
|
|
127
159
|
unmatched) means the previous step went wrong; stop and re-inspect it.
|
|
160
|
+
- `column_warnings` on a data read and `join_check` on a join are findings,
|
|
161
|
+
not decoration: fix each one the deliverable depends on, or say in the
|
|
162
|
+
report why you kept it. `view data get` pages with `{"offset": 51,
|
|
163
|
+
"limit": 50}`.
|
|
128
164
|
- A timeout, exit 7 or interruption does not prove failure; reconcile an
|
|
129
165
|
`outcome_unknown` (`job get`, `view task list`) before replaying.
|
|
130
166
|
- Run the [report checklist](references/report-checklist.md) before stating
|
|
@@ -100,6 +100,8 @@ Checkpoint Alert are the `view data-check` and `view checkpoint` families.
|
|
|
100
100
|
| Shift a date by an interval | Add / Subtract Date Values | `increment-date` |
|
|
101
101
|
| Add an empty column | Add Column | `add-column` |
|
|
102
102
|
| Copy a column under a new name | Copy Columns | `copy-columns` |
|
|
103
|
+
| Rename a column | Rename (column header) | `rename-columns` (a view setting, not a task) |
|
|
104
|
+
| Sort the rows | Sort (grid) | `sort` (a view setting, not a task) |
|
|
103
105
|
| Remove columns | Remove Column | `delete-columns` |
|
|
104
106
|
| Add columns from another view by matching keys | Join | `join` (`INNER`, `LEFT`, `RIGHT`, `OUTER`) |
|
|
105
107
|
| Bring one value per key from another view | Lookup | `lookup` |
|
|
@@ -117,15 +119,24 @@ value per key into one new column. Before either, confirm the key columns
|
|
|
117
119
|
in both views have the same type and values; recipes/transforms.md has the
|
|
118
120
|
read-back.
|
|
119
121
|
|
|
120
|
-
##
|
|
122
|
+
## View settings, and what has no command
|
|
123
|
+
|
|
124
|
+
Two commands change how the view shows its rows, not the rows. They add no
|
|
125
|
+
pipeline task, like their web counterparts (a column-header rename, a grid
|
|
126
|
+
sort):
|
|
127
|
+
|
|
128
|
+
- **Rename a column:** `view transform rename-columns` with `{"renames":
|
|
129
|
+
{"cust_id": "Customer ID"}}`. The column keeps its internal name, so
|
|
130
|
+
earlier tasks keep working; later commands, data reads, exports and
|
|
131
|
+
dashboards use the new name. To name a column you create, use its
|
|
132
|
+
`new_column` or `as_name` field instead.
|
|
133
|
+
- **Sort the rows:** `view transform sort` with `{"order_by": [["Revenue",
|
|
134
|
+
"DESC"]]}` (up to three columns; `[]` clears it). Data reads and exports
|
|
135
|
+
return rows in this order. To keep only the top N rows, use `limit-rows`
|
|
136
|
+
with `order_by`; for a rank column, `window` (`RANK`, `ROW_NUMBER`).
|
|
137
|
+
|
|
138
|
+
No command:
|
|
121
139
|
|
|
122
|
-
- **Rename a column.** The web app's rename is a display change, not a
|
|
123
|
-
task; the CLI has no rename command. Name new columns when you create them
|
|
124
|
-
(`new_column`, `as_name`); for an existing column, `copy-columns` under
|
|
125
|
-
the new name.
|
|
126
|
-
- **Sort.** There is no sort task, and the CLI has no sort command. For
|
|
127
|
-
"top N by X" use `limit-rows` with `order_by`; for a rank column use
|
|
128
|
-
`window` (`RANK`, `ROW_NUMBER`).
|
|
129
140
|
- **Union or append two views.** There is no union task. Upload a file into
|
|
130
141
|
an existing dataset with `append_to_ds_id`, or send a view's rows into an
|
|
131
142
|
existing dataset with `view export dataset` (`target_ds_id` and
|
|
@@ -139,6 +150,6 @@ Both call the same API. Do not switch to the web app in a browser for a
|
|
|
139
150
|
task the CLI covers. Before you conclude that the CLI cannot do something,
|
|
140
151
|
run `mammoth view transform --help`, search in plain words (`mammoth schema
|
|
141
152
|
find "merge two datasets"` finds `join`; a search with no full match lists
|
|
142
|
-
`suggestions`), and read
|
|
143
|
-
the gap with the command you tried; do not
|
|
144
|
-
by computing the result locally.
|
|
153
|
+
`suggestions`), and read "View settings, and what has no command" above.
|
|
154
|
+
If it is still missing, report the gap with the command you tried; do not
|
|
155
|
+
work around it in the browser or by computing the result locally.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# What is proven on release
|
|
2
2
|
|
|
3
3
|
Generated from `docs/release-capability-matrix.json`; do not edit by hand.
|
|
4
|
-
The CLI publishes
|
|
4
|
+
The CLI publishes 556 commands. 455 of them bind one of the 528 API operations in the matrix; the remainder are local commands (`schema`, `auth`, `doctor`, `log`, ...) or typed variants that share an operation (`view transform *` commands submit through `view.task.add`, except `rename-columns` and `sort`, which set view display properties through `view.update`). 262 bound commands ran once successfully on release, 2 are not supported there, and the rest are untried. Untried is not broken: discover the contract with `mammoth schema get COMMAND_ID`, run it, and treat the structured error envelope as the answer.
|
|
5
5
|
|
|
6
6
|
Status meanings:
|
|
7
7
|
|
|
@@ -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 556; 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
|
|
|
@@ -43,7 +43,7 @@ Load only the applicable domain file:
|
|
|
43
43
|
- [upgrade](commands/upgrade.md) — 1 published commands
|
|
44
44
|
- [user](commands/user.md) — 8 published commands
|
|
45
45
|
- [version](commands/version.md) — 1 published commands
|
|
46
|
-
- [view](commands/view.md) —
|
|
46
|
+
- [view](commands/view.md) — 118 published commands
|
|
47
47
|
- [webhook](commands/webhook.md) — 7 published commands
|
|
48
48
|
- [workflow](commands/workflow.md) — 16 published commands
|
|
49
49
|
- [workspace](commands/workspace.md) — 20 published commands
|
|
@@ -1034,6 +1034,16 @@ Result: `ViewTransformPivotResult`; mutation `reversible_pipeline`, confirmation
|
|
|
1034
1034
|
|
|
1035
1035
|
Status on release: ran once on CLI 2.0.18 through `view.task.add` and was read back with `view data get`; other inputs for this transform are untried.
|
|
1036
1036
|
|
|
1037
|
+
### `view.transform.rename-columns`
|
|
1038
|
+
|
|
1039
|
+
Run: `mammoth view transform rename-columns`. Exact input fields: `mammoth schema get view.transform.rename-columns`.
|
|
1040
|
+
|
|
1041
|
+
Example: `mammoth view transform rename-columns 123 --input '{"renames": {"cust_id": "Customer ID"}, "dataset_id": 456}'`. Placeholders are illustrative; resolve IDs and input from observed reads.
|
|
1042
|
+
|
|
1043
|
+
Result: `ViewTransformRenameColumnsResult`; mutation `benign_mutation`, confirmation `none`, wait policy `not_async`.
|
|
1044
|
+
|
|
1045
|
+
Status on release: untried; it submits through `view.task.add`, but this transform was not among those run.
|
|
1046
|
+
|
|
1037
1047
|
### `view.transform.replace`
|
|
1038
1048
|
|
|
1039
1049
|
Run: `mammoth view transform replace`. Exact input fields: `mammoth schema get view.transform.replace`.
|
|
@@ -1064,6 +1074,16 @@ Result: `ViewTransformSmallLargeResult`; mutation `reversible_pipeline`, confirm
|
|
|
1064
1074
|
|
|
1065
1075
|
Status on release: untried; it submits through `view.task.add`, but this transform was not among those run.
|
|
1066
1076
|
|
|
1077
|
+
### `view.transform.sort`
|
|
1078
|
+
|
|
1079
|
+
Run: `mammoth view transform sort`. Exact input fields: `mammoth schema get view.transform.sort`.
|
|
1080
|
+
|
|
1081
|
+
Example: `mammoth view transform sort 123 --input '{"order_by": [["Revenue", "DESC"]], "dataset_id": 456}'`. Placeholders are illustrative; resolve IDs and input from observed reads.
|
|
1082
|
+
|
|
1083
|
+
Result: `ViewTransformSortResult`; mutation `benign_mutation`, confirmation `none`, wait policy `not_async`.
|
|
1084
|
+
|
|
1085
|
+
Status on release: untried; it submits through `view.task.add`, but this transform was not among those run.
|
|
1086
|
+
|
|
1067
1087
|
### `view.transform.split`
|
|
1068
1088
|
|
|
1069
1089
|
Run: `mammoth view transform split`. Exact input fields: `mammoth schema get view.transform.split`.
|
|
@@ -22,6 +22,8 @@ mammoth view list CUSTOMERS_DS --project PROJECT_ID # -> CUSTOMERS_VIEW
|
|
|
22
22
|
# 2. look before you change: column names, types, row_count, a sample
|
|
23
23
|
mammoth view get ORDERS_VIEW ORDERS_DS --project PROJECT_ID
|
|
24
24
|
mammoth view data get ORDERS_VIEW ORDERS_DS --project PROJECT_ID
|
|
25
|
+
# data.column_warnings: text columns of numbers/dates (with the convert-type fix) and blanks;
|
|
26
|
+
# plan step 3 from them
|
|
25
27
|
|
|
26
28
|
# 3. clean orders (each call waits for its job; read back after each value change)
|
|
27
29
|
mammoth view transform discard-duplicates ORDERS_VIEW --project PROJECT_ID \
|
|
@@ -43,9 +45,10 @@ mammoth view get ORDERS_VIEW ORDERS_DS --project PROJECT_ID # row_count before
|
|
|
43
45
|
# 5. join, then check the match rate before building on it
|
|
44
46
|
mammoth view transform join ORDERS_VIEW --project PROJECT_ID \
|
|
45
47
|
--input '{"dataset_id": ORDERS_DS, "foreign_view": CUSTOMERS_VIEW, "foreign_dataset_id": CUSTOMERS_DS, "join_type": "LEFT", "on": [{"left": "customer_id", "right": "customer_id"}], "select": ["region"]}'
|
|
46
|
-
|
|
47
|
-
# if
|
|
48
|
+
# data.join_check: rows_before/rows_after, match_rate, unmatched_rows, unmatched_keys; report them
|
|
49
|
+
# if many rows are unmatched, the key does not match: compare the two key columns' values
|
|
48
50
|
# (type, padding, case) with view data get on both views; do not summarise unmatched data
|
|
51
|
+
# rows_after > rows_before: a key repeats in the other view (use lookup for one value per key)
|
|
49
52
|
|
|
50
53
|
# 6. deliverable first: export the cleaned, joined rows before any step that replaces them
|
|
51
54
|
mammoth view export csv ORDERS_VIEW --project PROJECT_ID \
|
|
@@ -73,6 +73,41 @@ mammoth schema get view.transform.join
|
|
|
73
73
|
mammoth view transform join VIEW_ID --project PROJECT_ID --input INPUT_JSON
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
+
## What most pipelines look like
|
|
77
|
+
|
|
78
|
+
These patterns come from how Mammoth pipelines are usually built. Use them
|
|
79
|
+
as defaults, and let the user's request override them:
|
|
80
|
+
|
|
81
|
+
- Keep it short. Most pipelines have one to three steps and touch a few
|
|
82
|
+
columns. Add only the steps the deliverable needs.
|
|
83
|
+
- New column or overwrite? `set-values`, `math` and `lookup` take
|
|
84
|
+
`new_column` (add a column) or `existing_column` (replace the values in
|
|
85
|
+
place), never both. Overwriting is as common as adding. If the user said
|
|
86
|
+
"fix", "clean" or "change" a column, use `existing_column`. If they said
|
|
87
|
+
"add", "calculate" or "flag", use `new_column`. If it is not clear, ask.
|
|
88
|
+
- Joins are nearly always `LEFT` on one key column. Use `INNER`, `RIGHT`,
|
|
89
|
+
`OUTER` or a key of two or more columns only when the user asks for it or
|
|
90
|
+
the data needs it, and say why in your report.
|
|
91
|
+
- Check the key before a join or lookup. Most keys go in without a prep
|
|
92
|
+
step, so a type, case or padding difference shows up as unmatched rows. Read
|
|
93
|
+
both key columns first (`view data get`) and act on `join_check`.
|
|
94
|
+
- Date steps (`increment-date`, `extract-date`, and `text` on date columns)
|
|
95
|
+
fail more often than other steps. Before a date step, confirm that the
|
|
96
|
+
column type is `DATE` (`view get`); if it is `TEXT`, run `convert-type`
|
|
97
|
+
first. Check the result on a few rows.
|
|
98
|
+
- Convert several columns to the same type in one `convert-type` call (one
|
|
99
|
+
`conversions` entry for each column), not one call for each column.
|
|
100
|
+
- Remove duplicates near the end, after the cleanup and joins, so the check
|
|
101
|
+
uses the final columns.
|
|
102
|
+
- `filter` also takes a plain-language `prompt` instead of a `condition`.
|
|
103
|
+
Use a `condition` when the rule is exact (a column, an operator, a value).
|
|
104
|
+
Use `prompt` only when the user described the rule in words and no exact
|
|
105
|
+
condition expresses it, then check the kept rows.
|
|
106
|
+
- "Top N" means the largest values first. Use the smallest values first only
|
|
107
|
+
when the user says "bottom", "lowest" or "smallest".
|
|
108
|
+
- The last step of a pipeline is not a signal that it is finished. Say that
|
|
109
|
+
the work is done only after you verify the deliverable.
|
|
110
|
+
|
|
76
111
|
## Aggregate or summarise
|
|
77
112
|
|
|
78
113
|
For a grouped summary (totals per region, counts per status) use the typed
|
|
@@ -9,11 +9,13 @@ or secrets in an argument, prompt, transcript, or checkpoint.
|
|
|
9
9
|
from PyPI into a fresh environment and verify it:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
python3 -m venv .mammoth && .mammoth/bin/python -m pip install --upgrade mammoth-cli
|
|
12
|
+
python3 -m venv .mammoth && .mammoth/bin/python -m pip install --no-cache-dir --upgrade mammoth-cli
|
|
13
13
|
.mammoth/bin/mammoth --version # or: uv tool install mammoth-cli
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
Pin `mammoth-cli==X.Y.Z` when the task names an approved release
|
|
16
|
+
Pin `mammoth-cli==X.Y.Z` when the task names an approved release, and
|
|
17
|
+
check that `mammoth --version` prints it (a pip cache can serve an older
|
|
18
|
+
release for a few minutes after a new one is published). Use the
|
|
17
19
|
host installer script (`installers/mammoth-install.sh` in the repository)
|
|
18
20
|
only when the operator names it; do not pipe a remote script to a shell on
|
|
19
21
|
your own initiative. The SDK (`mammoth-io`) comes with the CLI. If a later
|
|
@@ -684,9 +684,11 @@ HANDLERS: dict[str, Handler] = {
|
|
|
684
684
|
"view.transform.lookup": view_ops_cmd.view_transform_lookup,
|
|
685
685
|
"view.transform.math": view_ops_cmd.view_transform_math,
|
|
686
686
|
"view.transform.pivot": view_ops_cmd.view_transform_pivot,
|
|
687
|
+
"view.transform.rename-columns": view_ops_cmd.view_transform_rename_columns,
|
|
687
688
|
"view.transform.replace": view_ops_cmd.view_transform_replace,
|
|
688
689
|
"view.transform.set-values": view_ops_cmd.view_transform_set_values,
|
|
689
690
|
"view.transform.small-large": view_ops_cmd.view_transform_small_large,
|
|
691
|
+
"view.transform.sort": view_ops_cmd.view_transform_sort,
|
|
690
692
|
"view.transform.split": view_ops_cmd.view_transform_split,
|
|
691
693
|
"view.transform.substring": view_ops_cmd.view_transform_substring,
|
|
692
694
|
"view.transform.text": view_ops_cmd.view_transform_text,
|
|
@@ -89,11 +89,11 @@ _COMMAND_DISCOVERY_PURPOSES = {
|
|
|
89
89
|
"view.transform.convert-type": (
|
|
90
90
|
"convert type cast numeric number text date column parse to number to date"
|
|
91
91
|
),
|
|
92
|
-
"view.transform.copy-columns": "copy duplicate
|
|
92
|
+
"view.transform.copy-columns": "copy duplicate column into a new column",
|
|
93
93
|
"view.transform.crosstab": (
|
|
94
94
|
"crosstab cross tab pivot table matrix rows by columns summary into a new dataset"
|
|
95
95
|
),
|
|
96
|
-
"view.transform.date-diff": "date difference days between two date columns age duration",
|
|
96
|
+
"view.transform.date-diff": "date dates difference days between two date columns age duration",
|
|
97
97
|
"view.transform.delete-columns": "delete drop remove columns",
|
|
98
98
|
"view.transform.discard-duplicates": (
|
|
99
99
|
"duplicate duplicates dedup dedupe deduplicate remove repeated rows unique distinct"
|
|
@@ -117,7 +117,7 @@ _COMMAND_DISCOVERY_PURPOSES = {
|
|
|
117
117
|
"second view views dataset datasets table tables vlookup"
|
|
118
118
|
),
|
|
119
119
|
"view.transform.json-extract": "json extract parse nested fields keys into columns",
|
|
120
|
-
"view.transform.limit-rows": "limit top bottom first last n rows
|
|
120
|
+
"view.transform.limit-rows": "limit top bottom first last n rows head",
|
|
121
121
|
"view.transform.lookup": (
|
|
122
122
|
"lookup look up vlookup reference table map code to name enrich one value "
|
|
123
123
|
"from another view dataset"
|
|
@@ -130,12 +130,19 @@ _COMMAND_DISCOVERY_PURPOSES = {
|
|
|
130
130
|
"pivot group by aggregate aggregation sum count average summary summarize "
|
|
131
131
|
"summarise per region total"
|
|
132
132
|
),
|
|
133
|
+
"view.transform.rename-columns": (
|
|
134
|
+
"rename column columns header headers relabel change column name names title"
|
|
135
|
+
),
|
|
133
136
|
"view.transform.replace": "find replace substitute text value in columns",
|
|
134
137
|
"view.transform.set-values": (
|
|
135
138
|
"set values assign overwrite blank empty default where condition label "
|
|
136
139
|
"category bucket flag if then conditional value"
|
|
137
140
|
),
|
|
138
141
|
"view.transform.small-large": "nth smallest largest value across columns",
|
|
142
|
+
"view.transform.sort": (
|
|
143
|
+
"sort sorting order rows by column ascending descending asc desc arrange "
|
|
144
|
+
"highest lowest newest oldest latest earliest date dates alphabetical"
|
|
145
|
+
),
|
|
139
146
|
"view.transform.split": "split column by delimiter separator into columns",
|
|
140
147
|
"view.transform.substring": "substring left right characters regex pattern extract part text",
|
|
141
148
|
"view.transform.text": (
|
|
@@ -404,7 +411,12 @@ def _tokens(value: str) -> frozenset[str]:
|
|
|
404
411
|
|
|
405
412
|
|
|
406
413
|
def _query_tokens(query: str) -> tuple[str, ...]:
|
|
407
|
-
|
|
414
|
+
# Bare numbers ("top 10") are values, not intent words.
|
|
415
|
+
return tuple(
|
|
416
|
+
token
|
|
417
|
+
for token in _tokens(query)
|
|
418
|
+
if token not in _DISCOVERY_STOPWORDS and not token.isdigit()
|
|
419
|
+
)
|
|
408
420
|
|
|
409
421
|
|
|
410
422
|
def _token_aliases(token: str) -> frozenset[str]:
|
|
@@ -46,6 +46,7 @@ from mammoth_cli.runtime.confirm import (
|
|
|
46
46
|
from mammoth_cli.runtime.invocation import Invocation
|
|
47
47
|
from mammoth_cli.runtime.session import open_service, require_project
|
|
48
48
|
from mammoth_cli.services.conditions import CONDITION_KWARG, compile_condition
|
|
49
|
+
from mammoth_cli.services.data_quality import column_warnings
|
|
49
50
|
|
|
50
51
|
HandlerResult = tuple[Any, dict[str, Any]]
|
|
51
52
|
|
|
@@ -252,10 +253,33 @@ BRIEF_VIEW_FIELDS: tuple[str, ...] = (
|
|
|
252
253
|
)
|
|
253
254
|
|
|
254
255
|
|
|
256
|
+
def apply_column_renames(record: Any) -> Any:
|
|
257
|
+
"""Show renamed columns under their new names in a dataview record.
|
|
258
|
+
|
|
259
|
+
A rename (``view transform rename-columns`` or the web grid) is stored in
|
|
260
|
+
``display_properties.COLUMN_NAMES`` as ``{internal_name: name}``; the
|
|
261
|
+
server's ``metadata`` keeps the name the pipeline produced. Every CLI
|
|
262
|
+
output uses the name the user sees, so the rename wins.
|
|
263
|
+
"""
|
|
264
|
+
if not isinstance(record, dict):
|
|
265
|
+
return record
|
|
266
|
+
display = record.get("display_properties")
|
|
267
|
+
renames = display.get("COLUMN_NAMES") if isinstance(display, dict) else None
|
|
268
|
+
metadata = record.get(_METADATA_KEY)
|
|
269
|
+
if not isinstance(renames, dict) or not renames or not isinstance(metadata, list):
|
|
270
|
+
return record
|
|
271
|
+
columns = []
|
|
272
|
+
for column in metadata:
|
|
273
|
+
new_name = renames.get(column.get(_INTERNAL_NAME_KEY)) if isinstance(column, dict) else None
|
|
274
|
+
columns.append({**column, _DISPLAY_NAME_KEY: new_name} if new_name else column)
|
|
275
|
+
return {**record, _METADATA_KEY: columns}
|
|
276
|
+
|
|
277
|
+
|
|
255
278
|
def brief_view_record(record: Any) -> Any:
|
|
256
|
-
"""Keep only :data:`BRIEF_VIEW_FIELDS` of a dataview record."""
|
|
279
|
+
"""Keep only :data:`BRIEF_VIEW_FIELDS` of a dataview record, renames applied."""
|
|
257
280
|
if not isinstance(record, dict):
|
|
258
281
|
return record
|
|
282
|
+
record = apply_column_renames(record)
|
|
259
283
|
return {key: record[key] for key in BRIEF_VIEW_FIELDS if key in record}
|
|
260
284
|
|
|
261
285
|
|
|
@@ -369,6 +393,7 @@ def _dataview_metadata(
|
|
|
369
393
|
)
|
|
370
394
|
except Exception: # noqa: BLE001 -- labels are a presentation nicety, never fatal
|
|
371
395
|
return []
|
|
396
|
+
info = apply_column_renames(info)
|
|
372
397
|
metadata = info.get(_METADATA_KEY) if isinstance(info, dict) else None
|
|
373
398
|
if not isinstance(metadata, list):
|
|
374
399
|
return []
|
|
@@ -400,7 +425,7 @@ def _compile_query_filters(
|
|
|
400
425
|
project_id: int | None,
|
|
401
426
|
document: dict[str, Any],
|
|
402
427
|
kwargs: dict[str, Any],
|
|
403
|
-
) -> dict[str, str] | None:
|
|
428
|
+
) -> tuple[dict[str, str] | None, dict[str, str] | None]:
|
|
404
429
|
"""Translate a data query's ``condition`` and ``columns`` to the wire format.
|
|
405
430
|
|
|
406
431
|
The data route takes the backend condition shape (``{internal: {OP: ...}}``,
|
|
@@ -409,11 +434,11 @@ def _compile_query_filters(
|
|
|
409
434
|
only have one key". The spec is compiled through the shared condition
|
|
410
435
|
service and built against the view's display -> internal name and type
|
|
411
436
|
maps, and ``columns`` given as display names are mapped the same way.
|
|
412
|
-
Returns the internal -> display map
|
|
413
|
-
relabelling can reuse
|
|
437
|
+
Returns the internal -> display map and the display -> type map when
|
|
438
|
+
metadata was fetched, so the row relabelling and checks can reuse them.
|
|
414
439
|
"""
|
|
415
440
|
if CONDITION_KWARG not in document and "columns" not in document:
|
|
416
|
-
return None
|
|
441
|
+
return None, None
|
|
417
442
|
metadata = _dataview_metadata(service, dataset_id, dataview_id, project_id)
|
|
418
443
|
column_map: dict[str, str] = {}
|
|
419
444
|
column_types: dict[str, str] = {}
|
|
@@ -430,7 +455,9 @@ def _compile_query_filters(
|
|
|
430
455
|
columns = document.get("columns")
|
|
431
456
|
if isinstance(columns, list):
|
|
432
457
|
kwargs["columns"] = [column_map.get(c, c) if isinstance(c, str) else c for c in columns]
|
|
433
|
-
|
|
458
|
+
if not metadata:
|
|
459
|
+
return None, None
|
|
460
|
+
return {internal: display for display, internal in column_map.items()}, column_types
|
|
434
461
|
|
|
435
462
|
|
|
436
463
|
def _relabel_columns(
|
|
@@ -586,11 +613,14 @@ def view_data_get(invocation: Invocation) -> HandlerResult:
|
|
|
586
613
|
"""Fetch a dataview's data, waiting for the backing job to complete.
|
|
587
614
|
|
|
588
615
|
The dataset is resolved from the view unless given as a trailing positional
|
|
589
|
-
or a ``dataset_id`` --input field.
|
|
616
|
+
or a ``dataset_id`` --input field. ``offset`` (1-based) reads a later page
|
|
617
|
+
through the query route. The result carries ``column_warnings`` when the
|
|
618
|
+
rows show a text column of numbers or dates, or blanks.
|
|
590
619
|
"""
|
|
591
620
|
project_id = require_project(invocation)
|
|
592
621
|
view_id = _require_int_positional_at(invocation, 0, "view id")
|
|
593
622
|
document = invocation.load_input() or {}
|
|
623
|
+
limit = document.get("limit", _DATA_GET_DEFAULT_LIMIT)
|
|
594
624
|
with open_service(invocation) as (service, auth):
|
|
595
625
|
dataset_id = _resolve_dataset_id(service, invocation, view_id, document)
|
|
596
626
|
kwargs: dict[str, Any] = {
|
|
@@ -598,12 +628,165 @@ def view_data_get(invocation: Invocation) -> HandlerResult:
|
|
|
598
628
|
"dataview_id": view_id,
|
|
599
629
|
"project_id": project_id,
|
|
600
630
|
}
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
631
|
+
if document.get("offset") is not None:
|
|
632
|
+
kwargs["offset"] = int(document["offset"])
|
|
633
|
+
kwargs["limit"] = int(limit) if int(limit) > 0 else 400
|
|
634
|
+
_forward_optional(document, kwargs, ("sequence",))
|
|
635
|
+
data = service.call(_QUERY_DATA_SYMBOL, **kwargs)
|
|
636
|
+
else:
|
|
637
|
+
_forward_optional(document, kwargs, ("timeout", "poll_interval", "sequence"))
|
|
638
|
+
data = service.call(_symbol(invocation), **kwargs)
|
|
639
|
+
data = _relabel_and_check(service, dataset_id, view_id, project_id, data)
|
|
640
|
+
return _trim_rows(data, limit), _meta(invocation, auth.workspace_id, project_id)
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
_QUERY_DATA_SYMBOL = "mammoth.api.dataviews.DataviewsAPI.query_data"
|
|
644
|
+
|
|
645
|
+
_DATA_PAGE_SYMBOL = "mammoth.api.dataviews.DataviewsAPI.get_data"
|
|
646
|
+
_MAX_UNMATCHED_KEYS = 5
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
def join_snapshot(
|
|
650
|
+
service: Any, dataset_id: int, dataview_id: int, project_id: int | None
|
|
651
|
+
) -> dict[str, Any]:
|
|
652
|
+
"""Row count, columns and the first data page of a view (best effort)."""
|
|
653
|
+
snapshot: dict[str, Any] = {"row_count": None, "columns": {}, "rows": []}
|
|
654
|
+
try:
|
|
655
|
+
info = apply_column_renames(
|
|
656
|
+
service.call(
|
|
657
|
+
_DATAVIEW_GET_SYMBOL,
|
|
658
|
+
dataset_id=dataset_id,
|
|
659
|
+
dataview_id=dataview_id,
|
|
660
|
+
project_id=project_id,
|
|
661
|
+
)
|
|
662
|
+
)
|
|
663
|
+
if isinstance(info, dict):
|
|
664
|
+
snapshot["row_count"] = info.get("row_count")
|
|
665
|
+
snapshot["columns"] = {
|
|
666
|
+
c.get(_INTERNAL_NAME_KEY): c.get(_DISPLAY_NAME_KEY)
|
|
667
|
+
for c in info.get(_METADATA_KEY) or []
|
|
668
|
+
if isinstance(c, dict)
|
|
669
|
+
}
|
|
670
|
+
page = service.call(
|
|
671
|
+
_DATA_PAGE_SYMBOL,
|
|
672
|
+
dataset_id=dataset_id,
|
|
673
|
+
dataview_id=dataview_id,
|
|
674
|
+
project_id=project_id,
|
|
675
|
+
)
|
|
676
|
+
page = _relabel_columns(
|
|
677
|
+
service, dataset_id, dataview_id, project_id, page, snapshot["columns"]
|
|
678
|
+
)
|
|
679
|
+
rows = page.get(_ROWS_KEY) if isinstance(page, dict) else None
|
|
680
|
+
snapshot["rows"] = [r for r in rows or [] if isinstance(r, dict)]
|
|
681
|
+
except Exception: # noqa: BLE001 -- the check is advice; the join already ran
|
|
682
|
+
return snapshot
|
|
683
|
+
return snapshot
|
|
684
|
+
|
|
685
|
+
|
|
686
|
+
def with_join_check(data: Any, before: Any, after: dict[str, Any], document: dict[str, Any]) -> Any:
|
|
687
|
+
"""Add ``join_check`` (row counts, columns added, match rate) to a join result.
|
|
688
|
+
|
|
689
|
+
``unmatched_rows`` counts rows where every added column is blank: for a
|
|
690
|
+
LEFT join these are rows whose key found no match in the other view.
|
|
691
|
+
"""
|
|
692
|
+
if not isinstance(data, dict) or not isinstance(before, dict):
|
|
693
|
+
return data
|
|
694
|
+
added = [
|
|
695
|
+
name
|
|
696
|
+
for internal, name in after.get("columns", {}).items()
|
|
697
|
+
if internal not in before.get("columns", {}) and isinstance(name, str)
|
|
698
|
+
]
|
|
699
|
+
rows = after.get("rows") or []
|
|
700
|
+
check: dict[str, Any] = {
|
|
701
|
+
"rows_before": before.get("row_count"),
|
|
702
|
+
"rows_after": after.get("row_count"),
|
|
703
|
+
"columns_added": added,
|
|
704
|
+
"rows_checked": len(rows),
|
|
705
|
+
}
|
|
706
|
+
notes: list[str] = []
|
|
707
|
+
on = document.get("on")
|
|
708
|
+
left_key = None
|
|
709
|
+
if isinstance(on, list) and on and isinstance(on[0], dict):
|
|
710
|
+
left_key = on[0].get("left")
|
|
711
|
+
if added and rows:
|
|
712
|
+
unmatched = [r for r in rows if all(r.get(c) in (None, "") for c in added)]
|
|
713
|
+
check["unmatched_rows"] = len(unmatched)
|
|
714
|
+
check["match_rate"] = round((len(rows) - len(unmatched)) / len(rows), 3)
|
|
715
|
+
if unmatched:
|
|
716
|
+
keys = sorted({str(r.get(left_key)) for r in unmatched if left_key in r})
|
|
717
|
+
check["unmatched_keys"] = keys[:_MAX_UNMATCHED_KEYS]
|
|
718
|
+
notes.append(
|
|
719
|
+
f"{len(unmatched)} of {len(rows)} rows found no match. If that is more "
|
|
720
|
+
"than a few, compare the key columns in both views (type, case, "
|
|
721
|
+
"padding) before you build on this; otherwise say so in your report."
|
|
722
|
+
)
|
|
723
|
+
before_n, after_n = check["rows_before"], check["rows_after"]
|
|
724
|
+
if isinstance(before_n, int) and isinstance(after_n, int):
|
|
725
|
+
if after_n > before_n:
|
|
726
|
+
notes.append(
|
|
727
|
+
f"The join added {after_n - before_n} rows: a key repeats in the other "
|
|
728
|
+
"view, so matching rows repeat. Totals over this view count them twice; "
|
|
729
|
+
"use view transform lookup for one value per key."
|
|
730
|
+
)
|
|
731
|
+
elif after_n < before_n:
|
|
732
|
+
notes.append(
|
|
733
|
+
f"{before_n - after_n} rows had no match and were dropped "
|
|
734
|
+
"(an INNER join keeps matched rows only)."
|
|
735
|
+
)
|
|
736
|
+
if isinstance(after_n, int) and len(rows) < after_n:
|
|
737
|
+
notes.append(f"Match rate is from the first {len(rows)} rows of {after_n}.")
|
|
738
|
+
if notes:
|
|
739
|
+
check["notes"] = notes
|
|
740
|
+
return {**data, "join_check": check}
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
def _column_profile(
|
|
744
|
+
service: Any, dataset_id: int, dataview_id: int, project_id: int | None
|
|
745
|
+
) -> tuple[dict[str, str], dict[str, str]]:
|
|
746
|
+
"""One metadata read: internal-to-display names, and display name to type."""
|
|
747
|
+
mapping: dict[str, str] = {}
|
|
748
|
+
types: dict[str, str] = {}
|
|
749
|
+
for column in _dataview_metadata(service, dataset_id, dataview_id, project_id):
|
|
750
|
+
internal = column.get(_INTERNAL_NAME_KEY)
|
|
751
|
+
display = column.get(_DISPLAY_NAME_KEY)
|
|
752
|
+
if isinstance(internal, str) and isinstance(display, str):
|
|
753
|
+
mapping[internal] = display
|
|
754
|
+
types[display] = str(column.get("type") or "")
|
|
755
|
+
return mapping, types
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
def _relabel_and_check(
|
|
759
|
+
service: Any,
|
|
760
|
+
dataset_id: int,
|
|
761
|
+
view_id: int,
|
|
762
|
+
project_id: int | None,
|
|
763
|
+
data: Any,
|
|
764
|
+
mapping: dict[str, str] | None = None,
|
|
765
|
+
types: dict[str, str] | None = None,
|
|
766
|
+
) -> Any:
|
|
767
|
+
"""Relabel a data page to display names and add ``column_warnings``.
|
|
768
|
+
|
|
769
|
+
The metadata read happens only when the page has rows and the caller has
|
|
770
|
+
not read it already (one read serves both the names and the types).
|
|
771
|
+
"""
|
|
772
|
+
rows = data.get(_ROWS_KEY) if isinstance(data, dict) else None
|
|
773
|
+
if not isinstance(rows, list) or not rows:
|
|
774
|
+
return _relabel_columns(service, dataset_id, view_id, project_id, data, mapping)
|
|
775
|
+
if mapping is None or types is None:
|
|
776
|
+
mapping, types = _column_profile(service, dataset_id, view_id, project_id)
|
|
777
|
+
data = _relabel_columns(service, dataset_id, view_id, project_id, data, mapping)
|
|
778
|
+
return _with_column_warnings(data, types, view_id)
|
|
779
|
+
|
|
780
|
+
|
|
781
|
+
def _with_column_warnings(data: Any, types: dict[str, str], view_id: int) -> Any:
|
|
782
|
+
"""Add ``column_warnings`` for the rows of a data page (never fatal)."""
|
|
783
|
+
if not isinstance(data, dict) or not isinstance(data.get(_ROWS_KEY), list) or not types:
|
|
784
|
+
return data
|
|
785
|
+
try:
|
|
786
|
+
warnings = column_warnings(data[_ROWS_KEY], types, view_id)
|
|
787
|
+
except Exception: # noqa: BLE001 -- a presentation aid must not fail the read
|
|
788
|
+
return data
|
|
789
|
+
return {**data, "column_warnings": warnings} if warnings else data
|
|
607
790
|
|
|
608
791
|
|
|
609
792
|
#: Rows a plain ``view data get`` returns unless ``limit`` says otherwise.
|
|
@@ -653,9 +836,11 @@ def view_data_query(invocation: Invocation) -> HandlerResult:
|
|
|
653
836
|
"project_id": project_id,
|
|
654
837
|
}
|
|
655
838
|
_forward_optional(document, kwargs, ("sequence", "offset", "limit", "sort"))
|
|
656
|
-
mapping = _compile_query_filters(
|
|
839
|
+
mapping, types = _compile_query_filters(
|
|
840
|
+
service, dataset_id, view_id, project_id, document, kwargs
|
|
841
|
+
)
|
|
657
842
|
data = service.call(_symbol(invocation), **kwargs)
|
|
658
|
-
data =
|
|
843
|
+
data = _relabel_and_check(service, dataset_id, view_id, project_id, data, mapping, types)
|
|
659
844
|
return data, _meta(invocation, auth.workspace_id, project_id)
|
|
660
845
|
|
|
661
846
|
|