pltr-cli 0.13.0__tar.gz → 0.13.1__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 (190) hide show
  1. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/PKG-INFO +1 -1
  2. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/pyproject.toml +1 -1
  3. pltr_cli-0.13.1/src/pltr/__init__.py +1 -0
  4. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/cli.py +18 -0
  5. pltr_cli-0.13.1/src/pltr/commands/audit.py +186 -0
  6. pltr_cli-0.13.1/src/pltr/commands/data_health.py +474 -0
  7. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/dataset.py +4 -2
  8. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/folder.py +10 -10
  9. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/project.py +12 -12
  10. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/resource.py +18 -18
  11. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/resource_role.py +8 -8
  12. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/space.py +8 -8
  13. pltr_cli-0.13.1/src/pltr/commands/widgets.py +466 -0
  14. pltr_cli-0.13.1/src/pltr/services/audit.py +105 -0
  15. pltr_cli-0.13.1/src/pltr/services/data_health.py +212 -0
  16. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/ontology.py +7 -7
  17. pltr_cli-0.13.1/src/pltr/services/widgets.py +293 -0
  18. pltr_cli-0.13.1/tests/test_commands/test_audit.py +340 -0
  19. pltr_cli-0.13.1/tests/test_commands/test_data_health.py +396 -0
  20. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_dataset.py +35 -7
  21. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_folder.py +59 -14
  22. pltr_cli-0.13.1/tests/test_commands/test_widgets.py +560 -0
  23. pltr_cli-0.13.1/tests/test_services/test_data_health.py +259 -0
  24. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_ontology.py +6 -6
  25. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/uv.lock +1 -1
  26. pltr_cli-0.13.0/src/pltr/__init__.py +0 -1
  27. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/.github/workflows/ci.yml +0 -0
  28. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/.github/workflows/claude-code-review.yml +0 -0
  29. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/.github/workflows/claude.yml +0 -0
  30. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/.github/workflows/publish.yml +0 -0
  31. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/.github/workflows/test-publish.yml +0 -0
  32. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/.gitignore +0 -0
  33. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/.pre-commit-config.yaml +0 -0
  34. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/CHANGELOG.md +0 -0
  35. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/CLAUDE.md +0 -0
  36. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/LICENSE +0 -0
  37. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/README.md +0 -0
  38. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/RELEASE.md +0 -0
  39. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/README.md +0 -0
  40. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/SKILL.md +0 -0
  41. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/admin-commands.md +0 -0
  42. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/aip-agents-commands.md +0 -0
  43. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/connectivity-commands.md +0 -0
  44. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/dataset-commands.md +0 -0
  45. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/filesystem-commands.md +0 -0
  46. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/functions-commands.md +0 -0
  47. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/language-models-commands.md +0 -0
  48. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/mediasets-commands.md +0 -0
  49. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/models-commands.md +0 -0
  50. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/ontology-commands.md +0 -0
  51. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/orchestration-commands.md +0 -0
  52. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/quick-start.md +0 -0
  53. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/sql-commands.md +0 -0
  54. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/streams-commands.md +0 -0
  55. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/workflows/data-analysis.md +0 -0
  56. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/workflows/data-pipeline.md +0 -0
  57. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/workflows/permission-management.md +0 -0
  58. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/README.md +0 -0
  59. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/api/wrapper.md +0 -0
  60. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/examples/csv-upload.md +0 -0
  61. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/examples/gallery.md +0 -0
  62. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/features/dataset-transactions.md +0 -0
  63. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/migration/v2-pagination.md +0 -0
  64. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/pagination.md +0 -0
  65. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/user-guide/aliases.md +0 -0
  66. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/user-guide/authentication.md +0 -0
  67. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/user-guide/claude-skill.md +0 -0
  68. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/user-guide/commands.md +0 -0
  69. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/user-guide/quick-start.md +0 -0
  70. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/user-guide/troubleshooting.md +0 -0
  71. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/user-guide/workflows.md +0 -0
  72. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/mypy.ini +0 -0
  73. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/scripts/release.py +0 -0
  74. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/__main__.py +0 -0
  75. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/auth/__init__.py +0 -0
  76. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/auth/base.py +0 -0
  77. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/auth/manager.py +0 -0
  78. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/auth/oauth.py +0 -0
  79. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/auth/storage.py +0 -0
  80. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/auth/token.py +0 -0
  81. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/__init__.py +0 -0
  82. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/admin.py +0 -0
  83. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/aip_agents.py +0 -0
  84. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/alias.py +0 -0
  85. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/completion.py +0 -0
  86. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/configure.py +0 -0
  87. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/connectivity.py +0 -0
  88. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/cp.py +0 -0
  89. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/functions.py +0 -0
  90. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/language_models.py +0 -0
  91. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/mediasets.py +0 -0
  92. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/models.py +0 -0
  93. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/ontology.py +0 -0
  94. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/orchestration.py +0 -0
  95. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/shell.py +0 -0
  96. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/sql.py +0 -0
  97. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/streams.py +0 -0
  98. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/third_party_applications.py +0 -0
  99. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/verify.py +0 -0
  100. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/config/__init__.py +0 -0
  101. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/config/aliases.py +0 -0
  102. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/config/profiles.py +0 -0
  103. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/config/settings.py +0 -0
  104. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/__init__.py +0 -0
  105. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/admin.py +0 -0
  106. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/aip_agents.py +0 -0
  107. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/base.py +0 -0
  108. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/connectivity.py +0 -0
  109. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/copy.py +0 -0
  110. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/dataset.py +0 -0
  111. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/folder.py +0 -0
  112. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/functions.py +0 -0
  113. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/language_models.py +0 -0
  114. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/mediasets.py +0 -0
  115. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/models.py +0 -0
  116. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/orchestration.py +0 -0
  117. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/project.py +0 -0
  118. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/resource.py +0 -0
  119. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/resource_role.py +0 -0
  120. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/space.py +0 -0
  121. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/sql.py +0 -0
  122. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/streams.py +0 -0
  123. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/third_party_applications.py +0 -0
  124. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/utils/__init__.py +0 -0
  125. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/utils/alias_resolver.py +0 -0
  126. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/utils/completion.py +0 -0
  127. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/utils/formatting.py +0 -0
  128. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/utils/pagination.py +0 -0
  129. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/utils/progress.py +0 -0
  130. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/__init__.py +0 -0
  131. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/conftest.py +0 -0
  132. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/integration/README.md +0 -0
  133. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/integration/__init__.py +0 -0
  134. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/integration/conftest.py +0 -0
  135. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/integration/test_auth_flow.py +0 -0
  136. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/integration/test_cli_integration.py +0 -0
  137. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/integration/test_data_workflows.py +0 -0
  138. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/integration/test_data_workflows_simple.py +0 -0
  139. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/integration/test_simple_integration.py +0 -0
  140. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_auth/__init__.py +0 -0
  141. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_auth/test_base.py +0 -0
  142. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_auth/test_manager.py +0 -0
  143. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_auth/test_oauth.py +0 -0
  144. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_auth/test_storage.py +0 -0
  145. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_auth/test_token.py +0 -0
  146. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/__init__.py +0 -0
  147. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_admin.py +0 -0
  148. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_aip_agents.py +0 -0
  149. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_alias.py +0 -0
  150. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_completion.py +0 -0
  151. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_connectivity.py +0 -0
  152. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_functions.py +0 -0
  153. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_language_models.py +0 -0
  154. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_mediasets.py +0 -0
  155. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_models.py +0 -0
  156. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_ontology.py +0 -0
  157. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_orchestration.py +0 -0
  158. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_shell.py +0 -0
  159. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_sql.py +0 -0
  160. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_streams.py +0 -0
  161. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_third_party_applications.py +0 -0
  162. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_verify_simple.py +0 -0
  163. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_config/__init__.py +0 -0
  164. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_config/test_aliases.py +0 -0
  165. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_config/test_profiles.py +0 -0
  166. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_config/test_settings.py +0 -0
  167. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/__init__.py +0 -0
  168. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_admin.py +0 -0
  169. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_aip_agents.py +0 -0
  170. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_base.py +0 -0
  171. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_connectivity.py +0 -0
  172. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_copy.py +0 -0
  173. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_dataset.py +0 -0
  174. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_dataset_transactions.py +0 -0
  175. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_folder.py +0 -0
  176. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_functions.py +0 -0
  177. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_language_models.py +0 -0
  178. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_mediasets.py +0 -0
  179. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_models.py +0 -0
  180. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_orchestration.py +0 -0
  181. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_pagination_integration.py +0 -0
  182. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_project.py +0 -0
  183. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_resource.py +0 -0
  184. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_resource_role.py +0 -0
  185. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_space.py +0 -0
  186. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_sql.py +0 -0
  187. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_streams.py +0 -0
  188. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_utils/__init__.py +0 -0
  189. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_utils/test_alias_resolver.py +0 -0
  190. {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_utils/test_pagination.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pltr-cli
3
- Version: 0.13.0
3
+ Version: 0.13.1
4
4
  Summary: Command-line interface for Palantir Foundry APIs
5
5
  Project-URL: Homepage, https://github.com/anjor/pltr-cli
6
6
  Project-URL: Repository, https://github.com/anjor/pltr-cli
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pltr-cli"
3
- version = "0.13.0"
3
+ version = "0.13.1"
4
4
  description = "Command-line interface for Palantir Foundry APIs"
5
5
  authors = [
6
6
  { name = "anjor", email = "anjor@umd.edu" },
@@ -0,0 +1 @@
1
+ __version__ = "0.13.1"
@@ -30,6 +30,9 @@ from pltr.commands import (
30
30
  streams,
31
31
  language_models,
32
32
  models,
33
+ data_health,
34
+ audit,
35
+ widgets,
33
36
  )
34
37
  from pltr.commands.cp import cp_command
35
38
 
@@ -91,6 +94,21 @@ app.add_typer(
91
94
  name="models",
92
95
  help="Manage ML models and versions",
93
96
  )
97
+ app.add_typer(
98
+ data_health.app,
99
+ name="data-health",
100
+ help="Manage data health checks and reports",
101
+ )
102
+ app.add_typer(
103
+ audit.app,
104
+ name="audit",
105
+ help="Audit log operations for compliance and security monitoring",
106
+ )
107
+ app.add_typer(
108
+ widgets.app,
109
+ name="widgets",
110
+ help="Manage widget sets, releases, and repositories",
111
+ )
94
112
  app.add_typer(
95
113
  admin.app,
96
114
  name="admin",
@@ -0,0 +1,186 @@
1
+ """
2
+ Audit log file management commands for Foundry.
3
+ Provides access to audit logs for compliance and security monitoring.
4
+ """
5
+
6
+ from datetime import date, datetime
7
+ from pathlib import Path
8
+ from typing import Optional
9
+
10
+ import typer
11
+ from rich.console import Console
12
+
13
+ from ..auth.base import MissingCredentialsError, ProfileNotFoundError
14
+ from ..services.audit import AuditService
15
+ from ..utils.completion import (
16
+ complete_output_format,
17
+ complete_profile,
18
+ complete_rid,
19
+ cache_rid,
20
+ )
21
+ from ..utils.formatting import OutputFormatter
22
+ from ..utils.progress import SpinnerProgressTracker
23
+
24
+ app = typer.Typer(help="Audit log operations for compliance and security monitoring")
25
+ console = Console()
26
+ formatter = OutputFormatter(console)
27
+
28
+
29
+ def parse_date(date_str: str) -> date:
30
+ """Parse a date string in YYYY-MM-DD format (not full ISO 8601)."""
31
+ try:
32
+ return datetime.strptime(date_str, "%Y-%m-%d").date()
33
+ except ValueError:
34
+ raise typer.BadParameter(f"Invalid date format: {date_str}. Use YYYY-MM-DD.")
35
+
36
+
37
+ @app.command("list")
38
+ def list_log_files(
39
+ organization_rid: str = typer.Argument(
40
+ ...,
41
+ help="Organization Resource Identifier (e.g., ri.multipass..organization.xxx)",
42
+ autocompletion=complete_rid,
43
+ ),
44
+ start_date: str = typer.Argument(
45
+ ...,
46
+ help="Start date for audit events (YYYY-MM-DD format, required)",
47
+ ),
48
+ end_date: Optional[str] = typer.Option(
49
+ None,
50
+ "--end-date",
51
+ "-e",
52
+ help="End date for audit events (YYYY-MM-DD format, inclusive)",
53
+ ),
54
+ page_size: Optional[int] = typer.Option(
55
+ None,
56
+ "--page-size",
57
+ help="Number of results per page",
58
+ ),
59
+ profile: Optional[str] = typer.Option(
60
+ None,
61
+ "--profile",
62
+ "-p",
63
+ help="Profile name",
64
+ autocompletion=complete_profile,
65
+ ),
66
+ format: str = typer.Option(
67
+ "table",
68
+ "--format",
69
+ "-f",
70
+ help="Output format (table, json, csv)",
71
+ autocompletion=complete_output_format,
72
+ ),
73
+ output: Optional[str] = typer.Option(
74
+ None, "--output", "-o", help="Output file path"
75
+ ),
76
+ ) -> None:
77
+ """List audit log files for an organization."""
78
+ try:
79
+ # Cache the RID for future completions
80
+ cache_rid(organization_rid)
81
+
82
+ # Parse dates
83
+ start = parse_date(start_date)
84
+ end = parse_date(end_date) if end_date else None
85
+
86
+ service = AuditService(profile=profile)
87
+
88
+ with SpinnerProgressTracker().track_spinner("Fetching audit log files..."):
89
+ logs = service.list_log_files(
90
+ organization_rid=organization_rid,
91
+ start_date=start,
92
+ end_date=end,
93
+ page_size=page_size,
94
+ )
95
+
96
+ if not logs:
97
+ formatter.print_info("No audit log files found for the specified criteria")
98
+ return
99
+
100
+ formatter.print_info(f"Found {len(logs)} audit log files")
101
+
102
+ if output:
103
+ formatter.save_to_file(logs, output, format)
104
+ formatter.print_success(f"Audit log files saved to {output}")
105
+ else:
106
+ formatter.display(logs, format)
107
+
108
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
109
+ formatter.print_error(f"Authentication error: {e}")
110
+ raise typer.Exit(1)
111
+ except typer.BadParameter:
112
+ raise
113
+ except ValueError as e:
114
+ formatter.print_error(f"Invalid request: {e}")
115
+ raise typer.Exit(1)
116
+ except Exception as e:
117
+ formatter.print_error(f"Failed to list audit log files: {e}")
118
+ raise typer.Exit(1)
119
+
120
+
121
+ @app.command("get")
122
+ def get_log_file_content(
123
+ organization_rid: str = typer.Argument(
124
+ ...,
125
+ help="Organization Resource Identifier (e.g., ri.multipass..organization.xxx)",
126
+ autocompletion=complete_rid,
127
+ ),
128
+ log_file_id: str = typer.Argument(
129
+ ...,
130
+ help="Log file identifier (from list command)",
131
+ ),
132
+ output: Optional[str] = typer.Option(
133
+ None,
134
+ "--output",
135
+ "-o",
136
+ help="Output file path (required for binary content)",
137
+ ),
138
+ profile: Optional[str] = typer.Option(
139
+ None,
140
+ "--profile",
141
+ "-p",
142
+ help="Profile name",
143
+ autocompletion=complete_profile,
144
+ ),
145
+ ) -> None:
146
+ """Get the content of a specific audit log file."""
147
+ try:
148
+ # Cache the RID for future completions
149
+ cache_rid(organization_rid)
150
+
151
+ service = AuditService(profile=profile)
152
+
153
+ with SpinnerProgressTracker().track_spinner(
154
+ f"Fetching audit log file {log_file_id}..."
155
+ ):
156
+ content = service.get_log_file_content(
157
+ organization_rid=organization_rid,
158
+ log_file_id=log_file_id,
159
+ )
160
+
161
+ if output:
162
+ # Write binary content to file
163
+ Path(output).write_bytes(content)
164
+ formatter.print_success(
165
+ f"Audit log file saved to {output} ({len(content)} bytes)"
166
+ )
167
+ else:
168
+ # Try to decode as text for display
169
+ try:
170
+ text_content = content.decode("utf-8")
171
+ console.print(text_content)
172
+ except UnicodeDecodeError:
173
+ formatter.print_error(
174
+ "Log file contains binary content. Use --output to save to a file."
175
+ )
176
+ raise typer.Exit(1)
177
+
178
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
179
+ formatter.print_error(f"Authentication error: {e}")
180
+ raise typer.Exit(1)
181
+ except ValueError as e:
182
+ formatter.print_error(f"Invalid request: {e}")
183
+ raise typer.Exit(1)
184
+ except Exception as e:
185
+ formatter.print_error(f"Failed to get audit log file: {e}")
186
+ raise typer.Exit(1)
@@ -0,0 +1,474 @@
1
+ """
2
+ DataHealth management commands for Foundry.
3
+ Provides commands for managing data quality checks and reports.
4
+ """
5
+
6
+ import typer
7
+ import json
8
+ from typing import Optional
9
+ from rich.console import Console
10
+
11
+ from ..services.data_health import DataHealthService
12
+ from ..utils.formatting import OutputFormatter
13
+ from ..utils.progress import SpinnerProgressTracker
14
+ from ..auth.base import ProfileNotFoundError, MissingCredentialsError
15
+ from ..utils.completion import (
16
+ complete_rid,
17
+ complete_profile,
18
+ complete_output_format,
19
+ )
20
+
21
+ # Create main app and sub-apps
22
+ app = typer.Typer(help="Manage data health checks and reports")
23
+ check_app = typer.Typer(help="Manage data health checks")
24
+ report_app = typer.Typer(help="View data health check reports")
25
+
26
+ # Add sub-apps
27
+ app.add_typer(check_app, name="check")
28
+ app.add_typer(report_app, name="report")
29
+
30
+ console = Console()
31
+ formatter = OutputFormatter(console)
32
+
33
+
34
+ @check_app.command("get")
35
+ def get_check(
36
+ check_rid: str = typer.Argument(
37
+ ...,
38
+ help="Check RID (e.g., ri.data-health.main.check.xxx)",
39
+ autocompletion=complete_rid,
40
+ ),
41
+ profile: Optional[str] = typer.Option(
42
+ None,
43
+ "--profile",
44
+ "-p",
45
+ help="Profile name",
46
+ autocompletion=complete_profile,
47
+ ),
48
+ format: str = typer.Option(
49
+ "table",
50
+ "--format",
51
+ help="Output format (table, json, csv)",
52
+ autocompletion=complete_output_format,
53
+ ),
54
+ output: Optional[str] = typer.Option(
55
+ None,
56
+ "--output",
57
+ "-o",
58
+ help="Output file path (writes to file instead of stdout)",
59
+ ),
60
+ preview: bool = typer.Option(
61
+ False,
62
+ "--preview",
63
+ help="Enable preview mode",
64
+ ),
65
+ ):
66
+ """
67
+ Get information about a data health check.
68
+
69
+ Retrieves check details including configuration, status, and metadata.
70
+
71
+ Examples:
72
+
73
+ # Get check details
74
+ pltr data-health check get ri.data-health.main.check.abc123
75
+
76
+ # Get as JSON
77
+ pltr data-health check get ri.data-health.main.check.abc123 --format json
78
+
79
+ # Save to file
80
+ pltr data-health check get ri.data-health.main.check.abc123 \\
81
+ --format json \\
82
+ --output check-details.json
83
+ """
84
+ try:
85
+ with SpinnerProgressTracker().track_spinner("Fetching check information"):
86
+ service = DataHealthService(profile=profile)
87
+ result = service.get_check(
88
+ check_rid=check_rid,
89
+ preview=preview,
90
+ )
91
+
92
+ formatter.format_output(result, format, output)
93
+
94
+ if output:
95
+ console.print(f"[green]✓[/green] Check information saved to {output}")
96
+
97
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
98
+ console.print(f"[red]Authentication Error: {e}[/red]")
99
+ raise typer.Exit(1)
100
+ except Exception as e:
101
+ console.print(f"[red]Error: {e}[/red]")
102
+ raise typer.Exit(1)
103
+
104
+
105
+ @check_app.command("create")
106
+ def create_check(
107
+ config: str = typer.Argument(
108
+ ...,
109
+ help="Check configuration as JSON string or @filepath",
110
+ ),
111
+ intent: Optional[str] = typer.Option(
112
+ None,
113
+ "--intent",
114
+ "-i",
115
+ help="Note about why the check was set up",
116
+ ),
117
+ profile: Optional[str] = typer.Option(
118
+ None,
119
+ "--profile",
120
+ "-p",
121
+ help="Profile name",
122
+ autocompletion=complete_profile,
123
+ ),
124
+ format: str = typer.Option(
125
+ "table",
126
+ "--format",
127
+ help="Output format (table, json, csv)",
128
+ autocompletion=complete_output_format,
129
+ ),
130
+ output: Optional[str] = typer.Option(
131
+ None,
132
+ "--output",
133
+ "-o",
134
+ help="Output file path (writes to file instead of stdout)",
135
+ ),
136
+ preview: bool = typer.Option(
137
+ False,
138
+ "--preview",
139
+ help="Enable preview mode",
140
+ ),
141
+ ):
142
+ """
143
+ Create a new data health check.
144
+
145
+ The config argument should be a JSON string or @filepath containing
146
+ the check configuration. The configuration must include a 'type' field.
147
+
148
+ Supported check types include:
149
+ - buildStatus: Check dataset build status
150
+ - buildDuration: Check dataset build duration
151
+ - nullPercentage: Check percentage of null values in a column
152
+ - columnType: Check column existence and type
153
+ - numericColumnRange: Check numeric column value ranges
154
+ - And more...
155
+
156
+ Examples:
157
+
158
+ # Create a build status check from JSON string
159
+ pltr data-health check create '{
160
+ "type": "buildStatus",
161
+ "subject": {
162
+ "datasetRid": "ri.foundry.main.dataset.xxx",
163
+ "branchId": "master"
164
+ },
165
+ "statusCheckConfig": {"severity": "WARNING"}
166
+ }' --intent "Monitor production builds"
167
+
168
+ # Create from JSON file
169
+ pltr data-health check create @check-config.json
170
+
171
+ # Create with JSON output
172
+ pltr data-health check create @config.json --format json
173
+ """
174
+ try:
175
+ # Parse config from JSON string or file
176
+ config_dict = _parse_json_config(config)
177
+
178
+ with SpinnerProgressTracker().track_spinner("Creating check"):
179
+ service = DataHealthService(profile=profile)
180
+ result = service.create_check(
181
+ config=config_dict,
182
+ intent=intent,
183
+ preview=preview,
184
+ )
185
+
186
+ console.print(f"[green]✓[/green] Created check: {result.get('rid')}")
187
+
188
+ formatter.format_output(result, format, output)
189
+
190
+ if output:
191
+ console.print(f"[green]✓[/green] Check information saved to {output}")
192
+
193
+ except json.JSONDecodeError as e:
194
+ console.print(f"[red]Invalid JSON configuration: {e}[/red]")
195
+ raise typer.Exit(1)
196
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
197
+ console.print(f"[red]Authentication Error: {e}[/red]")
198
+ raise typer.Exit(1)
199
+ except Exception as e:
200
+ console.print(f"[red]Error: {e}[/red]")
201
+ raise typer.Exit(1)
202
+
203
+
204
+ @check_app.command("replace")
205
+ def replace_check(
206
+ check_rid: str = typer.Argument(
207
+ ...,
208
+ help="Check RID (e.g., ri.data-health.main.check.xxx)",
209
+ autocompletion=complete_rid,
210
+ ),
211
+ config: str = typer.Argument(
212
+ ...,
213
+ help="New check configuration as JSON string or @filepath",
214
+ ),
215
+ intent: Optional[str] = typer.Option(
216
+ None,
217
+ "--intent",
218
+ "-i",
219
+ help="Updated note about the check",
220
+ ),
221
+ profile: Optional[str] = typer.Option(
222
+ None,
223
+ "--profile",
224
+ "-p",
225
+ help="Profile name",
226
+ autocompletion=complete_profile,
227
+ ),
228
+ format: str = typer.Option(
229
+ "table",
230
+ "--format",
231
+ help="Output format (table, json, csv)",
232
+ autocompletion=complete_output_format,
233
+ ),
234
+ output: Optional[str] = typer.Option(
235
+ None,
236
+ "--output",
237
+ "-o",
238
+ help="Output file path (writes to file instead of stdout)",
239
+ ),
240
+ preview: bool = typer.Option(
241
+ False,
242
+ "--preview",
243
+ help="Enable preview mode",
244
+ ),
245
+ ):
246
+ """
247
+ Replace/update a data health check.
248
+
249
+ Note: Changing the type of a check after creation is not supported.
250
+
251
+ Examples:
252
+
253
+ # Update check configuration
254
+ pltr data-health check replace ri.data-health.main.check.abc123 \\
255
+ '{"type": "buildStatus", ...}' \\
256
+ --intent "Updated threshold"
257
+
258
+ # Update from file
259
+ pltr data-health check replace ri.data-health.main.check.abc123 \\
260
+ @updated-config.json
261
+ """
262
+ try:
263
+ # Parse config from JSON string or file
264
+ config_dict = _parse_json_config(config)
265
+
266
+ with SpinnerProgressTracker().track_spinner("Updating check"):
267
+ service = DataHealthService(profile=profile)
268
+ result = service.replace_check(
269
+ check_rid=check_rid,
270
+ config=config_dict,
271
+ intent=intent,
272
+ preview=preview,
273
+ )
274
+
275
+ console.print(f"[green]✓[/green] Updated check: {result.get('rid')}")
276
+
277
+ formatter.format_output(result, format, output)
278
+
279
+ if output:
280
+ console.print(f"[green]✓[/green] Check information saved to {output}")
281
+
282
+ except json.JSONDecodeError as e:
283
+ console.print(f"[red]Invalid JSON configuration: {e}[/red]")
284
+ raise typer.Exit(1)
285
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
286
+ console.print(f"[red]Authentication Error: {e}[/red]")
287
+ raise typer.Exit(1)
288
+ except Exception as e:
289
+ console.print(f"[red]Error: {e}[/red]")
290
+ raise typer.Exit(1)
291
+
292
+
293
+ @check_app.command("delete")
294
+ def delete_check(
295
+ check_rid: str = typer.Argument(
296
+ ...,
297
+ help="Check RID (e.g., ri.data-health.main.check.xxx)",
298
+ autocompletion=complete_rid,
299
+ ),
300
+ profile: Optional[str] = typer.Option(
301
+ None,
302
+ "--profile",
303
+ "-p",
304
+ help="Profile name",
305
+ autocompletion=complete_profile,
306
+ ),
307
+ force: bool = typer.Option(
308
+ False,
309
+ "--force",
310
+ "-f",
311
+ help="Skip confirmation prompt",
312
+ ),
313
+ preview: bool = typer.Option(
314
+ False,
315
+ "--preview",
316
+ help="Enable preview mode",
317
+ ),
318
+ ):
319
+ """
320
+ Delete a data health check.
321
+
322
+ Examples:
323
+
324
+ # Delete with confirmation
325
+ pltr data-health check delete ri.data-health.main.check.abc123
326
+
327
+ # Delete without confirmation
328
+ pltr data-health check delete ri.data-health.main.check.abc123 --force
329
+ """
330
+ # Handle confirmation outside try-except to avoid catching typer.Exit
331
+ if not force:
332
+ confirm = typer.confirm(f"Are you sure you want to delete check '{check_rid}'?")
333
+ if not confirm:
334
+ console.print("[yellow]Cancelled[/yellow]")
335
+ raise typer.Exit(0)
336
+
337
+ try:
338
+ with SpinnerProgressTracker().track_spinner("Deleting check"):
339
+ service = DataHealthService(profile=profile)
340
+ service.delete_check(
341
+ check_rid=check_rid,
342
+ preview=preview,
343
+ )
344
+
345
+ console.print(f"[green]✓[/green] Deleted check: {check_rid}")
346
+
347
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
348
+ console.print(f"[red]Authentication Error: {e}[/red]")
349
+ raise typer.Exit(1)
350
+ except Exception as e:
351
+ console.print(f"[red]Error: {e}[/red]")
352
+ raise typer.Exit(1)
353
+
354
+
355
+ @report_app.command("get")
356
+ def get_report(
357
+ check_report_rid: str = typer.Argument(
358
+ ...,
359
+ help="CheckReport RID (e.g., ri.data-health.main.check-report.xxx)",
360
+ autocompletion=complete_rid,
361
+ ),
362
+ profile: Optional[str] = typer.Option(
363
+ None,
364
+ "--profile",
365
+ "-p",
366
+ help="Profile name",
367
+ autocompletion=complete_profile,
368
+ ),
369
+ format: str = typer.Option(
370
+ "table",
371
+ "--format",
372
+ help="Output format (table, json, csv)",
373
+ autocompletion=complete_output_format,
374
+ ),
375
+ output: Optional[str] = typer.Option(
376
+ None,
377
+ "--output",
378
+ "-o",
379
+ help="Output file path (writes to file instead of stdout)",
380
+ ),
381
+ preview: bool = typer.Option(
382
+ False,
383
+ "--preview",
384
+ help="Enable preview mode",
385
+ ),
386
+ ):
387
+ """
388
+ Get a data health check report.
389
+
390
+ Retrieves the result of a check execution including status and details.
391
+
392
+ Check result statuses:
393
+ - PASSED: Check passed successfully
394
+ - FAILED: Check failed
395
+ - WARNING: Check completed with warnings
396
+ - ERROR: Check encountered an error
397
+ - NOT_APPLICABLE: Check was not applicable
398
+ - NOT_COMPUTABLE: Check result could not be computed
399
+
400
+ Examples:
401
+
402
+ # Get report details
403
+ pltr data-health report get ri.data-health.main.check-report.abc123
404
+
405
+ # Get as JSON
406
+ pltr data-health report get ri.data-health.main.check-report.abc123 \\
407
+ --format json
408
+
409
+ # Save to file
410
+ pltr data-health report get ri.data-health.main.check-report.abc123 \\
411
+ --format json \\
412
+ --output report.json
413
+ """
414
+ try:
415
+ with SpinnerProgressTracker().track_spinner("Fetching check report"):
416
+ service = DataHealthService(profile=profile)
417
+ result = service.get_check_report(
418
+ check_report_rid=check_report_rid,
419
+ preview=preview,
420
+ )
421
+
422
+ # Display status prominently
423
+ status = result.get("result", {}).get("status", "UNKNOWN")
424
+ status_colors = {
425
+ "PASSED": "green",
426
+ "FAILED": "red",
427
+ "WARNING": "yellow",
428
+ "ERROR": "red",
429
+ "NOT_APPLICABLE": "dim",
430
+ "NOT_COMPUTABLE": "dim",
431
+ }
432
+ color = status_colors.get(status, "white")
433
+ console.print(f"Status: [{color}]{status}[/{color}]")
434
+
435
+ message = result.get("result", {}).get("message")
436
+ if message:
437
+ console.print(f"Message: {message}")
438
+
439
+ console.print()
440
+ formatter.format_output(result, format, output)
441
+
442
+ if output:
443
+ console.print(f"[green]✓[/green] Report information saved to {output}")
444
+
445
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
446
+ console.print(f"[red]Authentication Error: {e}[/red]")
447
+ raise typer.Exit(1)
448
+ except Exception as e:
449
+ console.print(f"[red]Error: {e}[/red]")
450
+ raise typer.Exit(1)
451
+
452
+
453
+ def _parse_json_config(config: str) -> dict:
454
+ """
455
+ Parse JSON configuration from a string or file.
456
+
457
+ Args:
458
+ config: JSON string or @filepath
459
+
460
+ Returns:
461
+ Parsed dictionary
462
+
463
+ Raises:
464
+ json.JSONDecodeError: If JSON is invalid
465
+ FileNotFoundError: If file doesn't exist
466
+ """
467
+ if config.startswith("@"):
468
+ # Load from file
469
+ filepath = config[1:]
470
+ with open(filepath, "r") as f:
471
+ return json.load(f)
472
+ else:
473
+ # Parse JSON string
474
+ return json.loads(config)