pltr-cli 0.8.0__tar.gz → 0.9.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 (129) hide show
  1. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/PKG-INFO +1 -1
  2. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/pyproject.toml +1 -1
  3. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/scripts/release.py +26 -8
  4. pltr_cli-0.9.1/src/pltr/__init__.py +1 -0
  5. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/commands/dataset.py +55 -2
  6. pltr_cli-0.9.1/src/pltr/services/base.py +129 -0
  7. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/services/dataset.py +55 -0
  8. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/uv.lock +1 -1
  9. pltr_cli-0.8.0/src/pltr/__init__.py +0 -1
  10. pltr_cli-0.8.0/src/pltr/services/base.py +0 -62
  11. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/.github/workflows/ci.yml +0 -0
  12. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/.github/workflows/publish.yml +0 -0
  13. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/.github/workflows/test-publish.yml +0 -0
  14. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/.gitignore +0 -0
  15. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/.pre-commit-config.yaml +0 -0
  16. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/CHANGELOG.md +0 -0
  17. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/CLAUDE.md +0 -0
  18. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/LICENSE +0 -0
  19. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/README.md +0 -0
  20. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/RELEASE.md +0 -0
  21. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/children.csv +0 -0
  22. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/docs/README.md +0 -0
  23. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/docs/api/wrapper.md +0 -0
  24. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/docs/examples/csv-upload.md +0 -0
  25. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/docs/examples/gallery.md +0 -0
  26. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/docs/features/dataset-transactions.md +0 -0
  27. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/docs/user-guide/aliases.md +0 -0
  28. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/docs/user-guide/authentication.md +0 -0
  29. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/docs/user-guide/commands.md +0 -0
  30. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/docs/user-guide/quick-start.md +0 -0
  31. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/docs/user-guide/troubleshooting.md +0 -0
  32. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/docs/user-guide/workflows.md +0 -0
  33. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/folder_info.json +0 -0
  34. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/folders.json +0 -0
  35. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/mypy.ini +0 -0
  36. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/__main__.py +0 -0
  37. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/auth/__init__.py +0 -0
  38. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/auth/base.py +0 -0
  39. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/auth/manager.py +0 -0
  40. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/auth/oauth.py +0 -0
  41. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/auth/storage.py +0 -0
  42. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/auth/token.py +0 -0
  43. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/cli.py +0 -0
  44. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/commands/__init__.py +0 -0
  45. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/commands/admin.py +0 -0
  46. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/commands/alias.py +0 -0
  47. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/commands/completion.py +0 -0
  48. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/commands/configure.py +0 -0
  49. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/commands/connectivity.py +0 -0
  50. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/commands/folder.py +0 -0
  51. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/commands/mediasets.py +0 -0
  52. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/commands/ontology.py +0 -0
  53. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/commands/orchestration.py +0 -0
  54. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/commands/project.py +0 -0
  55. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/commands/resource.py +0 -0
  56. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/commands/resource_role.py +0 -0
  57. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/commands/shell.py +0 -0
  58. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/commands/space.py +0 -0
  59. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/commands/sql.py +0 -0
  60. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/commands/verify.py +0 -0
  61. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/config/__init__.py +0 -0
  62. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/config/aliases.py +0 -0
  63. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/config/profiles.py +0 -0
  64. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/config/settings.py +0 -0
  65. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/services/__init__.py +0 -0
  66. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/services/admin.py +0 -0
  67. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/services/connectivity.py +0 -0
  68. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/services/folder.py +0 -0
  69. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/services/mediasets.py +0 -0
  70. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/services/ontology.py +0 -0
  71. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/services/orchestration.py +0 -0
  72. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/services/project.py +0 -0
  73. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/services/resource.py +0 -0
  74. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/services/resource_role.py +0 -0
  75. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/services/space.py +0 -0
  76. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/services/sql.py +0 -0
  77. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/utils/__init__.py +0 -0
  78. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/utils/alias_resolver.py +0 -0
  79. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/utils/completion.py +0 -0
  80. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/utils/formatting.py +0 -0
  81. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/src/pltr/utils/progress.py +0 -0
  82. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/__init__.py +0 -0
  83. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/conftest.py +0 -0
  84. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/integration/README.md +0 -0
  85. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/integration/__init__.py +0 -0
  86. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/integration/conftest.py +0 -0
  87. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/integration/test_auth_flow.py +0 -0
  88. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/integration/test_cli_integration.py +0 -0
  89. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/integration/test_data_workflows.py +0 -0
  90. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/integration/test_data_workflows_simple.py +0 -0
  91. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/integration/test_simple_integration.py +0 -0
  92. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_auth/__init__.py +0 -0
  93. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_auth/test_base.py +0 -0
  94. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_auth/test_manager.py +0 -0
  95. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_auth/test_oauth.py +0 -0
  96. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_auth/test_storage.py +0 -0
  97. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_auth/test_token.py +0 -0
  98. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_commands/__init__.py +0 -0
  99. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_commands/test_admin.py +0 -0
  100. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_commands/test_alias.py +0 -0
  101. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_commands/test_completion.py +0 -0
  102. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_commands/test_connectivity.py +0 -0
  103. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_commands/test_dataset.py +0 -0
  104. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_commands/test_folder.py +0 -0
  105. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_commands/test_ontology.py +0 -0
  106. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_commands/test_orchestration.py +0 -0
  107. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_commands/test_shell.py +0 -0
  108. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_commands/test_sql.py +0 -0
  109. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_commands/test_verify_simple.py +0 -0
  110. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_config/__init__.py +0 -0
  111. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_config/test_aliases.py +0 -0
  112. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_config/test_profiles.py +0 -0
  113. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_config/test_settings.py +0 -0
  114. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_services/__init__.py +0 -0
  115. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_services/test_admin.py +0 -0
  116. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_services/test_base.py +0 -0
  117. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_services/test_connectivity.py +0 -0
  118. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_services/test_dataset.py +0 -0
  119. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_services/test_dataset_transactions.py +0 -0
  120. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_services/test_folder.py +0 -0
  121. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_services/test_ontology.py +0 -0
  122. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_services/test_orchestration.py +0 -0
  123. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_services/test_project.py +0 -0
  124. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_services/test_resource.py +0 -0
  125. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_services/test_resource_role.py +0 -0
  126. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_services/test_space.py +0 -0
  127. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_services/test_sql.py +0 -0
  128. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_utils/__init__.py +0 -0
  129. {pltr_cli-0.8.0 → pltr_cli-0.9.1}/tests/test_utils/test_alias_resolver.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pltr-cli
