salesforce-data-customcode 6.0.5.dev1__py3-none-any.whl → 6.0.6.dev2__py3-none-any.whl

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.
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: salesforce-data-customcode
3
- Version: 6.0.5.dev1
3
+ Version: 6.0.6.dev2
4
4
  Summary: Data Cloud Custom Code SDK
5
5
  License-Expression: Apache-2.0
6
6
  License-File: LICENSE.txt
7
7
  Requires-Python: >=3.10,<3.12
8
- Classifier: Development Status :: 4 - Beta
8
+ Classifier: Development Status :: 5 - Production/Stable
9
9
  Classifier: Operating System :: Unix
10
10
  Classifier: Programming Language :: Python
11
11
  Classifier: Programming Language :: Python :: 3
@@ -23,7 +23,7 @@ Requires-Dist: salesforce-cdp-connector (>=1.0.19)
23
23
  Requires-Dist: setuptools_scm (>=7.1.0,<8.0.0)
24
24
  Description-Content-Type: text/markdown
25
25
 
26
- # Data Cloud Custom Code SDK (BETA)
26
+ # Data Cloud Custom Code SDK
27
27
 
28
28
  This package provides a development kit for creating custom data transformations in [Data Cloud](https://www.salesforce.com/data/). It allows you to write your own data processing logic in Python while leveraging Data Cloud's infrastructure for data access and running data transformations, mapping execution into Data Cloud data structures like [Data Model Objects](https://help.salesforce.com/s/articleView?id=data.c360_a_data_model_objects.htm&type=5) and [Data Lake Objects](https://help.salesforce.com/s/articleView?id=sf.c360_a_data_lake_objects.htm&language=en_US&type=5).
29
29
 
@@ -36,7 +36,7 @@ Use of this project with Salesforce is subject to the [TERMS OF USE](./TERMS_OF_
36
36
  - **Python 3.11 only** (currently supported version - if your system version is different, we recommend using [pyenv](https://github.com/pyenv/pyenv) to configure 3.11)
37
37
  - JDK 17
38
38
  - Docker support like [Docker Desktop](https://docs.docker.com/desktop/)
39
- - A salesforce org with some DLOs or DMOs with data and this feature enabled (it is not GA)
39
+ - A salesforce org with some DLOs or DMOs with data and this feature enabled
40
40
  - **One of the following** for authentication:
41
41
  - A Salesforce org already authenticated via the [Salesforce CLI](https://developer.salesforce.com/tools/salesforcecli)
42
42
  (simplest — no External Client App needed)
@@ -116,7 +116,7 @@ After modifying the `entrypoint.py` as needed, using any dependencies you add in
116
116
  ```zsh
117
117
  cd my_package
118
118
  datacustomcode scan ./payload/entrypoint.py
119
- datacustomcode deploy --path ./payload --name my_custom_script --cpu-size CPU_L
119
+ datacustomcode deploy --path ./payload --name my_custom_script --cpu-size CPU_L --sf-cli-org myorg
120
120
  ```
121
121
 
122
122
  > [!TIP]
@@ -170,15 +170,22 @@ Your Python dependencies can be packaged as .py files, .zip archives (containing
170
170
 
171
171
  ## API
172
172
 
173
- Your entry point script will define logic using the `Client` object which wraps data access layers.
173
+ Your entry point script will define logic using the `Client` object (for batch transforms) or the `StreamingClient` object (for streaming delta transforms), which wrap the data access layers. Both are singletons; a single transform should use one or the other, not both.
174
174
 
175
- You should only need the following methods:
175
+ For a batch transform, use `Client`. You should only need the following methods:
176
176
  * `find_file_path(file_name)` – Resolve a bundled file (placed under `payload/files/`) to a `pathlib.Path` that exists. Works the same locally and inside Data Cloud — see [Bundled file resolution](#bundled-file-resolution) below for the full lookup order. Raises `FileNotFoundError` if the file isn't found.
177
177
  * `read_dlo(name)` – Read from a Data Lake Object by name
178
178
  * `read_dmo(name)` – Read from a Data Model Object by name
179
179
  * `write_to_dlo(name, spark_dataframe, write_mode)` – Write to a Data Model Object by name with a Spark dataframe
180
180
  * `write_to_dmo(name, spark_dataframe, write_mode)` – Write to a Data Lake Object by name with a Spark dataframe
181
181
 
182
+ For a streaming (delta) transform, use `StreamingClient`, which exposes the streaming counterparts:
183
+ * `read_dlo_deltas()` – Read the streaming change feed (deltas) of a Data Lake Object as a streaming DataFrame.
184
+ * `read_dmo_deltas()` – Read the streaming change feed (deltas) of a Data Model Object as a streaming DataFrame.
185
+ * `write_dlo_deltas(name, spark_dataframe)` – Write a streaming DataFrame of deltas to a Data Lake Object; returns the started `StreamingQuery`
186
+
187
+ `find_file_path`, `llm_gateway_generate_text`, and `einstein_predict` are available on both clients.
188
+
182
189
  For example:
183
190
  ```python
184
191
  from datacustomcode import Client
@@ -194,6 +201,36 @@ client.write_to_dlo('output_DLO')
194
201
  > [!WARNING]
195
202
  > Currently we only support reading from DMOs and writing to DMOs or reading from DLOs and writing to DLOs, but they cannot mix.
196
203
 
204
+ ### Streaming (delta) transforms
205
+
206
+ Streaming BYOC transforms process a Data Lake Object's Change Data Feed continuously instead of reading a bounded snapshot. Use a `StreamingClient` and its `*_deltas` methods in place of the batch `Client` read/write methods:
207
+
208
+ ```python
209
+ from pyspark.sql.functions import col, upper
210
+
211
+ from datacustomcode import StreamingClient
212
+
213
+ client = StreamingClient()
214
+
215
+ # read_dlo_deltas returns a *streaming* DataFrame over the change feed.
216
+ # The runtime resolves the single streaming source, so no name is passed.
217
+ deltas = client.read_dlo_deltas()
218
+
219
+ # Ordinary PySpark transform.
220
+ transformed = deltas.withColumn("description__c", upper(col("description__c")))
221
+
222
+ # write_dlo_deltas starts a streaming query and returns the StreamingQuery.
223
+ # The runtime owns the trigger and checkpoint location; you
224
+ # choose only the target table.
225
+ query = client.write_dlo_deltas("Output__dll", transformed)
226
+ query.awaitTermination()
227
+ ```
228
+
229
+ Notes:
230
+
231
+ - These methods only run inside the Data Cloud streaming (`DELTA_SYNC`) runtime. Locally (`datacustomcode run`) they raise `NotImplementedError`, since there is no change feed to stream.
232
+ - A complete runnable entry point is provided in [`examples/streaming_deltas/entrypoint.py`](src/datacustomcode/templates/script/examples/streaming_deltas/entrypoint.py).
233
+
197
234
  ### Bundled file resolution
198
235
 
199
236
  Place bundled files (CSVs, prompt files, etc.) under `payload/files/`. The same `client.find_file_path("data.csv")` call resolves consistently across all three runtimes:
@@ -345,6 +382,7 @@ Options:
345
382
  - `--description TEXT`: Description of the transformation job (default: "")
346
383
  - `--network TEXT`: docker network (default: "default")
347
384
  - `--cpu-size TEXT`: CPU size for the deployment (default: `CPU_2XL`). Available options: CPU_L(Large), CPU_XL(Extra Large), CPU_2XL(2X Large), CPU_4XL(4X Large)
385
+ - `--sf-cli-org TEXT`: Salesforce CLI org alias or username (e.g. `myorg`). Fetches credentials via `sf org display` — no `datacustomcode configure` step needed. Takes precedence over `--profile` if both are supplied.
348
386
  - `--function-invoke-opt TEXT`: Currently we support only `UnstructuredChunking` for functions.
349
387
 
350
388
 
@@ -397,6 +435,56 @@ datacustomcode run ./payload/entrypoint.py --sf-cli-org myorg
397
435
  ```
398
436
 
399
437
 
438
+ ## Testing Einstein Predictions
439
+
440
+ You can use AI models configured in Einstein Studio to score your data while
441
+ transforming it. As with the LLM Gateway, there are two flavors: a one-shot
442
+ scalar call (`client.einstein_predict`) and a per-row column helper
443
+ (`einstein_predict_col`). Below is a sample code example:
444
+
445
+ ```
446
+ from datacustomcode.client import Client, einstein_predict_col
447
+ from datacustomcode.einstein_predictions.types import PredictionType
448
+
449
+
450
+ def main():
451
+ client = Client()
452
+ df = client.read_dlo("Input__dll")
453
+ # einstein_predict_col returns a struct
454
+ # {status, response, error_code, error_message} per row, so per-row
455
+ # failures don't abort the Spark job. `response` is the prediction
456
+ # payload as a JSON string. Pick the field you want with [].
457
+ df_scored = df.withColumn(
458
+ "prediction__c",
459
+ einstein_predict_col(
460
+ "my_regression_model", # An AI model in your org
461
+ PredictionType.REGRESSION,
462
+ {"square_feet": col("square_feet__c"), "beds": col("beds__c")},
463
+ )["response"],
464
+ )
465
+
466
+ dlo_name = "Output_dll"
467
+ client.write_to_dlo(dlo_name, df_scored, write_mode=WriteMode.APPEND)
468
+
469
+ # One-shot scalar prediction returns the response payload as a dict
470
+ prediction = client.einstein_predict(
471
+ "my_regression_model",
472
+ PredictionType.REGRESSION,
473
+ {"square_feet": 1800, "beds": 3},
474
+ )
475
+
476
+ if __name__ == "__main__":
477
+ main()
478
+ ```
479
+
480
+ Testing this code locally uses the same External Client App setup described in
481
+ [Testing LLM Gateway](#testing-llm-gateway). Once your `myorg` alias is set up,
482
+ run:
483
+ ```
484
+ datacustomcode run ./payload/entrypoint.py --sf-cli-org myorg
485
+ ```
486
+
487
+
400
488
  ## Docker usage
401
489
 
402
490
  The SDK provides Docker-based development options that allow you to test your code in an environment that closely resembles Data Cloud's execution environment.
@@ -508,7 +596,7 @@ sf --version
508
596
  **Browser-based (recommended for developer orgs and sandboxes):**
509
597
  ```zsh
510
598
  # Production / Developer Edition
511
- sf org login web --alias myorg
599
+ sf org login web --alias myorg --instance-url <your-instance-url>
512
600
 
513
601
  # Sandbox
514
602
  sf org login web --alias mysandbox --instance-url https://test.salesforce.com
@@ -1,21 +1,24 @@
1
- datacustomcode/__init__.py,sha256=qx-X3U9lU_791ZbAxhGqQeyDw6eqTi9-E9AbYnwJfxU,2071
1
+ datacustomcode/__init__.py,sha256=5vvWRk5gb2mZIaVZ9BSPRL45uKSUwmSerxhLp6A4Q-4,2815
2
2
  datacustomcode/auth.py,sha256=fpSjhIBdv9trC8yq2vuljAix_Euu-4Ah7HDCGhYjOxI,8309
3
3
  datacustomcode/cli.py,sha256=i7hPoQqJskTmx3Odz2wVgkxBnf_PFaIawI12FXhaRUE,13264
4
- datacustomcode/client.py,sha256=fc3JmDbAFcTT-yP_k_0jNiGqNp_KwZaIpEsI-NPxNcw,15115
4
+ datacustomcode/client.py,sha256=jcJrIzOiWxqsjQL-ghSNyCjHsCCOKTin_pquX5ng5bg,24406
5
5
  datacustomcode/cmd.py,sha256=ZMs46aydJw2EaU26JgCtZmnqESQFHvvaJz10hnjZTBk,3537
6
6
  datacustomcode/common_config.py,sha256=SAUnxj3kqmOeWwPmFoYq4tuxokMgURVm4QwcGi-avL4,1928
7
- datacustomcode/config.py,sha256=2Pk61ieQsEWSxKDxlS66_rliKE8iX0j-9LweEm0aaGo,4072
8
- datacustomcode/config.yaml,sha256=Wd8Zd2f1__hRv7166H5IBbU5YoOEOdQNHgAb4ONbFnA,845
7
+ datacustomcode/config.py,sha256=lqed3jcWfoIweikSFZelaAoyBa0cXXScL8O6vaqdeRU,4372
8
+ datacustomcode/config.yaml,sha256=ldssmQYPghmYSSPaelm3F2mC99njavhrWsINRSzWymM,933
9
9
  datacustomcode/constants.py,sha256=SskQpUPnQE7LjKh4Z3AdZ2p191_0Kf73jV8gdBXDPLU,1436
10
10
  datacustomcode/credentials.py,sha256=D-7Zd3Nh_wStdj8_wUy5cnC8M_mdbfBijhIAi-2EbXs,9467
11
11
  datacustomcode/deploy.py,sha256=TZ6L4VrAnL-SlmAUMbEYguVpCgOm_Ncv8NdaBR3LX4Y,21906
12
12
  datacustomcode/einstein_platform_client.py,sha256=ON2B_m--vdbCVVMVcLc81T-BRZ5-UuxVCer8E6OEQPA,4083
13
13
  datacustomcode/einstein_platform_config.py,sha256=6lb_FRbEzdt5a8-2cR15f13ZKw674uvRJ4Xq0o_pQXE,1490
14
- datacustomcode/einstein_predictions/__init__.py,sha256=o-iask36phwGA7hGi_sxJpwbITO6h_STDe0J92qD2_M,859
14
+ datacustomcode/einstein_predictions/__init__.py,sha256=_RIDTqcEHDRu6AsCsj9lRBykNkHI8Ch8JBILL1ioPtA,1237
15
15
  datacustomcode/einstein_predictions/base.py,sha256=OBV445dpZRtCF5cpdHH49w_6RU_jZY1A-e7VtHTQCFU,1061
16
+ datacustomcode/einstein_predictions/errors.py,sha256=EoxVU5Mf14AIAyVBedI1JnbsS_o853kY-iMA1u-KPcw,1224
16
17
  datacustomcode/einstein_predictions/impl/default.py,sha256=fEFhrosozhG0yT87w4Gu8wbe1NgHxBqdAduwWHdWGN4,3011
18
+ datacustomcode/einstein_predictions/spark_base.py,sha256=MnFH2-pJ7ugFnc9iUvCdMt1vPAPAmiImptjjIGh9bvo,2567
19
+ datacustomcode/einstein_predictions/spark_default.py,sha256=tYL6u1DY3Ogu8xF7o1VqXqTGrcP2VUUMI6BShjXWvns,8119
17
20
  datacustomcode/einstein_predictions/types.py,sha256=W7H3sFzm_NdBtnia7O576w0OvM7jwzfGVQmFiZTO8Og,6098
18
- datacustomcode/einstein_predictions_config.py,sha256=oxKgp2u7t5SdHVsasBBxsvd3KAfXuZ9uQXTrtpcCUlU,2135
21
+ datacustomcode/einstein_predictions_config.py,sha256=7zUot5fUnXiihiu_9NStvk0-e9Otv55-Xk7dKqrMfBY,3758
19
22
  datacustomcode/file/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
20
23
  datacustomcode/file/base.py,sha256=2IUlQufPvpHccgyoeZlKhcktO4pS4NKdha03Whq33Zk,745
21
24
  datacustomcode/file/path/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
@@ -29,12 +32,12 @@ datacustomcode/function_utils.py,sha256=y6vaoSSaJ9CeHhjLCNyqzJT4vx6yCePWRxNLz38d
29
32
  datacustomcode/io/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
30
33
  datacustomcode/io/base.py,sha256=gbwZWWVUbCbGR4jIg_4h4qOz8tOMjE4RDTleD23WFKo,973
31
34
  datacustomcode/io/reader/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
32
- datacustomcode/io/reader/base.py,sha256=JRKg8KfEPJGR58wqicsEdpAPiXTl2K1eV3eHQyxYWaE,1390
35
+ datacustomcode/io/reader/base.py,sha256=2hAqaZvzHvvr5KBEgQSjUrHpidcHkgUXXTbGQG-b8io,3176
33
36
  datacustomcode/io/reader/query_api.py,sha256=eVrohrcnTnhSMsGfPRHu5XltjFtGG0hyHt1o4q1hp2w,9340
34
37
  datacustomcode/io/reader/sf_cli.py,sha256=x5QacVqRZaZSyph1_wwxo67s8r29wsOcUsOaiF9cDWE,6324
35
38
  datacustomcode/io/reader/utils.py,sha256=HlHhPZoHfmWA3mF8kTnd3m4Nd2exaz4NsOJJfQY7Pew,1656
36
39
  datacustomcode/io/writer/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
37
- datacustomcode/io/writer/base.py,sha256=6e2Yszb6BiuN1zCV2rjvZ5CQ0YikQdUgdYAkutoy9pE,1787
40
+ datacustomcode/io/writer/base.py,sha256=LtyOtkcEsX3oQZ-2zWFeNutVae1T3ialbGbvwl-7spU,3246
38
41
  datacustomcode/io/writer/csv.py,sha256=asty5teBpNQ1fMGHZ7wA3suLhq0sk0lVQPN5x7TOSRk,1555
39
42
  datacustomcode/io/writer/print.py,sha256=0g2sP_1Wb95UIyEELWJt3dqM18Iv_CWhDW3mDxcIhns,5105
40
43
  datacustomcode/llm_gateway/__init__.py,sha256=rcoGpSkv36tZuAOcTxKkhNpM0qV03qgmer_ej07Vmfc,1088
@@ -51,7 +54,7 @@ datacustomcode/llm_gateway/types/generate_text_response_builder.py,sha256=6MV6JZ
51
54
  datacustomcode/llm_gateway_config.py,sha256=ECm9CFqOFOaLHwenvVFAjiRSzG9Eg9fY4pb8nHbQ34c,3312
52
55
  datacustomcode/mixin.py,sha256=ZtROqO1W1_D7MV8lw4cw6zzcchJLoZS0aAiXrolYR4k,4914
53
56
  datacustomcode/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
- datacustomcode/run.py,sha256=2v-oJGnIq_vbJrlXANXgOg0UZlYgDxZ90UksAqPtFAg,7775
57
+ datacustomcode/run.py,sha256=Ky58Di6Nh7gk6Ic-5Jxt3Y4xB3vRNmzlUcoSlK-OLvo,8169
55
58
  datacustomcode/scan.py,sha256=Zb9mE733H_xaqyDI-LZjjnIcctMC9j1AaD_kcr9qTh4,14325
56
59
  datacustomcode/spark/__init__.py,sha256=12drVVlRiczCxOQw-EzuGtLsikCM8baBXvDEgwvelCI,860
57
60
  datacustomcode/spark/base.py,sha256=tlGqM4LxuLoDa7OxJF5nVeb7phO5uvD1DHBQeH7NMMs,1036
@@ -85,15 +88,16 @@ datacustomcode/templates/script/account.ipynb,sha256=LIbxgiVxflNASdspF2lfpMKkKAT
85
88
  datacustomcode/templates/script/build_native_dependencies.sh,sha256=ICRrp4f1ATBwPaUiuVGjY-MwiubFswNJLf8gMGU6YNg,197
86
89
  datacustomcode/templates/script/examples/employee_hierarchy/employee_data.csv,sha256=C7ggLBfoyi3M2BdMLNyOeKqF-5OO-Da76lkwgWg2cVQ,302
87
90
  datacustomcode/templates/script/examples/employee_hierarchy/entrypoint.py,sha256=Mfm3iQtEHTQRW6cmZTwRKdTh3IeGWR-teXrd6x-YLSY,2223
91
+ datacustomcode/templates/script/examples/streaming_deltas/entrypoint.py,sha256=1PpYyZck2j9IRTnoI-kfHbMf21vN8gA49_-qJr3rDjk,1984
88
92
  datacustomcode/templates/script/jupyterlab.sh,sha256=IHR3YQ8d_busuyvesByhJgzCKULIFPI-Hqogs0NPhCs,2432
89
93
  datacustomcode/templates/script/payload/config.json,sha256=0d2mEMt4NHIeOUTsgiPMuRKdOLIQxmh-Wq-IfEqU-gc,28
90
- datacustomcode/templates/script/payload/entrypoint.py,sha256=bLUhC4l03H-OQJKdMf11vGXmBnga6QitRXo-g9HibZg,1741
94
+ datacustomcode/templates/script/payload/entrypoint.py,sha256=4Uph0ILa5ukk_6C90paK3uzQn0zZvNLr9ho3o_ZwErQ,2474
91
95
  datacustomcode/templates/script/requirements-dev.txt,sha256=OWwuy1awesqOZOS3Zizmdd6BDnSePpGFN5bq5IrALvc,176
92
96
  datacustomcode/templates/script/requirements.txt,sha256=qJbqzs5z0Hrx590U3T7dHq_m8UQEx2TdhgrJSz-QHIQ,40
93
97
  datacustomcode/token_provider.py,sha256=kGPxdxGZEr6VFknW7jFb9P6wOvRaRo-sfdBN2cUjEZY,6792
94
98
  datacustomcode/version.py,sha256=9LlbVrzwBvut1L308QbwNBgxdQk5CrghH39JARVSxms,989
95
- salesforce_data_customcode-6.0.5.dev1.dist-info/METADATA,sha256=cypaTObtj1EVWAfVu58VEbxHgDIiai_VYcJqHjZNFqo,23234
96
- salesforce_data_customcode-6.0.5.dev1.dist-info/WHEEL,sha256=eY7nduwzv-ldUxpzbRlxwvC693Hg6PX8bWDjEHjZ_dk,88
97
- salesforce_data_customcode-6.0.5.dev1.dist-info/entry_points.txt,sha256=WpQ94UB7UuRCYGOLtJV3vAgm1tl7iVf43VYRWIuNu5Y,74
98
- salesforce_data_customcode-6.0.5.dev1.dist-info/licenses/LICENSE.txt,sha256=iOi8EmQpfkFhMENi7VYtkl2EqS14pEOccoXHiW2dyPU,11443
99
- salesforce_data_customcode-6.0.5.dev1.dist-info/RECORD,,
99
+ salesforce_data_customcode-6.0.6.dev2.dist-info/METADATA,sha256=ELHH1XxE3sqqmAIfVmKuO1fxn3XpSTH7XaRbZ4VQBuA,27207
100
+ salesforce_data_customcode-6.0.6.dev2.dist-info/WHEEL,sha256=eY7nduwzv-ldUxpzbRlxwvC693Hg6PX8bWDjEHjZ_dk,88
101
+ salesforce_data_customcode-6.0.6.dev2.dist-info/entry_points.txt,sha256=WpQ94UB7UuRCYGOLtJV3vAgm1tl7iVf43VYRWIuNu5Y,74
102
+ salesforce_data_customcode-6.0.6.dev2.dist-info/licenses/LICENSE.txt,sha256=iOi8EmQpfkFhMENi7VYtkl2EqS14pEOccoXHiW2dyPU,11443
103
+ salesforce_data_customcode-6.0.6.dev2.dist-info/RECORD,,