mammoth-cli 2.0.80__tar.gz → 2.0.82__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.
Files changed (234) hide show
  1. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/PKG-INFO +1 -1
  2. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/__init__.py +1 -1
  3. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/connector.md +2 -0
  4. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/scheduling.md +37 -0
  5. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/connector.py +41 -1
  6. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/runtime/verify.py +146 -4
  7. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/services/data_quality.py +57 -13
  8. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/pyproject.toml +1 -1
  9. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/.gitignore +0 -0
  10. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/LICENSE +0 -0
  11. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/README.md +0 -0
  12. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/__main__.py +0 -0
  13. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/app.py +0 -0
  14. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/SKILL.md +0 -0
  15. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/about-mammoth.md +0 -0
  16. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/auth.md +0 -0
  17. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities-misc.md +0 -0
  18. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/capabilities.md +0 -0
  19. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/command-index.md +0 -0
  20. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/activity.md +0 -0
  21. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/addon.md +0 -0
  22. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/agent.md +0 -0
  23. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/ai.md +0 -0
  24. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/annotation.md +0 -0
  25. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/auth.md +0 -0
  26. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/automation.md +0 -0
  27. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/batch.md +0 -0
  28. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/billing.md +0 -0
  29. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/browse.md +0 -0
  30. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/calc.md +0 -0
  31. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/capability.md +0 -0
  32. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/client-app.md +0 -0
  33. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/completion.md +0 -0
  34. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/config.md +0 -0
  35. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/context.md +0 -0
  36. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard-qa.md +0 -0
  37. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dashboard.md +0 -0
  38. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/data-app.md +0 -0
  39. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/dataset.md +0 -0
  40. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/doctor.md +0 -0
  41. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/external-key.md +0 -0
  42. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/file.md +0 -0
  43. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/folder.md +0 -0
  44. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/job.md +0 -0
  45. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/log.md +0 -0
  46. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/notification.md +0 -0
  47. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/parameter.md +0 -0
  48. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/project.md +0 -0
  49. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/report.md +0 -0
  50. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schedule.md +0 -0
  51. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/schema.md +0 -0
  52. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/skill.md +0 -0
  53. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/snippet.md +0 -0
  54. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/support.md +0 -0
  55. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/template.md +0 -0
  56. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/trash.md +0 -0
  57. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/upgrade.md +0 -0
  58. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/user.md +0 -0
  59. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/version.md +0 -0
  60. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/view-transform.md +0 -0
  61. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/view.md +0 -0
  62. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/webhook.md +0 -0
  63. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workflow.md +0 -0
  64. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/commands/workspace.md +0 -0
  65. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/handoff.md +0 -0
  66. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/input.md +0 -0
  67. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/jobs-drafts.md +0 -0
  68. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/machine-output.md +0 -0
  69. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/operations.md +0 -0
  70. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/auth-scope.md +0 -0
  71. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/cleanup.md +0 -0
  72. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/dashboards.md +0 -0
  73. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/end-to-end.md +0 -0
  74. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/exports.md +0 -0
  75. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/index.md +0 -0
  76. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/need-action.md +0 -0
  77. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/resources.md +0 -0
  78. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/transforms.md +0 -0
  79. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/recipes/typed-etl-discovery.md +0 -0
  80. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/recovery.md +0 -0
  81. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/report-checklist.md +0 -0
  82. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/retention.md +0 -0
  83. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/safety.md +0 -0
  84. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/bundled_skill/mammoth-cli/references/task-start.md +0 -0
  85. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/__init__.py +0 -0
  86. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/activity.py +0 -0
  87. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/addon.py +0 -0
  88. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/agent.py +0 -0
  89. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/ai.py +0 -0
  90. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/annotation.py +0 -0
  91. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/auth.py +0 -0
  92. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/automation.py +0 -0
  93. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/batch.py +0 -0
  94. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/billing.py +0 -0
  95. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/browse.py +0 -0
  96. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/calc.py +0 -0
  97. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/capability.py +0 -0
  98. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/client_app.py +0 -0
  99. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/completion.py +0 -0
  100. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/config.py +0 -0
  101. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/context.py +0 -0
  102. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/dashboard.py +0 -0
  103. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/data_app.py +0 -0
  104. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/dataset.py +0 -0
  105. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/doctor.py +0 -0
  106. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/external_key.py +0 -0
  107. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/file.py +0 -0
  108. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/folder.py +0 -0
  109. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/job.py +0 -0
  110. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/notification.py +0 -0
  111. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/parameter.py +0 -0
  112. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/project.py +0 -0
  113. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/registry.py +0 -0
  114. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/report.py +0 -0
  115. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/schedule.py +0 -0
  116. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/schema.py +0 -0
  117. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/skill.py +0 -0
  118. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/snippet.py +0 -0
  119. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/support.py +0 -0
  120. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/template.py +0 -0
  121. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/trash.py +0 -0
  122. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/upgrade.py +0 -0
  123. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/user.py +0 -0
  124. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/view.py +0 -0
  125. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/view_ops.py +0 -0
  126. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/webhook.py +0 -0
  127. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/workflow.py +0 -0
  128. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/commands/workspace.py +0 -0
  129. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/context/__init__.py +0 -0
  130. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/context/credentials.py +0 -0
  131. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/context/endpoint.py +0 -0
  132. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/context/profiles.py +0 -0
  133. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/context/resolver.py +0 -0
  134. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/contracts/__init__.py +0 -0
  135. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/contracts/auth.py +0 -0
  136. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/embed.py +0 -0
  137. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/errors/__init__.py +0 -0
  138. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/errors/envelope.py +0 -0
  139. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/manifest/__init__.py +0 -0
  140. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/manifest/loader.py +0 -0
  141. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/messages/__init__.py +0 -0
  142. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/output/__init__.py +0 -0
  143. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/output/envelope.py +0 -0
  144. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/output/normalize.py +0 -0
  145. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/output/policy.py +0 -0
  146. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/output/progress.py +0 -0
  147. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/output/render.py +0 -0
  148. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/py.typed +0 -0
  149. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/runtime/__init__.py +0 -0
  150. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/runtime/confirm.py +0 -0
  151. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/runtime/dryrun.py +0 -0
  152. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/runtime/embedded.py +0 -0
  153. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/runtime/executor.py +0 -0
  154. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/runtime/input_loader.py +0 -0
  155. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/runtime/invocation.py +0 -0
  156. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/runtime/options.py +0 -0
  157. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/runtime/parents.py +0 -0
  158. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/runtime/runlog.py +0 -0
  159. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/runtime/session.py +0 -0
  160. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/runtime/state.py +0 -0
  161. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/runtime/strict.py +0 -0
  162. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/runtime/updates.py +0 -0
  163. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/runtime/validate.py +0 -0
  164. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/services/__init__.py +0 -0
  165. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/services/argspec.py +0 -0
  166. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/services/coerce.py +0 -0
  167. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/services/command_contract.py +0 -0
  168. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/services/conditions.py +0 -0
  169. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/services/dashboard_pages.py +0 -0
  170. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/services/dashboard_review.py +0 -0
  171. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/services/dispatch.py +0 -0
  172. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/services/factory.py +0 -0
  173. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/services/input_fields.py +0 -0
  174. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/services/mapping.py +0 -0
  175. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/services/openapi_types.py +0 -0
  176. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/services/positionals.py +0 -0
  177. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/services/protocol.py +0 -0
  178. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/services/sdk_service.py +0 -0
  179. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/services/testing.py +0 -0
  180. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/services/type_system.py +0 -0
  181. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/skills/__init__.py +0 -0
  182. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/skills/installer.py +0 -0
  183. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/skills/steering.py +0 -0
  184. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/mammoth_cli/testing.py +0 -0
  185. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/activity.yaml +0 -0
  186. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/addon.yaml +0 -0
  187. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/agent.yaml +0 -0
  188. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/ai.yaml +0 -0
  189. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/annotation.yaml +0 -0
  190. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/auth.yaml +0 -0
  191. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/automation.yaml +0 -0
  192. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/batch.yaml +0 -0
  193. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/billing.yaml +0 -0
  194. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/browse.yaml +0 -0
  195. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/calc.yaml +0 -0
  196. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/capability.yaml +0 -0
  197. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/client-app.yaml +0 -0
  198. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/completion.yaml +0 -0
  199. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/config.yaml +0 -0
  200. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/connector.yaml +0 -0
  201. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/context.yaml +0 -0
  202. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/dashboard.yaml +0 -0
  203. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/data-app.yaml +0 -0
  204. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/dataset.yaml +0 -0
  205. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/doctor.yaml +0 -0
  206. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/external-key.yaml +0 -0
  207. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/file.yaml +0 -0
  208. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/folder.yaml +0 -0
  209. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/job.yaml +0 -0
  210. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/log.yaml +0 -0
  211. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/notification.yaml +0 -0
  212. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/parameter.yaml +0 -0
  213. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/project.yaml +0 -0
  214. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/report.yaml +0 -0
  215. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/schedule.yaml +0 -0
  216. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/schema.yaml +0 -0
  217. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/skill.yaml +0 -0
  218. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/snippet.yaml +0 -0
  219. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/support.yaml +0 -0
  220. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/template.yaml +0 -0
  221. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/trash.yaml +0 -0
  222. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/upgrade.yaml +0 -0
  223. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/user.yaml +0 -0
  224. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/version.yaml +0 -0
  225. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/view.yaml +0 -0
  226. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/webhook.yaml +0 -0
  227. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/workflow.yaml +0 -0
  228. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/commands/workspace.yaml +0 -0
  229. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/openapi-operations.yaml +0 -0
  230. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/schema-v1.json +0 -0
  231. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/sdk-catalog.source.yaml +0 -0
  232. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/manifests/sdk-methods.yaml +0 -0
  233. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/spec/openapi/metadata.json +0 -0
  234. {mammoth_cli-2.0.80 → mammoth_cli-2.0.82}/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.80