3
- Version: 0.8.0
3
+ Version: 0.9.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.8.0"
3
+ version = "0.9.1"
4
4
  description = "Command-line interface for Palantir Foundry APIs"
5
5
  authors = [
6
6
  { name = "anjor", email = "anjor@umd.edu" },
@@ -152,10 +152,25 @@ def check_tag_exists(version):
152
152
  return False
153
153
 
154
154
 
155
+ def update_uv_lock():
156
+ """Update uv.lock file after version change"""
157
+ try:
158
+ subprocess.run(["uv", "lock"], check=True, capture_output=True, text=True)
159
+ print("Updated uv.lock file")
160
+ return True
161
+ except subprocess.CalledProcessError as e:
162
+ print(f"Error updating uv.lock: {e.stderr}")
163
+ return False
164
+ except FileNotFoundError:
165
+ print("Warning: uv command not found. Skipping uv.lock update.")
166
+ print("Please ensure uv is installed to keep lock file in sync.")
167
+ return False
168
+
169
+
155
170
  def create_release_commit_and_tag(version, release_type, push_mode="ask"):
156
171
  """Create release commit and tag"""
157
172
  # Stage the version file changes
158
- run_git_command("git add pyproject.toml src/pltr/__init__.py")
173
+ run_git_command("git add pyproject.toml src/pltr/__init__.py uv.lock")
159
174
 
160
175
  # Create release commit
161
176
  commit_message = f"{release_type}: Release version {version}"
@@ -308,9 +323,10 @@ def main():
308
323
  print("\nDry run mode - would perform these actions:")
309
324
  print(f"1. Update pyproject.toml version to {new_version}")
310
325
  print(f"2. Update src/pltr/__init__.py __version__ to {new_version}")
311
- print(f"3. Create git commit: '{release_type}: Release version {new_version}'")
312
- print(f"4. Create git tag: v{new_version}")
313
- print("5. Optionally push to origin")
326
+ print("3. Update uv.lock file")
327
+ print(f"4. Create git commit: '{release_type}: Release version {new_version}'")
328
+ print(f"5. Create git tag: v{new_version}")
329
+ print("6. Optionally push to origin")
314
330
  return
315
331
 
316
332
  # Check git status
@@ -335,13 +351,14 @@ def main():
335
351
  print("This will:")
336
352
  print(f"1. Update pyproject.toml version to {new_version}")
337
353
  print(f"2. Update src/pltr/__init__.py __version__ to {new_version}")
338
- print(f"3. Create git commit and tag v{new_version}")
354
+ print("3. Update uv.lock file")
355
+ print(f"4. Create git commit and tag v{new_version}")
339
356
  if args.push:
340
- print("4. Push to origin to trigger GitHub Actions publishing")
357
+ print("5. Push to origin to trigger GitHub Actions publishing")
341
358
  elif args.no_push:
342
- print("4. NOT push to origin (--no-push specified)")
359
+ print("5. NOT push to origin (--no-push specified)")
343
360
  else:
344
- print("4. Optionally push to trigger GitHub Actions publishing")
361
+ print("5. Optionally push to trigger GitHub Actions publishing")
345
362
 
346
363
  if not args.yes:
347
364
  confirm = input("\nProceed with release? (y/N): ").strip().lower()
@@ -362,6 +379,7 @@ def main():
362
379
  # Perform release
363
380
  update_version_in_pyproject(new_version)
364
381
  update_version_in_init_py(new_version)
382
+ update_uv_lock() # Update uv.lock with new version
365
383
  create_release_commit_and_tag(new_version, release_type, push_mode)
366
384
 
367
385
  print(f"\n✅ Release {new_version} created successfully!")
@@ -0,0 +1 @@
1
+ __version__ = "0.9.1"
@@ -93,11 +93,17 @@ def get_schema(
93
93
  None, "--output", "-o", help="Output file path"
94
94
  ),
95
95
  ):
