salesforce-data-customcode 0.1.23__tar.gz → 0.1.25__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.
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/PKG-INFO +1 -1
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/pyproject.toml +1 -1
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/cli.py +30 -13
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/deploy.py +86 -2
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/run.py +4 -2
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/LICENSE.txt +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/README.md +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/__init__.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/auth.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/client.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/cmd.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/config.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/config.yaml +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/credentials.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/file/__init__.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/file/base.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/file/path/__init__.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/file/path/default.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/io/__init__.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/io/base.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/io/reader/__init__.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/io/reader/base.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/io/reader/query_api.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/io/reader/sf_cli.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/io/reader/utils.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/io/writer/__init__.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/io/writer/base.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/io/writer/csv.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/io/writer/print.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/mixin.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/proxy/__init__.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/proxy/base.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/proxy/client/LocalProxyClientProvider.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/proxy/client/__init__.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/proxy/client/base.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/py.typed +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/scan.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/spark/__init__.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/spark/base.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/spark/default.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/template.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/function/.devcontainer/devcontainer.json +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/function/Dockerfile +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/function/Dockerfile.dependencies +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/function/README.md +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/function/account.ipynb +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/function/build_native_dependencies.sh +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/function/examples/employee_hierarchy/employee_data.csv +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/function/examples/employee_hierarchy/entrypoint.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/function/jupyterlab.sh +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/function/payload/config.json +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/function/payload/entrypoint.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/function/requirements-dev.txt +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/function/requirements.txt +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/script/.devcontainer/devcontainer.json +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/script/Dockerfile +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/script/Dockerfile.dependencies +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/script/README.md +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/script/account.ipynb +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/script/build_native_dependencies.sh +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/script/examples/employee_hierarchy/employee_data.csv +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/script/examples/employee_hierarchy/entrypoint.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/script/jupyterlab.sh +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/script/payload/config.json +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/script/payload/entrypoint.py +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/script/requirements-dev.txt +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/templates/script/requirements.txt +0 -0
- {salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/version.py +0 -0
{salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/cli.py
RENAMED
|
@@ -160,6 +160,11 @@ def zip(path: str, network: str):
|
|
|
160
160
|
Choose based on your workload requirements.""",
|
|
161
161
|
)
|
|
162
162
|
@click.option("--function-invoke-opt")
|
|
163
|
+
@click.option(
|
|
164
|
+
"--sf-cli-org",
|
|
165
|
+
default=None,
|
|
166
|
+
help="SF CLI org alias or username. Fetches credentials via `sf org display`.",
|
|
167
|
+
)
|
|
163
168
|
def deploy(
|
|
164
169
|
path: str,
|
|
165
170
|
name: str,
|
|
@@ -169,15 +174,19 @@ def deploy(
|
|
|
169
174
|
profile: str,
|
|
170
175
|
network: str,
|
|
171
176
|
function_invoke_opt: str,
|
|
177
|
+
sf_cli_org: Optional[str],
|
|
172
178
|
):
|
|
173
179
|
from datacustomcode.credentials import Credentials
|
|
174
|
-
from datacustomcode.deploy import
|
|
180
|
+
from datacustomcode.deploy import (
|
|
181
|
+
COMPUTE_TYPES,
|
|
182
|
+
AccessTokenResponse,
|
|
183
|
+
CodeExtensionMetadata,
|
|
184
|
+
_retrieve_access_token_from_sf_cli,
|
|
185
|
+
deploy_full,
|
|
186
|
+
)
|
|
175
187
|
|
|
176
188
|
logger.debug("Deploying project")
|
|
177
189
|
|
|
178
|
-
# Validate compute type
|
|
179
|
-
from datacustomcode.deploy import COMPUTE_TYPES
|
|
180
|
-
|
|
181
190
|
if cpu_size not in COMPUTE_TYPES.keys():
|
|
182
191
|
click.secho(
|
|
183
192
|
f"Error: Invalid CPU size '{cpu_size}'. "
|
|
@@ -208,15 +217,23 @@ def deploy(
|
|
|
208
217
|
function_invoke_options = function_invoke_opt.split(",")
|
|
209
218
|
metadata.functionInvokeOptions = function_invoke_options
|
|
210
219
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
fg="red"
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
+
auth: Union[Credentials, AccessTokenResponse]
|
|
221
|
+
if sf_cli_org:
|
|
222
|
+
try:
|
|
223
|
+
auth = _retrieve_access_token_from_sf_cli(sf_cli_org)
|
|
224
|
+
except RuntimeError as e:
|
|
225
|
+
click.secho(f"Error: {e}", fg="red")
|
|
226
|
+
raise click.Abort() from None
|
|
227
|
+
else:
|
|
228
|
+
try:
|
|
229
|
+
auth = Credentials.from_available(profile=profile)
|
|
230
|
+
except ValueError as e:
|
|
231
|
+
click.secho(
|
|
232
|
+
f"Error: {e}",
|
|
233
|
+
fg="red",
|
|
234
|
+
)
|
|
235
|
+
raise click.Abort() from None
|
|
236
|
+
deploy_full(path, metadata, auth, network)
|
|
220
237
|
|
|
221
238
|
|
|
222
239
|
@cli.command()
|
{salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/deploy.py
RENAMED
|
@@ -17,7 +17,9 @@ from __future__ import annotations
|
|
|
17
17
|
from html import unescape
|
|
18
18
|
import json
|
|
19
19
|
import os
|
|
20
|
+
import re
|
|
20
21
|
import shutil
|
|
22
|
+
import subprocess
|
|
21
23
|
import tempfile
|
|
22
24
|
import time
|
|
23
25
|
from typing import (
|
|
@@ -57,6 +59,19 @@ COMPUTE_TYPES = {
|
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
|
|
62
|
+
def _sanitize_api_name(name: str) -> str:
|
|
63
|
+
"""Sanitize an API name to comply with Salesforce naming rules.
|
|
64
|
+
|
|
65
|
+
Replaces spaces and hyphens with underscores, removes invalid characters,
|
|
66
|
+
collapses consecutive underscores, and strips leading/trailing underscores.
|
|
67
|
+
"""
|
|
68
|
+
sanitized = re.sub(r"[ \-]", "_", name)
|
|
69
|
+
sanitized = re.sub(r"[^\w]", "", sanitized)
|
|
70
|
+
sanitized = re.sub(r"_+", "_", sanitized)
|
|
71
|
+
sanitized = sanitized.strip("_")
|
|
72
|
+
return sanitized
|
|
73
|
+
|
|
74
|
+
|
|
60
75
|
class CodeExtensionMetadata(BaseModel):
|
|
61
76
|
name: str
|
|
62
77
|
version: str
|
|
@@ -66,6 +81,24 @@ class CodeExtensionMetadata(BaseModel):
|
|
|
66
81
|
functionInvokeOptions: Union[list[str], None] = None
|
|
67
82
|
|
|
68
83
|
def __init__(self, **data):
|
|
84
|
+
name = data.get("name", "")
|
|
85
|
+
sanitized = _sanitize_api_name(name)
|
|
86
|
+
if sanitized != name:
|
|
87
|
+
logger.warning(f"API name '{name}' was sanitized to '{sanitized}'")
|
|
88
|
+
data["name"] = sanitized
|
|
89
|
+
if not sanitized:
|
|
90
|
+
raise ValueError(
|
|
91
|
+
f"API name '{name}' is invalid and could not be sanitized to a"
|
|
92
|
+
" valid name."
|
|
93
|
+
)
|
|
94
|
+
if not sanitized[0].isalpha():
|
|
95
|
+
raise ValueError(
|
|
96
|
+
f"API name '{sanitized}' must begin with a letter. "
|
|
97
|
+
"The name can only contain underscores and alphanumeric"
|
|
98
|
+
" characters, must begin with a letter, not include spaces,"
|
|
99
|
+
" not end with an underscore, and not contain two consecutive"
|
|
100
|
+
" underscores."
|
|
101
|
+
)
|
|
69
102
|
super().__init__(**data)
|
|
70
103
|
|
|
71
104
|
|
|
@@ -156,6 +189,54 @@ def _retrieve_access_token(credentials: Credentials) -> AccessTokenResponse:
|
|
|
156
189
|
return AccessTokenResponse(**response)
|
|
157
190
|
|
|
158
191
|
|
|
192
|
+
def _retrieve_access_token_from_sf_cli(sf_cli_org: str) -> AccessTokenResponse:
|
|
193
|
+
"""Get an access token from the Salesforce CLI."""
|
|
194
|
+
try:
|
|
195
|
+
result = subprocess.run(
|
|
196
|
+
["sf", "org", "display", "--target-org", sf_cli_org, "--json"],
|
|
197
|
+
capture_output=True,
|
|
198
|
+
text=True,
|
|
199
|
+
check=True,
|
|
200
|
+
timeout=30,
|
|
201
|
+
)
|
|
202
|
+
except FileNotFoundError as exc:
|
|
203
|
+
raise RuntimeError(
|
|
204
|
+
"The 'sf' command was not found. "
|
|
205
|
+
"Please install Salesforce CLI: https://developer.salesforce.com/tools/salesforcecli"
|
|
206
|
+
) from exc
|
|
207
|
+
except subprocess.TimeoutExpired as exc:
|
|
208
|
+
raise RuntimeError(
|
|
209
|
+
f"'sf org display' timed out for org '{sf_cli_org}'"
|
|
210
|
+
) from exc
|
|
211
|
+
except subprocess.CalledProcessError as exc:
|
|
212
|
+
raise RuntimeError(
|
|
213
|
+
f"'sf org display' failed for org '{sf_cli_org}'.\n"
|
|
214
|
+
f"Ensure the org is authenticated via 'sf org login web'.\n"
|
|
215
|
+
f"stderr: {exc.stderr.strip()}"
|
|
216
|
+
) from exc
|
|
217
|
+
|
|
218
|
+
try:
|
|
219
|
+
data = json.loads(result.stdout)
|
|
220
|
+
except json.JSONDecodeError as exc:
|
|
221
|
+
raise RuntimeError(f"Failed to parse 'sf org display' output: {exc}") from exc
|
|
222
|
+
|
|
223
|
+
if data.get("status") != 0:
|
|
224
|
+
raise RuntimeError(
|
|
225
|
+
f"SF CLI error for org '{sf_cli_org}': "
|
|
226
|
+
f"{data.get('message', 'unknown error')}"
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
org_result = data.get("result", {})
|
|
230
|
+
access_token = org_result.get("accessToken")
|
|
231
|
+
instance_url = org_result.get("instanceUrl")
|
|
232
|
+
if not access_token or not instance_url:
|
|
233
|
+
raise RuntimeError(
|
|
234
|
+
f"'sf org display' did not return an access token or instance URL "
|
|
235
|
+
f"for org '{sf_cli_org}'"
|
|
236
|
+
)
|
|
237
|
+
return AccessTokenResponse(access_token=access_token, instance_url=instance_url)
|
|
238
|
+
|
|
239
|
+
|
|
159
240
|
class CreateDeploymentResponse(BaseModel):
|
|
160
241
|
fileUploadUrl: str
|
|
161
242
|
|
|
@@ -463,12 +544,15 @@ def zip(
|
|
|
463
544
|
def deploy_full(
|
|
464
545
|
directory: str,
|
|
465
546
|
metadata: CodeExtensionMetadata,
|
|
466
|
-
credentials: Credentials,
|
|
547
|
+
credentials: Union["Credentials", AccessTokenResponse],
|
|
467
548
|
docker_network: str,
|
|
468
549
|
callback=None,
|
|
469
550
|
) -> AccessTokenResponse:
|
|
470
551
|
"""Deploy a data transform in the DataCloud."""
|
|
471
|
-
|
|
552
|
+
if isinstance(credentials, AccessTokenResponse):
|
|
553
|
+
access_token = credentials
|
|
554
|
+
else:
|
|
555
|
+
access_token = _retrieve_access_token(credentials)
|
|
472
556
|
|
|
473
557
|
# prepare payload
|
|
474
558
|
config = get_config(directory)
|
{salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/run.py
RENAMED
|
@@ -25,7 +25,7 @@ from typing import (
|
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
from datacustomcode.config import config
|
|
28
|
-
from datacustomcode.scan import get_package_type
|
|
28
|
+
from datacustomcode.scan import find_base_directory, get_package_type
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
def _set_config_option(config_obj, key: str, value: str) -> None:
|
|
@@ -68,7 +68,9 @@ def run_entrypoint(
|
|
|
68
68
|
f"config.json not found at {config_json_path}. config.json is required."
|
|
69
69
|
)
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
# SDK config (.datacustomcode_proj/sdk_config.json) is under project root
|
|
72
|
+
base_directory = find_base_directory(entrypoint)
|
|
73
|
+
package_type = get_package_type(base_directory)
|
|
72
74
|
|
|
73
75
|
try:
|
|
74
76
|
with open(config_json_path, "r") as f:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/auth.py
RENAMED
|
File without changes
|
{salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/client.py
RENAMED
|
File without changes
|
{salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/cmd.py
RENAMED
|
File without changes
|
{salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/config.py
RENAMED
|
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
|
|
File without changes
|
{salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/mixin.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/py.typed
RENAMED
|
File without changes
|
{salesforce_data_customcode-0.1.23 → salesforce_data_customcode-0.1.25}/src/datacustomcode/scan.py
RENAMED
|
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
|
|
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
|