3
+ Version: 2.0.82
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
@@ -6,7 +6,7 @@ not implement a second HTTP client and does not call private SDK members.
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
- __version__ = "2.0.80"
9
+ __version__ = "2.0.82"
10
10
 
11
11
  # The versioned machine output envelope contract.
12
12
  SCHEMA_VERSION = 1
@@ -200,6 +200,8 @@ Example: `mammoth connector list`. Placeholders are illustrative; resolve IDs an
200
200
 
201
201
  Result: `ConnectorListResult`; mutation `read`, confirmation `none`, wait policy `not_async`.
202
202
 
203
+ `is_premium: true` with `is_added: false` means the connector must be enabled by Mammoth sales before this workspace can use it -- not that nobody has set it up yet. Such an item also carries `availability: "premium_not_enabled"` and an `availability_note` saying so. Tell the user why (premium, not enabled here) and offer to contact Mammoth sales; there is no CLI command that enables a premium connector or contacts sales on the user's behalf.
204
+
203
205
  Status on release: ran once on CLI 2.0.18 — fixture-lifecycle sweep 2026-09-19: exit 0 on release with CLI 2.0.18. Listed 42 available connectors (name_key, disp_name, api_type, is_added, is_premium). Single invocation only.
204
206
 
205
207
  ### `connector.query.generate`