96
- """Get the schema of a dataset."""
96
+ """Get the schema of a dataset (requires API preview access)."""
97
97
  try:
98
98
  cache_rid(dataset_rid)
99
99
  service = DatasetService(profile=profile)
100
100
 
101
+ formatter.print_warning(
102
+ "Note: This command requires API preview access. "
103
+ "If you encounter an 'ApiFeaturePreviewUsageOnly' error, "
104
+ "use 'pltr dataset schema apply' instead to infer/apply schema."
105
+ )
106
+
101
107
  with SpinnerProgressTracker().track_spinner(
102
108
  f"Fetching schema for {dataset_rid}..."
103
109
  ):
@@ -120,7 +126,54 @@ def get_schema(
120
126
  formatter.print_error(f"Authentication error: {e}")
121
127
  raise typer.Exit(1)
122
128
  except Exception as e:
123
- formatter.print_error(f"Failed to get schema: {e}")
129
+ if "ApiFeaturePreviewUsageOnly" in str(e):
130
+ formatter.print_error(
131
+ "This command requires API preview access. "
132
+ "Please use 'pltr dataset schema apply' instead."
133
+ )
134
+ else:
135
+ formatter.print_error(f"Failed to get schema: {e}")
136
+ raise typer.Exit(1)
137
+
138
+
139
+ @schema_app.command("apply")
140
+ def apply_schema(
141
+ dataset_rid: str = typer.Argument(
142
+ ..., help="Dataset Resource Identifier", autocompletion=complete_rid
143
+ ),
144
+ branch: str = typer.Option("master", "--branch", "-b", help="Dataset branch name"),
145
+ profile: Optional[str] = typer.Option(
146
+ None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
147
+ ),
148
+ format: str = typer.Option(
149
+ "table",
150
+ "--format",
151
+ "-f",
152
+ help="Output format (table, json, csv)",
153
+ autocompletion=complete_output_format,
154
+ ),
155
+ ):
156
+ """Apply/infer schema for a dataset."""
157
+ try:
158
+ cache_rid(dataset_rid)
159
+ service = DatasetService(profile=profile)
160
+
161
+ with SpinnerProgressTracker().track_spinner(
162
+ f"Applying schema to dataset {dataset_rid} on branch '{branch}'..."
163
+ ):
164
+ result = service.apply_schema(dataset_rid, branch)
165
+
166
+ formatter.print_success(f"Schema applied successfully to branch '{branch}'")
167
+
168
+ # Display result if available
169
+ if result.get("result"):
170
+ formatter._format_json(result.get("result"))
171
+
172
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
173
+ formatter.print_error(f"Authentication error: {e}")
174
+ raise typer.Exit(1)
175
+ except Exception as e:
176
+ formatter.print_error(f"Failed to apply schema: {e}")
124
177
  raise typer.Exit(1)
125
178
 
126
179
 
@@ -0,0 +1,129 @@
1
+ """
2
+ Base service class for Foundry API wrappers.
3
+ """
4
+
5
+ from typing import Any, Optional, Dict
6
+ from abc import ABC, abstractmethod
7
+ import requests
8
+
9
+ from ..auth.manager import AuthManager
10
+ from ..auth.storage import CredentialStorage
11
+ from ..config.profiles import ProfileManager
12
+
13
+
14
+ class BaseService(ABC):
15
+ """Base class for Foundry service wrappers."""
16
+
17
+ def __init__(self, profile: Optional[str] = None):
18
+ """
19
+ Initialize base service.
20
+
21
+ Args:
22
+ profile: Authentication profile name (uses default if not specified)
23
+ """
24
+ self.profile = profile
25
+ self.auth_manager = AuthManager()
26
+ self._client: Optional[Any] = None
27
+
28
+ @property
29
+ def client(self) -> Any:
30
+ """
31
+ Get authenticated Foundry client.
32
+
33
+ Returns:
34
+ Configured FoundryClient instance
35
+
36
+ Raises:
37
+ ProfileNotFoundError: If profile doesn't exist
38
+ MissingCredentialsError: If credentials are incomplete
39
+ """
40
+ if self._client is None:
41
+ self._client = self.auth_manager.get_client(self.profile)
42
+ return self._client
43
+
44
+ @abstractmethod
45
+ def _get_service(self) -> Any:
46
+ """
47
+ Get the specific Foundry SDK service instance.
48
+
49
+ Returns:
50
+ Configured service instance from foundry-platform-sdk
51
+
52
+ This method should be implemented by subclasses to return the
53
+ appropriate service (e.g., client.datasets, client.ontology)
54
+ """
55
+ pass
56
+
57
+ @property
58
+ def service(self) -> Any:
59
+ """
60
+ Get the Foundry SDK service instance.
61
+
62
+ Returns:
63
+ Configured service instance
64
+ """
65
+ return self._get_service()
66
+
67
+ def _make_request(
68
+ self,
69
+ method: str,
70
+ endpoint: str,
71
+ data: Optional[Dict] = None,
72
+ json_data: Optional[Dict] = None,
73
+ headers: Optional[Dict] = None,
74
+ ) -> requests.Response:
75
+ """
76
+ Make a direct HTTP request to Foundry API.
77
+
78
+ Args:
79
+ method: HTTP method (GET, POST, PUT, DELETE)
80
+ endpoint: API endpoint path (e.g., '/foundry-schema-inference/api/...')
81
+ data: Form data to send
82
+ json_data: JSON data to send
83
+ headers: Additional headers
84
+
85
+ Returns:
86
+ Response object
87
+
88
+ Raises:
89
+ requests.HTTPError: If request fails
90
+ """
91
+ # Get credentials for authentication
92
+ storage = CredentialStorage()
93
+ profile_manager = ProfileManager()
94
+ profile_name = self.profile or profile_manager.get_active_profile()
95
+ if not profile_name:
96
+ from ..auth.base import ProfileNotFoundError
97
+
98
+ raise ProfileNotFoundError(
99
+ "No profile specified and no default profile configured. "
100
+ "Run 'pltr configure configure' to set up authentication."
101
+ )
102
+ credentials = storage.get_profile(profile_name)
103
+
104
+ # Build full URL
105
+ host = credentials.get("host", "").rstrip("/")
106
+ url = f"{host}{endpoint}"
107
+
108
+ # Set up headers with authentication
109
+ request_headers = {
110
+ "Authorization": f"Bearer {credentials.get('token')}",
111
+ "Content-Type": "application/json",
112
+ "Accept": "application/json",
113
+ }
114
+ if headers:
115
+ request_headers.update(headers)
116
+
117
+ # Make the request
118
+ response = requests.request(
119
+ method=method,
120
+ url=url,
121
+ data=data,
122
+ json=json_data,
123
+ headers=request_headers,
124
+ )
125
+
126
+ # Raise an error for bad status codes
127
+ response.raise_for_status()
128
+
129
+ return response
@@ -56,6 +56,61 @@ class DatasetService(BaseService):
56
56
  except Exception as e:
57
57
  raise RuntimeError(f"Failed to get schema for dataset {dataset_rid}: {e}")
58
58
 
59
+ def apply_schema(self, dataset_rid: str, branch: str = "master") -> Dict[str, Any]:
60
+ """
61
+ Apply/infer schema for a dataset using both schema inference and metadata APIs.
62
+
63
+ This method performs two sequential API calls:
64
+ 1. Schema inference to infer the dataset schema
65
+ 2. Schema application to apply the inferred schema to the dataset
66
+
67
+ Args:
68
+ dataset_rid: Dataset Resource Identifier
69
+ branch: Dataset branch name (default: "master")
70
+
71
+ Returns:
72
+ Schema application result including transaction and version information
73
+ """
74
+ try:
75
+ # Step 1: Call schema inference API to infer the schema
76
+ inference_endpoint = f"/foundry-schema-inference/api/datasets/{dataset_rid}/branches/{branch}/schema"
77
+ inference_response = self._make_request(
78
+ "POST", inference_endpoint, json_data={}
79
+ )
80
+
81
+ # Parse the inference response
82
+ inference_result = (
83
+ inference_response.json() if inference_response.text else {}
84
+ )
85
+
86
+ # Extract the foundry schema from the inference result
87
+ foundry_schema = inference_result.get("data", {}).get("foundrySchema")
88
+ if not foundry_schema:
89
+ raise RuntimeError(
90
+ "Schema inference failed: No foundrySchema found in response"
91
+ )
92
+
93
+ # Step 2: Call foundry-metadata API to apply the schema
94
+ metadata_endpoint = f"/foundry-metadata/api/schemas/datasets/{dataset_rid}/branches/{branch}"
95
+ metadata_response = self._make_request(
96
+ "POST", metadata_endpoint, json_data=foundry_schema
97
+ )
98
+
99
+ # Parse the metadata response
100
+ metadata_result = metadata_response.json() if metadata_response.text else {}
101
+
102
+ return {
103
+ "dataset_rid": dataset_rid,
104
+ "branch": branch,
105
+ "status": "Schema applied successfully",
106
+ "inference_result": inference_result,
107
+ "application_result": metadata_result,
108
+ "transaction_rid": metadata_result.get("transactionRid"),
109
+ "version_id": metadata_result.get("versionId"),
110
+ }
111
+ except Exception as e:
112
+ raise RuntimeError(f"Failed to apply schema for dataset {dataset_rid}: {e}")
113
+
59
114
  def put_schema(
60
115
  self,
61
116
  dataset_rid: str,
@@ -710,7 +710,7 @@ wheels = [
710
710
 
711
711
  [[package]]
712
712
  name = "pltr-cli"
713
- version = "0.8.0"
713
+ version = "0.9.1"
714
714
  source = { editable = "." }
715
715
  dependencies = [
716
716
  { name = "click-repl" },
@@ -1 +0,0 @@
1
- __version__ = "0.8.0"
@@ -1,62 +0,0 @@
1
- """
2
- Base service class for Foundry API wrappers.
3
- """
4
-
5
- from typing import Any, Optional
6
- from abc import ABC, abstractmethod
7
-
8
- from ..auth.manager import AuthManager
9
-
10
-
11
- class BaseService(ABC):
12
- """Base class for Foundry service wrappers."""
13
-
14
- def __init__(self, profile: Optional[str] = None):
15
- """
16
- Initialize base service.
17
-
18
- Args:
19
- profile: Authentication profile name (uses default if not specified)
20
- """
21
- self.profile = profile
22
- self.auth_manager = AuthManager()
23
- self._client: Optional[Any] = None
24
-
25
- @property
26
- def client(self) -> Any:
27
- """
28
- Get authenticated Foundry client.
29
-
30
- Returns:
31
- Configured FoundryClient instance
32
-
33
- Raises:
34
- ProfileNotFoundError: If profile doesn't exist
35
- MissingCredentialsError: If credentials are incomplete
36
- """
37
- if self._client is None:
38
- self._client = self.auth_manager.get_client(self.profile)
39
- return self._client
40
-
41
- @abstractmethod
42
- def _get_service(self) -> Any:
43
- """
44
- Get the specific Foundry SDK service instance.
45
-
46
- Returns:
47
- Configured service instance from foundry-platform-sdk
48
-
49
- This method should be implemented by subclasses to return the
50
- appropriate service (e.g., client.datasets, client.ontology)
51
- """
52
- pass
53
-
54
- @property
55
- def service(self) -> Any:
56
- """
57
- Get the Foundry SDK service instance.
58
-
59
- Returns:
60
- Configured service instance
61
- """
62
- return self._get_service()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes