truefoundry 0.10.2rc1__py3-none-any.whl → 0.10.4__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.

Potentially problematic release.


This version of truefoundry might be problematic. Click here for more details.

@@ -94,7 +94,6 @@ class AskClient:
94
94
  """Generate authorization headers for connecting to the SSE server."""
95
95
  return {
96
96
  "Authorization": f"Bearer {self.token}",
97
- "X-TFY-Cluster-Id": self.cluster,
98
97
  "X-TFY-Session-Id": self._session_id,
99
98
  }
100
99
 
@@ -317,6 +316,10 @@ class AskClient:
317
316
  turn += 1
318
317
  message = response.choices[0].message
319
318
 
319
+ if not message.content and not message.tool_calls:
320
+ self._log_message("No assistant response. Try again.", log=True)
321
+ break
322
+
320
323
  if message.content:
321
324
  self._append_message(
322
325
  ChatCompletionAssistantMessageParam(
@@ -327,8 +330,7 @@ class AskClient:
327
330
  if message.tool_calls:
328
331
  await self._handle_tool_calls(message, spinner)
329
332
 
330
- if not message.content and not message.tool_calls:
331
- self._log_message("No assistant response.")
333
+ if message.content and not message.tool_calls:
332
334
  break
333
335
  except Exception as e:
334
336
  self._log_message(f"OpenAI call failed: {e}", log=True)
@@ -402,10 +404,16 @@ class AskClient:
402
404
 
403
405
  async def chat_loop(self):
404
406
  """Interactive loop: accepts user queries and returns responses until interrupted or 'exit' is typed."""
407
+ self._append_message(
408
+ ChatCompletionUserMessageParam(
409
+ role="user",
410
+ content=f"Selected cluster: {self.cluster}",
411
+ )
412
+ )
405
413
  self._append_message(
406
414
  ChatCompletionAssistantMessageParam(
407
415
  role="assistant",
408
- content="Hello! How can I help you with your Kubernetes cluster?",
416
+ content="Hello! How can I help you with this Kubernetes cluster?",
409
417
  )
410
418
  )
411
419
 
truefoundry/cli/util.py CHANGED
@@ -109,7 +109,7 @@ def print_dict_as_table_panel(
109
109
  ):
110
110
  table = Table(show_header=False, box=None)
111
111
  table.add_column("Key", style=f"bold {key_color}", width=15)
112
- table.add_column("Value")
112
+ table.add_column("Value", overflow="fold")
113
113
  for key, value in dct.items():
114
114
  table.add_row(key, value)
115
115
  console.print(
@@ -118,6 +118,7 @@ from truefoundry.deploy.v2.lib.patched_models import (
118
118
  SparkImageBuild,
119
119
  SparkJobJavaEntrypoint,
120
120
  SparkJobPythonEntrypoint,
121
+ SparkJobPythonNotebookEntrypoint,
121
122
  SparkJobScalaEntrypoint,
122
123
  SQSInputConfig,
123
124
  SQSOutputConfig,
@@ -1,6 +1,6 @@
1
1
  # generated by datamodel-codegen:
2
2
  # filename: application.json
3
- # timestamp: 2025-06-09T12:01:27+00:00
3
+ # timestamp: 2025-06-18T21:24:37+00:00
4
4
 
5
5
  from __future__ import annotations
6
6
 
@@ -908,7 +908,7 @@ class SparkImageBuild(BaseModel):
908
908
  None,
909
909
  description="FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
910
910
  )
911
- build_source: GitSource
911
+ build_source: Union[GitSource, RemoteSource] = Field(..., description="")
912
912
  build_spec: SparkBuild
913
913
 
914
914
 
@@ -936,6 +936,14 @@ class SparkJobPythonEntrypoint(BaseModel):
936
936
  )
937
937
 
938
938
 
939
+ class SparkJobPythonNotebookEntrypoint(BaseModel):
940
+ type: Literal["python-notebook"] = Field(..., description="")
941
+ main_application_file: str = Field(
942
+ ...,
943
+ description="The main application file to be executed by the spark job. Relative path in case of git repository.",
944
+ )
945
+
946
+
939
947
  class SparkJobScalaEntrypoint(BaseModel):
940
948
  type: Literal["scala"] = Field(..., description="")
941
949
  main_application_file: str = Field(
@@ -1449,7 +1457,10 @@ class SparkJob(BaseModel):
1449
1457
  description="The image to use for driver and executors. Must have spark installed. Spark version must match the version in the image.",
1450
1458
  )
1451
1459
  entrypoint: Union[
1452
- SparkJobPythonEntrypoint, SparkJobScalaEntrypoint, SparkJobJavaEntrypoint
1460
+ SparkJobPythonEntrypoint,
1461
+ SparkJobScalaEntrypoint,
1462
+ SparkJobJavaEntrypoint,
1463
+ SparkJobPythonNotebookEntrypoint,
1453
1464
  ] = Field(..., description="")
1454
1465
  driver_config: SparkDriverConfig
1455
1466
  executor_config: SparkExecutorConfig
@@ -31,6 +31,11 @@ def execute_notebook(notebook_path, output_path="/tmp/output.ipynb", parameters=
31
31
  parameters=parameters,
32
32
  # TODO(gw): Replace with kernel name for venv
33
33
  kernel_name="python3",
34
+ # Log cell by cell execution output
35
+ # TODO(gw): Output logs to a file instead, so that they aren't merged with the container's logs
36
+ log_output=True,
37
+ stdout_file=sys.stdout,
38
+ stderr_file=sys.stderr,
34
39
  )
35
40
  print(f"Successfully executed notebook: {notebook_path}")
36
41
 
@@ -2,12 +2,13 @@ import ast
2
2
  import io
3
3
  import json
4
4
  import re
5
- from typing import Dict, List, Optional
5
+ from typing import Any, Callable, Dict, List, Optional
6
6
 
7
7
  from rich.console import Console
8
8
  from rich.pretty import pprint
9
9
 
10
10
  from truefoundry.deploy import Application, LocalSource
11
+ from truefoundry.pydantic_v1 import BaseModel
11
12
 
12
13
 
13
14
  def generate_deployment_code(
@@ -16,7 +17,7 @@ def generate_deployment_code(
16
17
  spec_repr: str,
17
18
  workspace_fqn: str,
18
19
  ):
19
- symbols = ",".join(symbols_to_import)
20
+ symbols = ", ".join(symbols_to_import)
20
21
  application_type = application_type.replace(" ", "").replace("-", "_")
21
22
  code = f"""\
22
23
  import logging
@@ -71,7 +72,7 @@ def remove_none_type_fields(code):
71
72
 
72
73
  def remove_type_field(code):
73
74
  lines = code.split("\n")
74
- new_lines = [re.sub(r'^[ \t]*type=[\'"][^"]*[\'"],', "", line) for line in lines]
75
+ new_lines = [re.sub(r'^[ \t]*type=[\'"][^"]*[\'"],?', "", line) for line in lines]
75
76
  return "\n".join(new_lines)
76
77
 
77
78
 
@@ -102,7 +103,7 @@ def add_local_source_comment(code):
102
103
  return "\n".join(new_lines)
103
104
 
104
105
 
105
- def convert_deployment_config_to_python(workspace_fqn: str, application_spec: dict):
106
+ def _convert_deployment_config_to_python(workspace_fqn: str, application_spec: dict):
106
107
  """
107
108
  Convert a deployment config to a python file that can be used to deploy to a workspace
108
109
  """
@@ -142,6 +143,49 @@ def convert_deployment_config_to_python(workspace_fqn: str, application_spec: di
142
143
  return generated_code
143
144
 
144
145
 
146
+ def _default_exclude_fn(model: BaseModel, name: str) -> bool:
147
+ return False
148
+
149
+
150
+ def convert_deployment_config_to_python(
151
+ workspace_fqn: str,
152
+ application_spec: Dict[str, Any],
153
+ exclude_fn: Callable[[BaseModel, str], bool] = _default_exclude_fn,
154
+ exclude_unset: bool = False,
155
+ exclude_defaults: bool = False,
156
+ ):
157
+ original_repr_args = BaseModel.__repr_args__
158
+
159
+ def _patched_repr_args(self: BaseModel):
160
+ _missing = object()
161
+ pairs = []
162
+ for name, value in original_repr_args(self):
163
+ if name is not None:
164
+ if exclude_fn(self, name):
165
+ continue
166
+ if exclude_unset and name not in self.__fields_set__:
167
+ continue
168
+ model_field = self.__fields__.get(name)
169
+ if model_field is None:
170
+ continue
171
+ if (
172
+ exclude_defaults
173
+ and not getattr(model_field, "required", True)
174
+ and getattr(model_field, "default", _missing) == value
175
+ ):
176
+ continue
177
+ pairs.append((name, value))
178
+ return pairs
179
+
180
+ try:
181
+ BaseModel.__repr_args__ = _patched_repr_args
182
+ return _convert_deployment_config_to_python(
183
+ workspace_fqn=workspace_fqn, application_spec=application_spec
184
+ )
185
+ finally:
186
+ BaseModel.__repr_args__ = original_repr_args
187
+
188
+
145
189
  def generate_python_snippet_for_trigger_job(
146
190
  application_fqn: str, command: Optional[str], params: Optional[Dict[str, str]]
147
191
  ):
@@ -520,3 +520,9 @@ class SparkJobPythonEntrypoint(models.SparkJobPythonEntrypoint, PatchedModelBase
520
520
 
521
521
  class SparkJobJavaEntrypoint(models.SparkJobJavaEntrypoint, PatchedModelBase):
522
522
  type: Literal["java"] = "java"
523
+
524
+
525
+ class SparkJobPythonNotebookEntrypoint(
526
+ models.SparkJobPythonNotebookEntrypoint, PatchedModelBase
527
+ ):
528
+ type: Literal["python-notebook"] = "python-notebook"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: truefoundry
3
- Version: 0.10.2rc1
3
+ Version: 0.10.4
4
4
  Summary: TrueFoundry CLI
5
5
  Author-email: TrueFoundry Team <abhishek@truefoundry.com>
6
6
  Requires-Python: <3.14,>=3.8.1
@@ -30,7 +30,7 @@ Requires-Dist: requirements-parser<0.12.0,>=0.11.0
30
30
  Requires-Dist: rich-click<2.0.0,>=1.2.1
31
31
  Requires-Dist: rich<14.0.0,>=13.7.1
32
32
  Requires-Dist: tqdm<5.0.0,>=4.0.0
33
- Requires-Dist: truefoundry-sdk<0.2.0,>=0.1.1
33
+ Requires-Dist: truefoundry-sdk<0.2.0,>=0.1.3
34
34
  Requires-Dist: typing-extensions>=4.0
35
35
  Requires-Dist: urllib3<3,>=1.26.18
36
36
  Requires-Dist: yq<4.0.0,>=3.1.0
@@ -5,7 +5,7 @@ truefoundry/pydantic_v1.py,sha256=jSuhGtz0Mbk1qYu8jJ1AcnIDK4oxUsdhALc4spqstmM,34
5
5
  truefoundry/version.py,sha256=bqiT4Q-VWrTC6P4qfK43mez-Ppf-smWfrl6DcwV7mrw,137
6
6
  truefoundry/_ask/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  truefoundry/_ask/cli.py,sha256=zPaDvxhX2dITmPTtut2Iu6WAIaizrwR-U_dDZ6xv2io,5814
8
- truefoundry/_ask/client.py,sha256=4vWO04jWbSF0XD3q8DwXjvL4HW-WBg7nsQ0DydNwHmM,18479
8
+ truefoundry/_ask/client.py,sha256=QWQRiDwmtIlLaZsyGcLZaQstYFzpmJeCRdATMapjL-8,18740
9
9
  truefoundry/_ask/llm_utils.py,sha256=ayjz7JtVu142lrm8t0cVoxLxUpx76b71y8R62z_WurY,13537
10
10
  truefoundry/autodeploy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  truefoundry/autodeploy/cli.py,sha256=9ZxKu_MGIpraMzaW4ZyuQZhlKIQYE3biBrBV4S1h6Fo,14167
@@ -37,7 +37,7 @@ truefoundry/cli/config.py,sha256=f7z0_gmYZiNImB7Bxz0AnOlrxY2X4lFnX4jYW1I7NHQ,139
37
37
  truefoundry/cli/console.py,sha256=9-dMy4YPisCJQziRKTg8Qa0UJnOGl1soiUnJjsnLDvE,242
38
38
  truefoundry/cli/const.py,sha256=dVHPo1uAiDSSMXwXoT2mR5kNQjExT98QNVRz98Hz_Ts,510
39
39
  truefoundry/cli/display_util.py,sha256=9vzN3mbQqU6OhS7qRUiMRana4PTHa4sDTA0Hn7OVjCI,3108
40
- truefoundry/cli/util.py,sha256=pezUfF2GC6ru7s8VeH2a7uvXTU0xN9ka7yLXkIgC3dY,4998
40
+ truefoundry/cli/util.py,sha256=sSKFZ5wGkForoRIiKD2gFlMyj9D1iinzdjQtMYJx8oU,5015
41
41
  truefoundry/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
42
  truefoundry/common/auth_service_client.py,sha256=N3YxKlx63r6cPZqbgb2lqBOPI69ShB7D7RCIq4FSCjc,7949
43
43
  truefoundry/common/constants.py,sha256=nWd3Je71WmHEORRUTCupZy5fWADqEFftjYP6wiYhCIc,4627
@@ -52,9 +52,9 @@ truefoundry/common/storage_provider_utils.py,sha256=yURhMw8k0FLFvaviRHDiifhvc6Gn
52
52
  truefoundry/common/types.py,sha256=BMJFCsR1lPJAw66IQBSvLyV4I6o_x5oj78gVsUa9si8,188
53
53
  truefoundry/common/utils.py,sha256=j3QP0uOsaGD_VmDDR68JTwoYE1okkAq6OqpVkzVf48Q,6424
54
54
  truefoundry/common/warnings.py,sha256=rs6BHwk7imQYedo07iwh3TWEOywAR3Lqhj0AY4khByg,504
55
- truefoundry/deploy/__init__.py,sha256=2GNbI8IGJBotz_IKaqQ-DWYWZn_pSu7lN7aId15Gk7Q,2799
56
- truefoundry/deploy/python_deploy_codegen.py,sha256=AainOFR20XvhNeztJkLPWGZ40lAT_nwc-ZmG77Kum4o,6525
57
- truefoundry/deploy/_autogen/models.py,sha256=xt-DuaRDx5jeRwyGoQH2yyPZAep9Q2MHFW9XBuRzG8E,73161
55
+ truefoundry/deploy/__init__.py,sha256=PVbGPU9S3-dTFn5LvLwaEnfsp2RrGT9iiM7_15kOV84,2837
56
+ truefoundry/deploy/python_deploy_codegen.py,sha256=k19_m5DGsUyjOUCSKwIVP8vDna2sq01tHABsUfoVpW4,8019
57
+ truefoundry/deploy/_autogen/models.py,sha256=8j_y0Yp8k8Sjj7iVtZDHeuxq9kDvD0xI8-iFnbf0370,73571
58
58
  truefoundry/deploy/builder/__init__.py,sha256=kgvlkVkiWpMVdim81tIeLrdoACqrFDgwCqHdQVsCsMo,4988
59
59
  truefoundry/deploy/builder/constants.py,sha256=amUkHoHvVKzGv0v_knfiioRuKiJM0V0xW0diERgWiI0,508
60
60
  truefoundry/deploy/builder/docker_service.py,sha256=sm7GWeIqyrKaZpxskdLejZlsxcZnM3BTDJr6orvPN4E,3948
@@ -67,7 +67,7 @@ truefoundry/deploy/builder/builders/tfy_python_buildpack/__init__.py,sha256=_fjq
67
67
  truefoundry/deploy/builder/builders/tfy_python_buildpack/dockerfile_template.py,sha256=f4l3fH21E2b8W3-JotMKc0AdPcCxV7LRPxxYJa7z_UQ,9134
68
68
  truefoundry/deploy/builder/builders/tfy_spark_buildpack/__init__.py,sha256=NEPlM6_vTVxp4ITa18B8DBbgYCn1q5d8be21lbgu5oY,2888
69
69
  truefoundry/deploy/builder/builders/tfy_spark_buildpack/dockerfile_template.py,sha256=dAmWgAHcNdBLSedpz18r5r7n9hdXKV-PB7yFPMdaoww,5990
70
- truefoundry/deploy/builder/builders/tfy_spark_buildpack/tfy_execute_notebook.py,sha256=Orib09GBfAwQukt5wV_jyxL-fw_dWsuIqQ5TyTST188,1738
70
+ truefoundry/deploy/builder/builders/tfy_spark_buildpack/tfy_execute_notebook.py,sha256=PKJWNlW76dRw_XtFkRnqpzwBGuXU4w6_kIJkgoBmZ5Q,1975
71
71
  truefoundry/deploy/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
72
72
  truefoundry/deploy/cli/commands/__init__.py,sha256=qv818jxqSAygJ3h-6Ul8t-5VOgR_UrSgsVtNCl3e5G0,1408
73
73
  truefoundry/deploy/cli/commands/apply_command.py,sha256=DmXmKVokkauyKIiJDtErTwbJ5_LvQeJbTQsG5BjyKpo,2427
@@ -117,7 +117,7 @@ truefoundry/deploy/v2/lib/deploy.py,sha256=HfSUdAS3gSpFAFtV0Mq9LscfpkaXqA2LHW4VX
117
117
  truefoundry/deploy/v2/lib/deploy_workflow.py,sha256=G5BzMIbap8pgDX1eY-TITruUxQdkKhYtBmRwLL6lDeY,14342
118
118
  truefoundry/deploy/v2/lib/deployable_patched_models.py,sha256=mUi-OjPf7bc8rzfrPLdFb79LKuDq7F36RxL4V-AXebs,6830
119
119
  truefoundry/deploy/v2/lib/models.py,sha256=ogc1UYs1Z2nBdGSKCrde9sk8d0GxFKMkem99uqO5CmM,1148
120
- truefoundry/deploy/v2/lib/patched_models.py,sha256=VkfS7akbUzMA4q15lQUcAirdTsyVE1rfMeCmjXJC6Zk,15394
120
+ truefoundry/deploy/v2/lib/patched_models.py,sha256=oNsOr5ojVn2XHjATD3VLuuO6w_ljDL99siHXy6y3Y0g,15558
121
121
  truefoundry/deploy/v2/lib/source.py,sha256=d6-8_6Zn5koBglqrBrY6ZLG_7yyPuLdyEmK4iZTw6xY,9405
122
122
  truefoundry/ml/__init__.py,sha256=EEEHV7w58Krpo_W9Chd8Y3TdItfFO3LI6j6Izqc4-P8,2219
123
123
  truefoundry/ml/constants.py,sha256=vDq72d4C9FSWqr9MMdjgTF4TuyNFApvo_6RVsSeAjB4,2837
@@ -381,7 +381,7 @@ truefoundry/workflow/remote_filesystem/__init__.py,sha256=LQ95ViEjJ7Ts4JcCGOxMPs
381
381
  truefoundry/workflow/remote_filesystem/logger.py,sha256=em2l7D6sw7xTLDP0kQSLpgfRRCLpN14Qw85TN7ujQcE,1022
382
382
  truefoundry/workflow/remote_filesystem/tfy_signed_url_client.py,sha256=xcT0wQmQlgzcj0nP3tJopyFSVWT1uv3nhiTIuwfXYeg,12342
383
383
  truefoundry/workflow/remote_filesystem/tfy_signed_url_fs.py,sha256=nSGPZu0Gyd_jz0KsEE-7w_BmnTD8CVF1S8cUJoxaCbc,13305
384
- truefoundry-0.10.2rc1.dist-info/METADATA,sha256=bvv_QGYYNpuoOuzv6fiFP7NQDSgk3CYKlGa_UgfthNs,2508
385
- truefoundry-0.10.2rc1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
386
- truefoundry-0.10.2rc1.dist-info/entry_points.txt,sha256=xVjn7RMN-MW2-9f7YU-bBdlZSvvrwzhpX1zmmRmsNPU,98
387
- truefoundry-0.10.2rc1.dist-info/RECORD,,
384
+ truefoundry-0.10.4.dist-info/METADATA,sha256=WrMuchpPgh57vtJ90hAo2hLj6bkILIbkD0SWTzJ29I4,2505
385
+ truefoundry-0.10.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
386
+ truefoundry-0.10.4.dist-info/entry_points.txt,sha256=xVjn7RMN-MW2-9f7YU-bBdlZSvvrwzhpX1zmmRmsNPU,98
387
+ truefoundry-0.10.4.dist-info/RECORD,,