@@ -47,6 +47,43 @@ mammoth automation create 'Nightly refresh' --yes --input '{
47
47
  from an uploaded file or a URL (`weburl`) is a one-time copy with no source
48
48
  details to refresh from — say so rather than scheduling one.
49
49
 
50
+ That is not the same as "this dataset can never be recurring." A
51
+ file-backed dataset's pipeline re-runs on new data exactly like any other
52
+ dataset's ([how Mammoth organises
53
+ data](../about-mammoth.md#how-mammoth-organises-data)); the only difference
54
+ is that nothing pulls the next file in for you — each new batch has to be
55
+ uploaded with `append_to_ds_id` rather than fetched automatically. Once a
56
+ new file lands that way, every view on that dataset recomputes over it
57
+ automatically, so a monthly "email this view as CSV" delivery is buildable
58
+ today, with no connector:
59
+
60
+ ```bash
61
+ # each month, once the new file is ready (a person or an outside script runs this):
62
+ mammoth file upload ./brand_spend_2026_10.csv --input '{"append_to_ds_id": DATASET_ID}'
63
+ # one-time setup: the recurring delivery itself, via send_an_alert
64
+ mammoth automation create 'Monthly brand spend to client' --yes --input '{
65
+ "tasks": [
66
+ {"task_type": "send_an_alert", "details": {
67
+ "alert_type": "email", "recipients": ["client@example.com"],
68
+ "subject": "Monthly brand spend report",
69
+ "attachments": {"dataview_ids": [VIEW_ID]}
70
+ }}
71
+ ],
72
+ "conditions": [
73
+ {"condition_type": "at_specific_time", "details": {
74
+ "frequency": "monthly", "interval": 1, "start_at": "2026-01-01T02:00:00Z"
75
+ }}
76
+ ]
77
+ }'
78
+ ```
79
+
80
+ `send_an_alert`'s CSV attachment is exported from the view's prepared rows
81
+ at the moment the automation fires, not a copy taken at creation time (every
82
+ output in Mammoth is computed from prepared data, never cached — see
83
+ [about-mammoth.md](../about-mammoth.md)), so once this automation exists it
84
+ delivers whatever the view currently holds each month; only the file-upload
85
+ step above still needs to happen before each run.
86
+
50
87
  The other three task types take the shapes documented in `schema get
51
88
  automation.create` under `tasks[].details`:
52
89
 
@@ -145,11 +145,51 @@ def connector_get(invocation: Invocation) -> HandlerResult:
145
145
  return data, _meta(invocation, auth.workspace_id, resolved_project(invocation))
146
146
 
147
147
 
148
+ #: ``availability`` a premium connector gets when it is not yet added to the
149
+ #: workspace -- distinct from an ordinary connector nobody has added yet.
150
+ _PREMIUM_NOT_ENABLED = "premium_not_enabled"
151
+
152
+
153
+ _PREMIUM_NOT_ENABLED_NOTE = (
154
+ "Premium connector, not enabled in this workspace: Mammoth sales must enable"
155
+ " it before it can be connected. Tell the user so and offer to contact sales."
156
+ )
157
+
158
+
159
+ def _with_premium_availability(data: Any) -> Any:
160
+ """Mark each premium, not-yet-added connector with why it cannot be connected.
161
+
162
+ ``is_premium``/``is_added`` alone said a connector could not be connected
163
+ but never why: a premium connector must be enabled by Mammoth sales
164
+ before this workspace can use it, unlike an ordinary connector nobody has
165
+ added yet. Without this, an agent that reads ``connector list`` can route
166
+ a user to sales but never explain why (T2-WPP-W7). ``ConnectorsAPI.list``
167
+ returns a list, which stays a list.
168
+ """
169
+ if not isinstance(data, list):
170
+ return data
171
+ return [
172
+ (
173
+ {
174
+ **item,
175
+ "availability": _PREMIUM_NOT_ENABLED,
176
+ "availability_note": _PREMIUM_NOT_ENABLED_NOTE,
177
+ }
178
+ if isinstance(item, dict) and item.get("is_premium") and not item.get("is_added")
179
+ else item
180
+ )
181
+ for item in data
182
+ ]
183
+
184
+
148
185
  def connector_list(invocation: Invocation) -> HandlerResult:
149
186
  """List all available connectors (workspace-scoped, no project)."""
150
187
  with open_service(invocation) as (service, auth):
151
188
  data = service.call(_symbol(invocation))
152
- return data, _meta(invocation, auth.workspace_id, resolved_project(invocation))
189
+ return (
190
+ _with_premium_availability(data),
191
+ _meta(invocation, auth.workspace_id, resolved_project(invocation)),
192
+ )
153
193
 
154
194
 
155
195
  def connector_ai_chat(invocation: Invocation) -> HandlerResult:
@@ -10,15 +10,21 @@ what it should" instead of re-deriving it per command.
10
10
 
11
11
  from __future__ import annotations
12
12
 
13
- from typing import TYPE_CHECKING, Any
13
+ from typing import Any
14
14
 
15
- if TYPE_CHECKING:
16
- from mammoth_cli.runtime.invocation import Invocation
15
+ from mammoth_cli.runtime.invocation import Invocation
17
16
 
18
17
  #: Below this share of matched rows, a join has enough misses to flag before
19
18
  #: the caller builds anything further on it.
20
19
  JOIN_MATCH_RATE_THRESHOLD = 0.8
21
20
 
21
+ #: The one ``mutation_class`` (see ``spec/manifests/commands/view.yaml``) a
22
+ #: view write can carry that runs a pipeline -- the only kind that can leave a
23
+ #: downstream export referencing something the write just changed or removed.
24
+ _VIEW_PIPELINE_MUTATION_CLASS = "reversible_pipeline"
25
+
26
+ _VIEW_EXPORT_LIST_COMMAND = "view.export.list"
27
+
22
28
  _FAILURE_STATUSES = frozenset({"error", "failed", "failure"})
23
29
  _FAILURE_PIPELINE_STATES = frozenset({"error", "ref_error"})
24
30
 
@@ -83,6 +89,7 @@ def with_verify(data: Any, invocation: Invocation | None = None) -> Any:
83
89
  verify["needs_user"] = _needs_user(
84
90
  data, verified=verified, rows_before=rows_before, rows_after=rows_after
85
91
  )
92
+ _apply_downstream_export_check(verify, invocation)
86
93
  return {**data, "verify": verify}
87
94
 
88
95
 
@@ -270,7 +277,10 @@ def _needs_user(
270
277
  ``needs_user`` means "a serious outcome the user must hear about before
271
278
  anything is built on it" -- never "something went wrong that you can
272
279
  retry". A failed write is reported through ``verified``/``reason``
273
- instead (see :func:`_verify_and_reason`); it never sets this.
280
+ instead (see :func:`_verify_and_reason`); it never sets this -- except a
281
+ downstream export broken by this very write (see
282
+ :func:`_apply_downstream_export_check`), which is serious enough to set
283
+ both.
274
284
  """
275
285
  if not verified:
276
286
  return None
@@ -285,3 +295,135 @@ def _needs_user(
285
295
  "confirm before building on it."
286
296
  )
287
297
  return None
298
+
299
+
300
+ # ---------------------------------------------------------------------------
301
+ # A pipeline write can succeed on the view itself while leaving a saved
302
+ # export broken -- its target_properties still reference a column the write
303
+ # just deleted or renamed. The write's own response never carries that; only
304
+ # a fresh read of the view's exports does (T2-WPP-W2: `view export dataset`
305
+ # then `view transform delete-columns` left the export in error_info 7001,
306
+ # but the delete's own verify said verified: true with no warnings).
307
+ # ---------------------------------------------------------------------------
308
+
309
+
310
+ def _apply_downstream_export_check(verify: dict[str, Any], invocation: Invocation | None) -> None:
311
+ """Flag a view-pipeline write that left one of its exports in error.
312
+
313
+ Runs at most once per write, and only when the write's own signals
314
+ already say a clean, settled success -- a write already reported
315
+ unverified for its own reason spends no extra read here.
316
+ """
317
+ if invocation is None or not verify["verified"] or verify["reason"] is not None:
318
+ return
319
+ view_id = _pipeline_view_id(invocation)
320
+ if view_id is None:
321
+ return
322
+ broken = _broken_downstream_exports(invocation, view_id)
323
+ if isinstance(broken, str):
324
+ verify["warnings"] = [*verify["warnings"], broken]
325
+ return
326
+ if not broken:
327
+ return
328
+ details = [_export_error_detail(item) for item in broken]
329
+ verify["verified"] = False
330
+ verify["reason"] = "a saved export on this view is in error: " + "; ".join(details)
331
+ verify["warnings"] = [*verify["warnings"], *details]
332
+ verify["needs_user"] = (
333
+ "A saved export on this view is in error after this change; its data will "
334
+ "not reach its destination until this is fixed: " + "; ".join(details)
335
+ )
336
+
337
+
338
+ def _pipeline_view_id(invocation: Invocation) -> int | None:
339
+ """The view id a ``reversible_pipeline`` write acted on, or None otherwise."""
340
+ from mammoth_cli.manifest.loader import command_by_id
341
+
342
+ record = command_by_id(invocation.command_id) or {}
343
+ if record.get("mutation_class") != _VIEW_PIPELINE_MUTATION_CLASS:
344
+ return None
345
+ for name in ("view_id", "dataview_id"):
346
+ value = invocation.positional(name)
347
+ if isinstance(value, bool):
348
+ continue
349
+ if isinstance(value, int):
350
+ return value
351
+ if isinstance(value, str) and value.strip().lstrip("-").isdigit():
352
+ return int(value)
353
+ return None
354
+
355
+
356
+ def _broken_downstream_exports(invocation: Invocation, view_id: int) -> list[dict[str, Any]] | str:
357
+ """Exports on ``view_id`` now in error, read via the existing ``view.export.list``.
358
+
359
+ Each export the backend hands back already carries its own ``error_info``
360
+ when it can no longer run (see ``mammoth.models.exports.ItemExportInfo``);
361
+ this is the one read that surfaces it. A read that itself fails returns
362
+ the warning to show instead: it must not hide the write's own,
363
+ already-settled success, nor pass silently.
364
+ """
365
+ from mammoth_cli.commands.registry import HANDLERS
366
+
367
+ handler = HANDLERS.get(_VIEW_EXPORT_LIST_COMMAND)
368
+ if handler is None:
369
+ return []
370
+ read_invocation = Invocation(
371
+ command_id=_VIEW_EXPORT_LIST_COMMAND,
372
+ output="json",
373
+ profile=invocation.profile,
374
+ project=invocation.project,
375
+ timeout=invocation.timeout,
376
+ job_timeout=invocation.job_timeout,
377
+ pipeline_timeout=invocation.pipeline_timeout,
378
+ no_input=True,
379
+ positionals={"dataview_id": view_id},
380
+ extra_args=[str(view_id)],
381
+ )
382
+ try:
383
+ read_data, _meta = handler(read_invocation)
384
+ except Exception as exc: # noqa: BLE001 -- the write already succeeded
385
+ return f"could not check this view's saved exports: {exc}"
386
+ exports = read_data.get("exports") if isinstance(read_data, dict) else None
387
+ if not isinstance(exports, list):
388
+ return []
389
+ return [item for item in exports if isinstance(item, dict) and item.get("error_info")]
390
+
391
+
392
+ def _export_error_detail(item: dict[str, Any]) -> str:
393
+ """Human-readable ``"export <id> (<handler>): ..."`` line for one broken export."""
394
+ error_info = item.get("error_info")
395
+ error_info = error_info if isinstance(error_info, dict) else {}
396
+ # the backend nests the details: error_info.additional_info.{error_code,
397
+ # reference_errors} (live `view export get`, T2-WPP-W2)
398
+ nested = error_info.get("additional_info")
399
+ error_info = {**error_info, **nested} if isinstance(nested, dict) else error_info
400
+ what = f"export {item.get('id')}"
401
+ handler_type = item.get("handler_type")
402
+ if handler_type:
403
+ what += f" ({handler_type})"
404
+ error_code = error_info.get("error_code")
405
+ detail = f"error {error_code}" if error_code is not None else "an error"
406
+ columns = _export_error_columns(error_info)
407
+ if columns:
408
+ detail += f", column(s) {', '.join(columns)}"
409
+ return f"{what} is in error: {detail}"
410
+
411
+
412
+ def _export_error_columns(error_info: dict[str, Any]) -> list[str]:
413
+ """Column display names named by an export's ``error_info.reference_errors``."""
414
+ reference_errors = error_info.get("reference_errors")
415
+ if isinstance(reference_errors, dict):
416
+ entries = reference_errors.get("reference_errors") or []
417
+ elif isinstance(reference_errors, list):
418
+ entries = reference_errors
419
+ else:
420
+ entries = []
421
+ names: list[str] = []
422
+ for entry in entries:
423
+ if not isinstance(entry, dict):
424
+ continue
425
+ column = entry.get("column")
426
+ name = column.get("display_name") if isinstance(column, dict) else column
427
+ if isinstance(name, str):
428
+ names.append(name)
429
+ return names
@@ -176,6 +176,58 @@ def _duplicate_rows_warning(
176
176
  return warning
177
177
 
178
178
 
179
+ def _varying_numbers(rows: list[Mapping[str, Any]], column_types: Mapping[str, str]) -> list[str]:
180
+ """The NUMERIC columns whose non-blank values differ between rows: the row's figures."""
181
+ return [
182
+ column
183
+ for column, col_type in column_types.items()
184
+ if str(col_type).upper() == "NUMERIC"
185
+ and len({str(row.get(column)) for row in rows if not _blank(row.get(column))}) > 1
186
+ ]
187
+
188
+
189
+ def _blank_values_warning(
190
+ column: str,
191
+ blanks: int,
192
+ total: int,
193
+ checked: int,
194
+ remove_fix: str | None,
195
+ ) -> dict[str, Any]:
196
+ """The ``blank_values`` record; *remove_fix* when a blank row holds no figure at all."""
197
+ detail = f"{blanks} of {total} rows are blank. "
198
+ if remove_fix is None:
199
+ detail += (
200
+ "Decide before you summarise: fill them (view transform set-values with "
201
+ "IS_EMPTY, or fill-missing), remove the rows (view transform filter), or "
202
+ "keep them and say so."
203
+ )
204
+ return {
205
+ "column": column,
206
+ "issue": "blank_values",
207
+ "detail": detail,
208
+ "rows_checked": checked,
209
+ }
210
+ detail += (
211
+ f"{column} is the only number that varies between rows, so these rows hold no "
212
+ "figure: removing them (fix) is the clean-up. Fill them only with a value the "
213
+ "user gave; keep them only when the user needs every row listed."
214
+ )
215
+ return {
216
+ "column": column,
217
+ "issue": "blank_values",
218
+ "detail": detail,
219
+ "fix": remove_fix,
220
+ "rows_checked": checked,
221
+ }
222
+
223
+
224
+ def _remove_blank_rows_hint(view_id: int, dataset_id: int, column: str) -> str:
225
+ spec = json.dumps(
226
+ {"condition": {"column": column, "operator": "IS_NOT_EMPTY"}, "dataset_id": dataset_id}
227
+ )
228
+ return f"mammoth view transform filter {view_id} --input '{spec}'"
229
+
230
+
179
231
  def column_warnings(
180
232
  rows: Iterable[Mapping[str, Any]],
181
233
  column_types: Mapping[str, str],
@@ -204,6 +256,7 @@ def column_warnings(
204
256
  return []
205
257
  checked = len(materialised)
206
258
  warnings: list[dict[str, Any]] = []
259
+ figures = _varying_numbers(materialised, column_types)
207
260
  duplicate_warning = _duplicate_rows_warning(materialised, view_id, dataset_id)
208
261
  if duplicate_warning is not None:
209
262
  warnings.append(duplicate_warning)
@@ -254,17 +307,8 @@ def column_warnings(
254
307
  if variant_warning is not None:
255
308
  warnings.append(variant_warning)
256
309
  if blanks:
257
- warnings.append(
258
- {
259
- "column": column,
260
- "issue": "blank_values",
261
- "detail": (
262
- f"{blanks} of {len(values)} rows are blank. Decide before you "
263
- "summarise: fill them (view transform set-values with "
264
- "IS_EMPTY, or fill-missing), remove the rows (view transform "
265
- "filter), or keep them and say so."
266
- ),
267
- "rows_checked": checked,
268
- }
269
- )
310
+ remove_fix = None
311
+ if figures == [column] and view_id is not None and dataset_id is not None:
312
+ remove_fix = _remove_blank_rows_hint(view_id, dataset_id, column)
313
+ warnings.append(_blank_values_warning(column, blanks, len(values), checked, remove_fix))
270
314
  return warnings
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mammoth-cli"
3
- version = "2.0.80"
3
+ version = "2.0.82"
4
4
  description = "Command-line interface for the Mammoth Analytics platform"
5
5
  authors = [{name = "Mammoth Analytics", email = "support@mammoth.io"}]
6
6
  readme = "README.md"
File without changes
File without changes
File without changes