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.
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/PKG-INFO +1 -1
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/pyproject.toml +1 -1
- pltr_cli-0.13.1/src/pltr/__init__.py +1 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/cli.py +18 -0
- pltr_cli-0.13.1/src/pltr/commands/audit.py +186 -0
- pltr_cli-0.13.1/src/pltr/commands/data_health.py +474 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/dataset.py +4 -2
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/folder.py +10 -10
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/project.py +12 -12
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/resource.py +18 -18
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/resource_role.py +8 -8
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/space.py +8 -8
- pltr_cli-0.13.1/src/pltr/commands/widgets.py +466 -0
- pltr_cli-0.13.1/src/pltr/services/audit.py +105 -0
- pltr_cli-0.13.1/src/pltr/services/data_health.py +212 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/ontology.py +7 -7
- pltr_cli-0.13.1/src/pltr/services/widgets.py +293 -0
- pltr_cli-0.13.1/tests/test_commands/test_audit.py +340 -0
- pltr_cli-0.13.1/tests/test_commands/test_data_health.py +396 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_dataset.py +35 -7
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_folder.py +59 -14
- pltr_cli-0.13.1/tests/test_commands/test_widgets.py +560 -0
- pltr_cli-0.13.1/tests/test_services/test_data_health.py +259 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_ontology.py +6 -6
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/uv.lock +1 -1
- pltr_cli-0.13.0/src/pltr/__init__.py +0 -1
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/.github/workflows/ci.yml +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/.github/workflows/claude-code-review.yml +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/.github/workflows/claude.yml +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/.github/workflows/publish.yml +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/.github/workflows/test-publish.yml +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/.gitignore +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/.pre-commit-config.yaml +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/CHANGELOG.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/CLAUDE.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/LICENSE +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/README.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/RELEASE.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/README.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/SKILL.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/admin-commands.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/aip-agents-commands.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/connectivity-commands.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/dataset-commands.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/filesystem-commands.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/functions-commands.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/language-models-commands.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/mediasets-commands.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/models-commands.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/ontology-commands.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/orchestration-commands.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/quick-start.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/sql-commands.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/reference/streams-commands.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/workflows/data-analysis.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/workflows/data-pipeline.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/claude_skill/workflows/permission-management.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/README.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/api/wrapper.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/examples/csv-upload.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/examples/gallery.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/features/dataset-transactions.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/migration/v2-pagination.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/pagination.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/user-guide/aliases.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/user-guide/authentication.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/user-guide/claude-skill.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/user-guide/commands.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/user-guide/quick-start.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/user-guide/troubleshooting.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/docs/user-guide/workflows.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/mypy.ini +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/scripts/release.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/__main__.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/auth/__init__.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/auth/base.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/auth/manager.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/auth/oauth.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/auth/storage.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/auth/token.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/__init__.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/admin.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/aip_agents.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/alias.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/completion.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/configure.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/connectivity.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/cp.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/functions.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/language_models.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/mediasets.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/models.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/ontology.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/orchestration.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/shell.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/sql.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/streams.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/third_party_applications.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/commands/verify.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/config/__init__.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/config/aliases.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/config/profiles.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/config/settings.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/__init__.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/admin.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/aip_agents.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/base.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/connectivity.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/copy.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/dataset.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/folder.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/functions.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/language_models.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/mediasets.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/models.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/orchestration.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/project.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/resource.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/resource_role.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/space.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/sql.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/streams.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/services/third_party_applications.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/utils/__init__.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/utils/alias_resolver.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/utils/completion.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/utils/formatting.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/utils/pagination.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/src/pltr/utils/progress.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/__init__.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/conftest.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/integration/README.md +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/integration/__init__.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/integration/conftest.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/integration/test_auth_flow.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/integration/test_cli_integration.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/integration/test_data_workflows.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/integration/test_data_workflows_simple.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/integration/test_simple_integration.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_auth/__init__.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_auth/test_base.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_auth/test_manager.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_auth/test_oauth.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_auth/test_storage.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_auth/test_token.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/__init__.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_admin.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_aip_agents.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_alias.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_completion.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_connectivity.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_functions.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_language_models.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_mediasets.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_models.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_ontology.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_orchestration.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_shell.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_sql.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_streams.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_third_party_applications.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_commands/test_verify_simple.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_config/__init__.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_config/test_aliases.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_config/test_profiles.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_config/test_settings.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/__init__.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_admin.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_aip_agents.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_base.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_connectivity.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_copy.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_dataset.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_dataset_transactions.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_folder.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_functions.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_language_models.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_mediasets.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_models.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_orchestration.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_pagination_integration.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_project.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_resource.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_resource_role.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_space.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_sql.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_services/test_streams.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_utils/__init__.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_utils/test_alias_resolver.py +0 -0
- {pltr_cli-0.13.0 → pltr_cli-0.13.1}/tests/test_utils/test_pagination.py +0 -0
|
@@ -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)
|