truefoundry 0.3.0rc7__py3-none-any.whl → 0.3.0rc9__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.
- truefoundry/deploy/__init__.py +1 -9
- truefoundry/deploy/auto_gen/models.py +51 -191
- truefoundry/deploy/builder/__init__.py +2 -4
- truefoundry/deploy/builder/builders/tfy_notebook_buildpack/__init__.py +7 -5
- truefoundry/deploy/builder/builders/tfy_notebook_buildpack/dockerfile_template.py +34 -19
- truefoundry/deploy/cli/commands/deploy_command.py +6 -3
- truefoundry/deploy/cli/commands/patch_application_command.py +2 -0
- truefoundry/deploy/v2/lib/deploy.py +52 -1
- truefoundry/deploy/v2/lib/deploy_workflow.py +130 -10
- truefoundry/deploy/v2/lib/deployable_patched_models.py +3 -1
- truefoundry/deploy/v2/lib/patched_models.py +0 -36
- truefoundry/version.py +3 -1
- truefoundry/workflow/__init__.py +1 -1
- truefoundry/workflow/example/hello_world_package/workflow.py +3 -2
- truefoundry/workflow/example/package/test_workflow.py +29 -8
- truefoundry/workflow/example/truefoundry.yaml +1 -1
- truefoundry/workflow/workflow.py +62 -2
- {truefoundry-0.3.0rc7.dist-info → truefoundry-0.3.0rc9.dist-info}/METADATA +2 -1
- {truefoundry-0.3.0rc7.dist-info → truefoundry-0.3.0rc9.dist-info}/RECORD +21 -21
- {truefoundry-0.3.0rc7.dist-info → truefoundry-0.3.0rc9.dist-info}/WHEEL +0 -0
- {truefoundry-0.3.0rc7.dist-info → truefoundry-0.3.0rc9.dist-info}/entry_points.txt +0 -0
truefoundry/deploy/__init__.py
CHANGED
|
@@ -6,6 +6,7 @@ from truefoundry.deploy.auto_gen.models import (
|
|
|
6
6
|
Kustomize,
|
|
7
7
|
ParamType,
|
|
8
8
|
Protocol,
|
|
9
|
+
WorkbenchImage,
|
|
9
10
|
)
|
|
10
11
|
from truefoundry.deploy.lib.dao.application import (
|
|
11
12
|
delete_application,
|
|
@@ -56,14 +57,10 @@ from truefoundry.deploy.v2.lib.patched_models import (
|
|
|
56
57
|
BlueGreen,
|
|
57
58
|
Build,
|
|
58
59
|
Canary,
|
|
59
|
-
CodeserverImage,
|
|
60
60
|
CoreNATSOutputConfig,
|
|
61
61
|
CPUUtilizationMetric,
|
|
62
62
|
CronMetric,
|
|
63
63
|
CUDAVersion,
|
|
64
|
-
CustomCodeserverImage,
|
|
65
|
-
CustomNotebookImage,
|
|
66
|
-
CustomSSHServerImage,
|
|
67
64
|
DockerFileBuild,
|
|
68
65
|
DynamicVolumeConfig,
|
|
69
66
|
Endpoint,
|
|
@@ -104,15 +101,10 @@ from truefoundry.deploy.v2.lib.patched_models import (
|
|
|
104
101
|
SQSInputConfig,
|
|
105
102
|
SQSOutputConfig,
|
|
106
103
|
SQSQueueMetricConfig,
|
|
107
|
-
SSHServerImage,
|
|
108
104
|
StaticVolumeConfig,
|
|
109
105
|
StringDataMount,
|
|
110
106
|
TPUType,
|
|
111
107
|
TruefoundryArtifactSource,
|
|
112
|
-
TruefoundryImageBase,
|
|
113
|
-
TruefoundryImageCuda1180,
|
|
114
|
-
TruefoundryImageCuda1211,
|
|
115
|
-
TruefoundryImageFull,
|
|
116
108
|
VolumeBrowser,
|
|
117
109
|
VolumeMount,
|
|
118
110
|
WorkerConfig,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# generated by datamodel-codegen:
|
|
2
2
|
# filename: application.json
|
|
3
|
-
# timestamp: 2024-
|
|
3
|
+
# timestamp: 2024-08-09T07:42:58+00:00
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
@@ -125,6 +125,13 @@ class AsyncProcessorSidecar(BaseModel):
|
|
|
125
125
|
)
|
|
126
126
|
|
|
127
127
|
|
|
128
|
+
class Autoshutdown(BaseModel):
|
|
129
|
+
wait_time: conint(ge=0) = Field(
|
|
130
|
+
300,
|
|
131
|
+
description="+label=Wait Time\n+usage=The period to wait after the last received request before scaling the replicas to 0",
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
128
135
|
class BaseAutoscaling(BaseModel):
|
|
129
136
|
min_replicas: conint(ge=0) = Field(
|
|
130
137
|
1,
|
|
@@ -138,10 +145,6 @@ class BaseAutoscaling(BaseModel):
|
|
|
138
145
|
30,
|
|
139
146
|
description="+label=Polling Interval\n+usage=This is the interval to check each trigger on.",
|
|
140
147
|
)
|
|
141
|
-
cooldown_period: conint(ge=0) = Field(
|
|
142
|
-
300,
|
|
143
|
-
description="+label=Cooldown Period\n+usage=The period to wait after the last trigger reported active before scaling the resource back to 0.",
|
|
144
|
-
)
|
|
145
148
|
|
|
146
149
|
|
|
147
150
|
class BasicAuthCreds(BaseModel):
|
|
@@ -197,26 +200,6 @@ class CanaryStep(BaseModel):
|
|
|
197
200
|
)
|
|
198
201
|
|
|
199
202
|
|
|
200
|
-
class CodeserverImage(BaseModel):
|
|
201
|
-
"""
|
|
202
|
-
+usage=Codeserver with persistent environment (Python 3.11.6)
|
|
203
|
-
"""
|
|
204
|
-
|
|
205
|
-
type: constr(regex=r"^codeserver$") = Field(..., description="+value=codeserver")
|
|
206
|
-
enable_sudo: bool = Field(
|
|
207
|
-
True,
|
|
208
|
-
description="+label=Enable root access to the container\n+usage=Changes made to the root directory `/` will not be persisted across notebook restarts",
|
|
209
|
-
)
|
|
210
|
-
apt_packages: Optional[List[str]] = Field(
|
|
211
|
-
None,
|
|
212
|
-
description='+label=List of Debian packages to install.\n+usage=Debian packages to install via `apt get`.\nIn Python/YAML E.g. ["git", "ffmpeg", "htop"]\n+placeholder=Enter a debian package name E.g. ffmpeg',
|
|
213
|
-
)
|
|
214
|
-
docker_registry: Optional[str] = Field(
|
|
215
|
-
None,
|
|
216
|
-
description="+docs=FQN of the container registry. You can the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
|
|
217
|
-
)
|
|
218
|
-
|
|
219
|
-
|
|
220
203
|
class CronMetric(BaseModel):
|
|
221
204
|
type: Literal["cron"] = Field(..., description="+value=cron")
|
|
222
205
|
desired_replicas: Optional[conint(ge=1)] = Field(
|
|
@@ -237,60 +220,6 @@ class CronMetric(BaseModel):
|
|
|
237
220
|
)
|
|
238
221
|
|
|
239
222
|
|
|
240
|
-
class CustomCodeserverImage(BaseModel):
|
|
241
|
-
"""
|
|
242
|
-
+usage=User supplied docker image URI for vscode server
|
|
243
|
-
"""
|
|
244
|
-
|
|
245
|
-
type: constr(regex=r"^customcodeserver$") = Field(
|
|
246
|
-
..., description="+value=customcodeserver"
|
|
247
|
-
)
|
|
248
|
-
image_uri: str = Field(
|
|
249
|
-
...,
|
|
250
|
-
description="+label=Image URI\n+usage=The image URI. Specify the name of the image and the tag.\nIf the image is in Dockerhub, you can skip registry-url (for e.g. `tensorflow/tensorflow`).\nYou can use an image from a private registry using Advanced fields\n+placeholder=registry-url/account/image:version",
|
|
251
|
-
)
|
|
252
|
-
docker_registry: Optional[str] = Field(
|
|
253
|
-
None,
|
|
254
|
-
description="+docs=FQN of the container registry. You can use the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
|
|
255
|
-
)
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
class CustomNotebookImage(BaseModel):
|
|
259
|
-
"""
|
|
260
|
-
+usage=User supplied docker image URI for jupyter notebook
|
|
261
|
-
"""
|
|
262
|
-
|
|
263
|
-
type: constr(regex=r"^customnotebook$") = Field(
|
|
264
|
-
..., description="+value=customnotebook"
|
|
265
|
-
)
|
|
266
|
-
image_uri: str = Field(
|
|
267
|
-
...,
|
|
268
|
-
description="+label=Image URI\n+usage=The image URI. Specify the name of the image and the tag.\nIf the image is in Dockerhub, you can skip registry-url (for e.g. `tensorflow/tensorflow`).\nYou can use an image from a private registry using Advanced fields\n+placeholder=registry-url/account/image:version",
|
|
269
|
-
)
|
|
270
|
-
docker_registry: Optional[str] = Field(
|
|
271
|
-
None,
|
|
272
|
-
description="+docs=FQN of the container registry. You can use the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
|
|
273
|
-
)
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
class CustomSSHServerImage(BaseModel):
|
|
277
|
-
"""
|
|
278
|
-
+usage=User supplied docker image URI for ssh server
|
|
279
|
-
"""
|
|
280
|
-
|
|
281
|
-
type: constr(regex=r"^custom-ssh-server$") = Field(
|
|
282
|
-
..., description="+value=custom-ssh-server"
|
|
283
|
-
)
|
|
284
|
-
image_uri: str = Field(
|
|
285
|
-
...,
|
|
286
|
-
description="+label=Image URI\n+usage=The image URI. Specify the name of the image and the tag.\nIf the image is in Dockerhub, you can skip registry-url (for e.g. `tensorflow/tensorflow`).\nYou can use an image from a private registry using Advanced fields\n+placeholder=registry-url/account/image:version",
|
|
287
|
-
)
|
|
288
|
-
docker_registry: Optional[str] = Field(
|
|
289
|
-
None,
|
|
290
|
-
description="+docs=FQN of the container registry. You can use the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
|
|
291
|
-
)
|
|
292
|
-
|
|
293
|
-
|
|
294
223
|
class DockerFileBuild(BaseModel):
|
|
295
224
|
"""
|
|
296
225
|
+docs=Describes that we are using a dockerfile to build our image
|
|
@@ -976,22 +905,6 @@ class SQSQueueMetricConfig(BaseModel):
|
|
|
976
905
|
)
|
|
977
906
|
|
|
978
907
|
|
|
979
|
-
class SSHServerImage(BaseModel):
|
|
980
|
-
"""
|
|
981
|
-
+usage=Ssh Server with persistent environment (Python 3.11.6)
|
|
982
|
-
"""
|
|
983
|
-
|
|
984
|
-
type: constr(regex=r"^ssh-server$") = Field(..., description="+value=ssh-server")
|
|
985
|
-
apt_packages: Optional[List[str]] = Field(
|
|
986
|
-
None,
|
|
987
|
-
description='+label=List of Debian packages to install.\n+usage=Debian packages to install via `apt get`.\nIn Python/YAML E.g. ["git", "ffmpeg", "htop"]\n+placeholder=Enter a debian package name E.g. ffmpeg',
|
|
988
|
-
)
|
|
989
|
-
docker_registry: Optional[str] = Field(
|
|
990
|
-
None,
|
|
991
|
-
description="+docs=FQN of the container registry. You can the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
|
|
992
|
-
)
|
|
993
|
-
|
|
994
|
-
|
|
995
908
|
class ConcurrencyPolicy(str, Enum):
|
|
996
909
|
"""
|
|
997
910
|
+usage=Choose whether to allow this job to run while another instance of the job is running, or to replace the currently running instance. Allow
|
|
@@ -1149,86 +1062,6 @@ class TruefoundryArtifactSource(BaseModel):
|
|
|
1149
1062
|
)
|
|
1150
1063
|
|
|
1151
1064
|
|
|
1152
|
-
class TruefoundryImageBase(BaseModel):
|
|
1153
|
-
"""
|
|
1154
|
-
+usage=JupyterLab with persistent python environment (Python 3.11.6)
|
|
1155
|
-
"""
|
|
1156
|
-
|
|
1157
|
-
type: constr(regex=r"^truefoundrybase$") = Field(
|
|
1158
|
-
..., description="+value=truefoundrybase"
|
|
1159
|
-
)
|
|
1160
|
-
enable_sudo: bool = Field(
|
|
1161
|
-
True,
|
|
1162
|
-
description="+label=Enable root access to the container\n+usage=Changes made to the root directory `/` will not be persisted across notebook restarts",
|
|
1163
|
-
)
|
|
1164
|
-
apt_packages: Optional[List[str]] = Field(
|
|
1165
|
-
None,
|
|
1166
|
-
description='+label=List of Debian packages to install.\n+usage=Debian packages to install via `apt get`.\nIn Python/YAML E.g. ["git", "ffmpeg", "htop"]\n+placeholder=Enter a debian package name E.g. ffmpeg',
|
|
1167
|
-
)
|
|
1168
|
-
docker_registry: Optional[str] = Field(
|
|
1169
|
-
None,
|
|
1170
|
-
description="+docs=FQN of the container registry. You can use the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
|
|
1171
|
-
)
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
class TruefoundryImageCuda1180(BaseModel):
|
|
1175
|
-
"""
|
|
1176
|
-
+usage=JupyterLab with persistent python environment (Python 3.11.6, Cuda 11.8.0)
|
|
1177
|
-
"""
|
|
1178
|
-
|
|
1179
|
-
type: constr(regex=r"^truefoundrycuda1180$") = Field(
|
|
1180
|
-
..., description="+value=truefoundrycuda1180"
|
|
1181
|
-
)
|
|
1182
|
-
apt_packages: Optional[List[str]] = Field(
|
|
1183
|
-
None,
|
|
1184
|
-
description='+label=List of Debian packages to install.\n+usage=Debian packages to install via `apt get`.\nIn Python/YAML E.g. ["git", "ffmpeg", "htop"]\n+placeholder=Enter a debian package name E.g. ffmpeg',
|
|
1185
|
-
)
|
|
1186
|
-
docker_registry: Optional[str] = Field(
|
|
1187
|
-
None,
|
|
1188
|
-
description="+docs=FQN of the container registry. You can use the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
|
|
1189
|
-
)
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
class TruefoundryImageCuda1211(BaseModel):
|
|
1193
|
-
"""
|
|
1194
|
-
+usage=JupyterLab with persistent python environment (Python 3.11.6, Cuda 12.1.1)
|
|
1195
|
-
"""
|
|
1196
|
-
|
|
1197
|
-
type: constr(regex=r"^truefoundrycuda1211$") = Field(
|
|
1198
|
-
..., description="+value=truefoundrycuda1211"
|
|
1199
|
-
)
|
|
1200
|
-
apt_packages: Optional[List[str]] = Field(
|
|
1201
|
-
None,
|
|
1202
|
-
description='+label=List of Debian packages to install.\n+usage=Debian packages to install via `apt get`.\nIn Python/YAML E.g. ["git", "ffmpeg", "htop"]\n+placeholder=Enter a debian package name E.g. ffmpeg',
|
|
1203
|
-
)
|
|
1204
|
-
docker_registry: Optional[str] = Field(
|
|
1205
|
-
None,
|
|
1206
|
-
description="+docs=FQN of the container registry. You can use the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
|
|
1207
|
-
)
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
class TruefoundryImageFull(BaseModel):
|
|
1211
|
-
"""
|
|
1212
|
-
+usage=JupyterLab + Tensorflow 2.15.0 and Pytorch 2.1.1 with persistent environment (Python 3.11.6)
|
|
1213
|
-
"""
|
|
1214
|
-
|
|
1215
|
-
type: constr(regex=r"^truefoundryfull$") = Field(
|
|
1216
|
-
..., description="+value=truefoundryfull"
|
|
1217
|
-
)
|
|
1218
|
-
enable_sudo: bool = Field(
|
|
1219
|
-
True,
|
|
1220
|
-
description="+label=Enable root access to the container\n+usage=Changes made to the root directory `/` will not be persisted across notebook restarts",
|
|
1221
|
-
)
|
|
1222
|
-
apt_packages: Optional[List[str]] = Field(
|
|
1223
|
-
None,
|
|
1224
|
-
description='+label=List of Debian packages to install.\n+usage=Debian packages to install via `apt get`.\nIn Python/YAML E.g. ["git", "ffmpeg", "htop"]\n+placeholder=Enter a debian package name E.g. ffmpeg',
|
|
1225
|
-
)
|
|
1226
|
-
docker_registry: Optional[str] = Field(
|
|
1227
|
-
None,
|
|
1228
|
-
description="+docs=FQN of the container registry. You can use the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
|
|
1229
|
-
)
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
1065
|
class VolumeBrowser(BaseModel):
|
|
1233
1066
|
"""
|
|
1234
1067
|
+label=Volume Browser
|
|
@@ -1265,6 +1098,25 @@ class VolumeMount(BaseModel):
|
|
|
1265
1098
|
)
|
|
1266
1099
|
|
|
1267
1100
|
|
|
1101
|
+
class WorkbenchImage(BaseModel):
|
|
1102
|
+
"""
|
|
1103
|
+
+usage=Workbench Image with persistent environment (Python 3.11.6)
|
|
1104
|
+
"""
|
|
1105
|
+
|
|
1106
|
+
image_uri: str = Field(
|
|
1107
|
+
...,
|
|
1108
|
+
description="+label=Image URI\n+usage=The image URI. Specify the name of the image and the tag.\nIf the image is in Dockerhub, you can skip registry-url (for e.g. `tensorflow/tensorflow`).\nYou can use an image from a private registry using Advanced fields\n+placeholder=registry-url/account/image:version",
|
|
1109
|
+
)
|
|
1110
|
+
build_script: Optional[constr(min_length=1, max_length=1024)] = Field(
|
|
1111
|
+
None,
|
|
1112
|
+
description="+label=Build Script\n+usage=The build script to run when building the image.\nThis will be executed as the last step in the docker build process as the root user (RUN DEBIAN_FRONTEND=noninteractive bash -ex build_script.sh)\n+placeholder=Enter the build script",
|
|
1113
|
+
)
|
|
1114
|
+
docker_registry: Optional[str] = Field(
|
|
1115
|
+
None,
|
|
1116
|
+
description="+docs=FQN of the container registry. You can the FQN of your desired container registry (or add one)\nin the Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
|
|
1117
|
+
)
|
|
1118
|
+
|
|
1119
|
+
|
|
1268
1120
|
class ArtifactsDownload(BaseModel):
|
|
1269
1121
|
"""
|
|
1270
1122
|
+docs=Describes the configuration for the artifacts cache
|
|
@@ -1317,6 +1169,10 @@ class BaseWorkbenchInput(BaseModel):
|
|
|
1317
1169
|
)
|
|
1318
1170
|
service_account: Optional[str] = Field(None, description="+sort=10113")
|
|
1319
1171
|
kustomize: Optional[Kustomize] = None
|
|
1172
|
+
workspace_fqn: Optional[str] = Field(
|
|
1173
|
+
None,
|
|
1174
|
+
description="+label=Workspace FQN\n+docs=Fully qualified name of the workspace\n+uiType=Hidden",
|
|
1175
|
+
)
|
|
1320
1176
|
|
|
1321
1177
|
|
|
1322
1178
|
class Build(BaseModel):
|
|
@@ -1361,9 +1217,7 @@ class Codeserver(BaseWorkbenchInput):
|
|
|
1361
1217
|
"""
|
|
1362
1218
|
|
|
1363
1219
|
type: constr(regex=r"^codeserver$") = Field(..., description="+value=Code Server")
|
|
1364
|
-
image:
|
|
1365
|
-
..., description="+usage=Pick a codeserver image to deploy\n+sort=2"
|
|
1366
|
-
)
|
|
1220
|
+
image: WorkbenchImage
|
|
1367
1221
|
auth: Optional[BasicAuthCreds] = None
|
|
1368
1222
|
|
|
1369
1223
|
|
|
@@ -1458,6 +1312,10 @@ class Helm(BaseModel):
|
|
|
1458
1312
|
)
|
|
1459
1313
|
kustomize: Optional[Kustomize] = None
|
|
1460
1314
|
ignoreDifferences: Optional[List[Dict[str, Any]]] = None
|
|
1315
|
+
workspace_fqn: Optional[str] = Field(
|
|
1316
|
+
None,
|
|
1317
|
+
description="+label=Workspace FQN\n+docs=Fully qualified name of the workspace\n+uiType=Hidden",
|
|
1318
|
+
)
|
|
1461
1319
|
|
|
1462
1320
|
|
|
1463
1321
|
class Job(BaseModel):
|
|
@@ -1509,6 +1367,10 @@ class Job(BaseModel):
|
|
|
1509
1367
|
)
|
|
1510
1368
|
labels: Optional[Dict[str, str]] = Field(None, description="+label=Labels")
|
|
1511
1369
|
kustomize: Optional[Kustomize] = None
|
|
1370
|
+
workspace_fqn: Optional[str] = Field(
|
|
1371
|
+
None,
|
|
1372
|
+
description="+label=Workspace FQN\n+docs=Fully qualified name of the workspace\n+uiType=Hidden",
|
|
1373
|
+
)
|
|
1512
1374
|
|
|
1513
1375
|
|
|
1514
1376
|
class KafkaInputConfig(BaseModel):
|
|
@@ -1615,16 +1477,7 @@ class Notebook(BaseWorkbenchInput):
|
|
|
1615
1477
|
"""
|
|
1616
1478
|
|
|
1617
1479
|
type: constr(regex=r"^notebook$") = Field(..., description="+value=notebook")
|
|
1618
|
-
image:
|
|
1619
|
-
TruefoundryImageBase,
|
|
1620
|
-
TruefoundryImageFull,
|
|
1621
|
-
CustomNotebookImage,
|
|
1622
|
-
TruefoundryImageCuda1180,
|
|
1623
|
-
TruefoundryImageCuda1211,
|
|
1624
|
-
] = Field(
|
|
1625
|
-
...,
|
|
1626
|
-
description="+usage=Changes made to the root directory `/` will not be persisted across notebook restarts\n+sort=2",
|
|
1627
|
-
)
|
|
1480
|
+
image: WorkbenchImage
|
|
1628
1481
|
auth: Optional[BasicAuthCreds] = None
|
|
1629
1482
|
cull_timeout: conint(ge=5) = Field(
|
|
1630
1483
|
30,
|
|
@@ -1660,9 +1513,7 @@ class SSHServer(BaseWorkbenchInput):
|
|
|
1660
1513
|
"""
|
|
1661
1514
|
|
|
1662
1515
|
type: constr(regex=r"^ssh-server$") = Field(..., description="+value=SSH Server")
|
|
1663
|
-
image:
|
|
1664
|
-
..., description="+usage=Pick a ssh server image to deploy\n+sort=2"
|
|
1665
|
-
)
|
|
1516
|
+
image: WorkbenchImage
|
|
1666
1517
|
ssh_public_key: str = Field(
|
|
1667
1518
|
...,
|
|
1668
1519
|
description="+label: SSH Public Key\n+usage=Add Your SSH Public Key, this will be used to authenticate you to the SSH Server. You can find it using `cat ~/.ssh/id_rsa.pub`\n+sort=4",
|
|
@@ -1680,6 +1531,10 @@ class Volume(BaseModel):
|
|
|
1680
1531
|
description="+sort=2\n+label=Volume Config\n+message=Volume Configuration, can be either Dynamically provisioned or statically provisioned.",
|
|
1681
1532
|
)
|
|
1682
1533
|
volume_browser: Optional[VolumeBrowser] = None
|
|
1534
|
+
workspace_fqn: Optional[str] = Field(
|
|
1535
|
+
None,
|
|
1536
|
+
description="+label=Workspace FQN\n+docs=Fully qualified name of the workspace\n+uiType=Hidden",
|
|
1537
|
+
)
|
|
1683
1538
|
|
|
1684
1539
|
|
|
1685
1540
|
class WorkerConfig(BaseModel):
|
|
@@ -1729,6 +1584,10 @@ class BaseService(BaseModel):
|
|
|
1729
1584
|
kustomize: Optional[Kustomize] = None
|
|
1730
1585
|
liveness_probe: Optional[HealthProbe] = None
|
|
1731
1586
|
readiness_probe: Optional[HealthProbe] = None
|
|
1587
|
+
workspace_fqn: Optional[str] = Field(
|
|
1588
|
+
None,
|
|
1589
|
+
description="+label=Workspace FQN\n+docs=Fully qualified name of the workspace\n+uiType=Hidden",
|
|
1590
|
+
)
|
|
1732
1591
|
|
|
1733
1592
|
|
|
1734
1593
|
class FlyteLaunchPlan(BaseModel):
|
|
@@ -1756,6 +1615,7 @@ class Service(BaseService):
|
|
|
1756
1615
|
1,
|
|
1757
1616
|
description="+label=Replicas\n+usage=Deploy multiple instances of your pods to distribute incoming traffic across them, ensuring effective load balancing.\n+icon=fa-clone\n+sort=4",
|
|
1758
1617
|
)
|
|
1618
|
+
auto_shutdown: Optional[Autoshutdown] = None
|
|
1759
1619
|
allow_interception: bool = Field(
|
|
1760
1620
|
False,
|
|
1761
1621
|
description="+label=Allow intercepts\n+usage=Whether to allow intercepts to be applied for this service.\nThis would inject an additional sidecar in each pod of the service. Not recommended on production",
|
|
@@ -10,19 +10,17 @@ from truefoundry.deploy.builder.builders import get_builder
|
|
|
10
10
|
from truefoundry.deploy.builder.builders.tfy_notebook_buildpack.dockerfile_template import (
|
|
11
11
|
NotebookImageBuild,
|
|
12
12
|
)
|
|
13
|
-
from truefoundry.pydantic_v1 import BaseModel
|
|
13
|
+
from truefoundry.pydantic_v1 import BaseModel, Field
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class _BuildConfig(BaseModel):
|
|
17
|
-
# I cannot use Field(discriminator="build_config_type") here as
|
|
18
|
-
# build_config_type in the build configs is not a Literal.
|
|
19
17
|
__root__: Union[
|
|
20
18
|
DockerFileBuild,
|
|
21
19
|
PythonBuild,
|
|
22
20
|
NotebookImageBuild,
|
|
23
21
|
TaskPythonBuild,
|
|
24
22
|
TaskDockerFileBuild,
|
|
25
|
-
]
|
|
23
|
+
] = Field(discriminator="type")
|
|
26
24
|
|
|
27
25
|
|
|
28
26
|
def build(
|
|
@@ -13,18 +13,19 @@ __all__ = ["generate_dockerfile_content", "build"]
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def _convert_to_dockerfile_build_config(
|
|
16
|
-
build_configuration: NotebookImageBuild,
|
|
17
|
-
dockerfile_path: str,
|
|
16
|
+
build_configuration: NotebookImageBuild, local_dir: str
|
|
18
17
|
) -> DockerFileBuild:
|
|
19
18
|
dockerfile_content = generate_dockerfile_content(
|
|
20
|
-
build_configuration=build_configuration
|
|
19
|
+
build_configuration=build_configuration,
|
|
20
|
+
local_dir=local_dir,
|
|
21
21
|
)
|
|
22
|
+
dockerfile_path = os.path.join(local_dir, "Dockerfile")
|
|
22
23
|
with open(dockerfile_path, "w", encoding="utf8") as fp:
|
|
23
24
|
fp.write(dockerfile_content)
|
|
24
|
-
|
|
25
25
|
return DockerFileBuild(
|
|
26
26
|
type="dockerfile",
|
|
27
27
|
dockerfile_path=dockerfile_path,
|
|
28
|
+
build_context_path=local_dir,
|
|
28
29
|
)
|
|
29
30
|
|
|
30
31
|
|
|
@@ -35,7 +36,8 @@ def build(
|
|
|
35
36
|
):
|
|
36
37
|
with TemporaryDirectory() as local_dir:
|
|
37
38
|
docker_build_configuration = _convert_to_dockerfile_build_config(
|
|
38
|
-
build_configuration,
|
|
39
|
+
build_configuration,
|
|
40
|
+
local_dir=local_dir,
|
|
39
41
|
)
|
|
40
42
|
dockerfile.build(
|
|
41
43
|
tag=tag,
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import hashlib
|
|
2
|
+
import os
|
|
3
|
+
from typing import Literal, Optional
|
|
2
4
|
|
|
3
5
|
from mako.template import Template
|
|
4
6
|
|
|
@@ -6,43 +8,56 @@ from truefoundry.pydantic_v1 import BaseModel
|
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
class NotebookImageBuild(BaseModel):
|
|
9
|
-
type:
|
|
11
|
+
type: Literal["tfy-notebook-buildpack"] = "tfy-notebook-buildpack"
|
|
10
12
|
base_image_uri: str
|
|
11
|
-
|
|
13
|
+
build_script: Optional[str] = None
|
|
12
14
|
|
|
13
15
|
|
|
14
16
|
DOCKERFILE_TEMPLATE = Template(
|
|
15
17
|
"""
|
|
16
18
|
FROM ${base_image_uri}
|
|
17
19
|
USER root
|
|
18
|
-
|
|
20
|
+
|
|
21
|
+
% if build_script_docker_commands is not None:
|
|
22
|
+
${build_script_docker_commands}
|
|
23
|
+
% endif
|
|
24
|
+
|
|
19
25
|
USER $NB_UID
|
|
20
26
|
"""
|
|
21
27
|
)
|
|
22
28
|
|
|
23
29
|
|
|
24
|
-
def
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if not packages_list:
|
|
30
|
+
def generate_build_script_docker_commands(
|
|
31
|
+
build_script: Optional[str], local_dir: str
|
|
32
|
+
) -> Optional[str]:
|
|
33
|
+
if not build_script:
|
|
29
34
|
return None
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
build_script_path = None
|
|
36
|
+
if build_script:
|
|
37
|
+
# we add build script's hash to the file name to ensure docker cache invalidation
|
|
38
|
+
script_hash = hashlib.sha256(build_script.encode("utf-8")).hexdigest()
|
|
39
|
+
build_script_path = os.path.join(local_dir, f"build-script-{script_hash}.sh")
|
|
40
|
+
with open(build_script_path, "w") as fp:
|
|
41
|
+
fp.write(build_script)
|
|
42
|
+
build_script_path = os.path.relpath(build_script_path, local_dir)
|
|
43
|
+
run_build_script_command = f"""\
|
|
44
|
+
COPY {build_script_path} /tmp/user-build-script.sh
|
|
45
|
+
RUN mkdir -p /var/log/ && DEBIAN_FRONTEND=noninteractive bash -ex /tmp/user-build-script.sh 2>&1 | tee /var/log/user-build-script-output.log
|
|
46
|
+
"""
|
|
47
|
+
return run_build_script_command
|
|
36
48
|
|
|
37
49
|
|
|
38
|
-
def generate_dockerfile_content(
|
|
39
|
-
|
|
40
|
-
|
|
50
|
+
def generate_dockerfile_content(
|
|
51
|
+
build_configuration: NotebookImageBuild, local_dir: str
|
|
52
|
+
) -> str:
|
|
53
|
+
build_script_docker_commands = generate_build_script_docker_commands(
|
|
54
|
+
build_script=build_configuration.build_script,
|
|
55
|
+
local_dir=local_dir,
|
|
41
56
|
)
|
|
42
57
|
|
|
43
58
|
template_args = {
|
|
44
59
|
"base_image_uri": build_configuration.base_image_uri,
|
|
45
|
-
"
|
|
60
|
+
"build_script_docker_commands": build_script_docker_commands,
|
|
46
61
|
}
|
|
47
62
|
|
|
48
63
|
template = DOCKERFILE_TEMPLATE
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import sys
|
|
3
|
+
from typing import Optional
|
|
3
4
|
|
|
4
5
|
import rich_click as click
|
|
5
6
|
import yaml
|
|
@@ -9,6 +10,7 @@ from click.exceptions import ClickException
|
|
|
9
10
|
from truefoundry.autodeploy.cli import cli as autodeploy_cli
|
|
10
11
|
from truefoundry.autodeploy.exception import InvalidRequirementsException
|
|
11
12
|
from truefoundry.deploy.cli.const import GROUP_CLS
|
|
13
|
+
from truefoundry.deploy.cli.util import handle_exception_wrapper
|
|
12
14
|
|
|
13
15
|
|
|
14
16
|
def _get_default_spec_file():
|
|
@@ -41,8 +43,8 @@ def _get_default_spec_file():
|
|
|
41
43
|
"-w",
|
|
42
44
|
"--workspace-fqn",
|
|
43
45
|
"--workspace_fqn",
|
|
44
|
-
|
|
45
|
-
help="FQN of the Workspace to deploy to",
|
|
46
|
+
default=None,
|
|
47
|
+
help="FQN of the Workspace to deploy to. If not provided, the Workspace FQN will be read from the deployment spec if available.",
|
|
46
48
|
)
|
|
47
49
|
@click.option(
|
|
48
50
|
"--wait/--no-wait",
|
|
@@ -52,7 +54,8 @@ def _get_default_spec_file():
|
|
|
52
54
|
default=True,
|
|
53
55
|
help="Wait and tail the deployment progress",
|
|
54
56
|
)
|
|
55
|
-
|
|
57
|
+
@handle_exception_wrapper
|
|
58
|
+
def deploy_command(file: str, workspace_fqn: Optional[str], wait: bool):
|
|
56
59
|
from truefoundry.deploy.lib.auth.servicefoundry_session import ServiceFoundrySession
|
|
57
60
|
from truefoundry.deploy.v2.lib.deployable_patched_models import Application
|
|
58
61
|
|
|
@@ -4,6 +4,7 @@ import rich_click as click
|
|
|
4
4
|
import yaml
|
|
5
5
|
|
|
6
6
|
from truefoundry.deploy.cli.const import GROUP_CLS
|
|
7
|
+
from truefoundry.deploy.cli.util import handle_exception_wrapper
|
|
7
8
|
from truefoundry.deploy.lib.dao import application as application_lib
|
|
8
9
|
|
|
9
10
|
|
|
@@ -44,6 +45,7 @@ from truefoundry.deploy.lib.dao import application as application_lib
|
|
|
44
45
|
default=True,
|
|
45
46
|
help="Wait and tail the deployment progress",
|
|
46
47
|
)
|
|
48
|
+
@handle_exception_wrapper
|
|
47
49
|
def patch_application_command(
|
|
48
50
|
patch_file: str, application_fqn: str, patch: str, wait: bool
|
|
49
51
|
):
|
|
@@ -191,10 +191,61 @@ def _warn_when_gpu_selected_without_cuda(component: Component):
|
|
|
191
191
|
)
|
|
192
192
|
|
|
193
193
|
|
|
194
|
+
def _resolve_workspace_fqn(
|
|
195
|
+
component: Component, workspace_fqn: Optional[str] = None
|
|
196
|
+
) -> str:
|
|
197
|
+
if not workspace_fqn:
|
|
198
|
+
if hasattr(component, "workspace_fqn") and component.workspace_fqn:
|
|
199
|
+
resolved_workspace_fqn = component.workspace_fqn
|
|
200
|
+
else:
|
|
201
|
+
raise ValueError(
|
|
202
|
+
f"""\
|
|
203
|
+
No Workspace FQN was provided or mentioned in the spec.
|
|
204
|
+
Either add a `workspace_fqn` to your yaml spec as
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
name: {getattr(component, 'name', 'my-app')}
|
|
208
|
+
type: {getattr(component, 'type', 'undefined')}
|
|
209
|
+
...
|
|
210
|
+
workspace_fqn: <your workspace fqn>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
or Python deployment spec as
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
app = {component.__class__.__name__}(
|
|
217
|
+
name='{getattr(component, 'name', 'my-app')}',
|
|
218
|
+
...
|
|
219
|
+
workspace_fqn='<your workspace fqn>'
|
|
220
|
+
)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
or pass it explicitly using `--workspace-fqn` argument on CLI.
|
|
224
|
+
"""
|
|
225
|
+
)
|
|
226
|
+
else:
|
|
227
|
+
if (
|
|
228
|
+
hasattr(component, "workspace_fqn")
|
|
229
|
+
and component.workspace_fqn
|
|
230
|
+
and component.workspace_fqn != workspace_fqn
|
|
231
|
+
):
|
|
232
|
+
logger.warning(
|
|
233
|
+
f"`workspace_fqn` set in the deployment spec doesn't match the provided `workspace_fqn` argument {component.workspace_fqn!r} \n"
|
|
234
|
+
f"Using `workspace_fqn`: {workspace_fqn!r} "
|
|
235
|
+
)
|
|
236
|
+
resolved_workspace_fqn = workspace_fqn
|
|
237
|
+
|
|
238
|
+
return resolved_workspace_fqn
|
|
239
|
+
|
|
240
|
+
|
|
194
241
|
def deploy_component(
|
|
195
|
-
component: Component, workspace_fqn: str, wait: bool = True
|
|
242
|
+
component: Component, workspace_fqn: Optional[str] = None, wait: bool = True
|
|
196
243
|
) -> Deployment:
|
|
197
244
|
_warn_when_gpu_selected_without_cuda(component=component)
|
|
245
|
+
workspace_fqn = _resolve_workspace_fqn(
|
|
246
|
+
component=component, workspace_fqn=workspace_fqn
|
|
247
|
+
)
|
|
248
|
+
component.workspace_fqn = workspace_fqn
|
|
198
249
|
workspace_id = get_workspace_by_fqn(workspace_fqn).id
|
|
199
250
|
updated_component = _handle_if_local_source(
|
|
200
251
|
component=component, workspace_fqn=workspace_fqn
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import sys
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import List, Union
|
|
4
|
+
from typing import Dict, List, Optional, Union
|
|
5
5
|
|
|
6
|
+
import requirements
|
|
7
|
+
from flytekit.configuration import (
|
|
8
|
+
SERIALIZED_CONTEXT_ENV_VAR,
|
|
9
|
+
ImageConfig,
|
|
10
|
+
SerializationSettings,
|
|
11
|
+
)
|
|
6
12
|
from flytekit.configuration import Image as FlytekitImage
|
|
7
|
-
from flytekit.configuration import ImageConfig, SerializationSettings
|
|
8
13
|
from flytekit.models.launch_plan import LaunchPlan as FlyteLaunchPlan
|
|
9
14
|
from flytekit.tools.repo import serialize as serialize_workflow
|
|
10
15
|
from flytekit.tools.translator import TaskSpec as FlyteTaskSpec
|
|
@@ -22,6 +27,10 @@ from truefoundry.deploy.v2.lib.source import (
|
|
|
22
27
|
)
|
|
23
28
|
from truefoundry.logger import logger
|
|
24
29
|
from truefoundry.pydantic_v1 import ValidationError
|
|
30
|
+
from truefoundry.workflow.workflow import (
|
|
31
|
+
TRUEFOUNDRY_LAUNCH_PLAN_NAME,
|
|
32
|
+
execution_config_store,
|
|
33
|
+
)
|
|
25
34
|
|
|
26
35
|
|
|
27
36
|
def _handle_code_upload_for_workflow(
|
|
@@ -36,14 +45,60 @@ def _handle_code_upload_for_workflow(
|
|
|
36
45
|
return new_workflow
|
|
37
46
|
|
|
38
47
|
|
|
48
|
+
def _is_tfy_workflow_package(package: requirements.parser.Requirement) -> bool:
|
|
49
|
+
return package.name == "truefoundry" and "workflow" in package.extras
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _is_tfy_wf_present_in_pip_packages_or_requirements_file(
|
|
53
|
+
pip_packages: List[str],
|
|
54
|
+
project_root_path: str,
|
|
55
|
+
requirements_path: Optional[str] = None,
|
|
56
|
+
) -> bool:
|
|
57
|
+
for package in pip_packages:
|
|
58
|
+
parsed_package = requirements.parser.Requirement.parse(package)
|
|
59
|
+
if _is_tfy_workflow_package(parsed_package):
|
|
60
|
+
return True
|
|
61
|
+
if requirements_path:
|
|
62
|
+
requirements_file_absolute_path = os.path.join(
|
|
63
|
+
project_root_path, requirements_path
|
|
64
|
+
)
|
|
65
|
+
if not os.path.exists(requirements_file_absolute_path):
|
|
66
|
+
raise FileNotFoundError(
|
|
67
|
+
f"requirements file not found at {requirements_file_absolute_path}. requirements file path should be relative to project root path."
|
|
68
|
+
)
|
|
69
|
+
with open(requirements_file_absolute_path, "r") as file:
|
|
70
|
+
for package in requirements.parse(file):
|
|
71
|
+
if _is_tfy_workflow_package(package):
|
|
72
|
+
return True
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _is_tfy_wf_present_in_task_python_build(
|
|
77
|
+
task_image_spec: Dict, project_root_path: str
|
|
78
|
+
) -> bool:
|
|
79
|
+
pip_packages = task_image_spec["pip_packages"] or []
|
|
80
|
+
requirements_path = task_image_spec.get("requirements_path")
|
|
81
|
+
return _is_tfy_wf_present_in_pip_packages_or_requirements_file(
|
|
82
|
+
pip_packages=pip_packages,
|
|
83
|
+
project_root_path=project_root_path,
|
|
84
|
+
requirements_path=requirements_path,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _is_dynamic_task(flyte_task: FlyteTaskSpec) -> bool:
|
|
89
|
+
envs: Dict[str:str] = flyte_task.template.container.env or {}
|
|
90
|
+
return SERIALIZED_CONTEXT_ENV_VAR in envs.keys()
|
|
91
|
+
|
|
92
|
+
|
|
39
93
|
# this function does validation that num_workflows = 1, this also validates task_config is passed correctly.
|
|
40
94
|
# This is verified by pydantic but doing it here also as error messages are not clear in pydantic
|
|
41
|
-
def _validate_workflow_entities(
|
|
95
|
+
def _validate_workflow_entities( # noqa: C901
|
|
42
96
|
workflow_entities: List[Union[FlyteWorkflowSpec, FlyteLaunchPlan, FlyteTaskSpec]],
|
|
97
|
+
project_root_path: str,
|
|
43
98
|
):
|
|
44
|
-
workflow_objs = []
|
|
45
|
-
launch_plans = []
|
|
46
|
-
tasks = []
|
|
99
|
+
workflow_objs: List[FlyteWorkflowSpec] = []
|
|
100
|
+
launch_plans: List[FlyteLaunchPlan] = []
|
|
101
|
+
tasks: List[FlyteTaskSpec] = []
|
|
47
102
|
for entity in workflow_entities:
|
|
48
103
|
if isinstance(entity, FlyteWorkflowSpec):
|
|
49
104
|
workflow_objs.append(entity)
|
|
@@ -57,9 +112,9 @@ def _validate_workflow_entities(
|
|
|
57
112
|
raise ValueError(
|
|
58
113
|
f"Workflow file must have exactly one workflow object. Found {len(workflow_objs)}"
|
|
59
114
|
)
|
|
60
|
-
if len(launch_plans)
|
|
115
|
+
if len(launch_plans) > 2:
|
|
61
116
|
raise ValueError(
|
|
62
|
-
f"Workflow file must have exactly one launch plan. Found {len(launch_plans)}"
|
|
117
|
+
f"Workflow file must have exactly one launch plan. Found {len(launch_plans) - 1}"
|
|
63
118
|
)
|
|
64
119
|
|
|
65
120
|
error_message_to_use_truefoundry_decorators = """Invalid task definition for task: {}, Please use valid truefoundry decorator/class and pass task_config for tasks.
|
|
@@ -69,13 +124,25 @@ def _validate_workflow_entities(
|
|
|
69
124
|
`PythonTaskConfig`, or `ContainerTaskConfig`. You can import these using:
|
|
70
125
|
`from truefoundry.workflow import PythonTaskConfig, ContainerTaskConfig`
|
|
71
126
|
"""
|
|
127
|
+
tasks_without_truefoundry_worflow_package = []
|
|
72
128
|
for task in tasks:
|
|
129
|
+
if _is_dynamic_task(task):
|
|
130
|
+
raise ValueError("Dynamic workflows are not supported yet.")
|
|
73
131
|
if not task.template.custom:
|
|
74
132
|
raise ValueError(
|
|
75
133
|
error_message_to_use_truefoundry_decorators.format(
|
|
76
134
|
task.template.id.name
|
|
77
135
|
)
|
|
78
136
|
)
|
|
137
|
+
task_image_spec = task.template.custom["truefoundry"]["image"]
|
|
138
|
+
if task_image_spec["type"] == "task-python-build":
|
|
139
|
+
is_tfy_wf_present_in_task_python_build = (
|
|
140
|
+
_is_tfy_wf_present_in_task_python_build(
|
|
141
|
+
task_image_spec=task_image_spec, project_root_path=project_root_path
|
|
142
|
+
)
|
|
143
|
+
)
|
|
144
|
+
if not is_tfy_wf_present_in_task_python_build:
|
|
145
|
+
tasks_without_truefoundry_worflow_package.append(task.template.id.name)
|
|
79
146
|
try:
|
|
80
147
|
auto_gen_models.FlyteTaskCustom.validate(task.template.custom)
|
|
81
148
|
except ValidationError:
|
|
@@ -84,6 +151,23 @@ def _validate_workflow_entities(
|
|
|
84
151
|
task.template.id.name
|
|
85
152
|
)
|
|
86
153
|
) from None
|
|
154
|
+
if len(tasks_without_truefoundry_worflow_package) > 0:
|
|
155
|
+
raise ValueError(
|
|
156
|
+
rf"truefoundry\[workflow] package is required dependency to run workflows, add it in pip_packages for tasks: {', '.join(tasks_without_truefoundry_worflow_package)}"
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
# validate that all inputs have default values for cron workflows
|
|
160
|
+
for launch_plan in launch_plans:
|
|
161
|
+
if (
|
|
162
|
+
execution_config_store.get(launch_plan.spec.workflow_id.name)
|
|
163
|
+
and launch_plan.id.name == TRUEFOUNDRY_LAUNCH_PLAN_NAME
|
|
164
|
+
):
|
|
165
|
+
workflow_inputs = launch_plan.spec.default_inputs.parameters
|
|
166
|
+
for input in workflow_inputs:
|
|
167
|
+
if workflow_inputs[input].required:
|
|
168
|
+
raise ValueError(
|
|
169
|
+
f"All inputs must have default for a cron workflow. Input {input} is required in workflow but default value is not provided"
|
|
170
|
+
)
|
|
87
171
|
|
|
88
172
|
|
|
89
173
|
def _get_relative_package_path_from_filepath(
|
|
@@ -126,10 +210,27 @@ def _generate_manifest_for_workflow(
|
|
|
126
210
|
workflow_entities = serialize_workflow(
|
|
127
211
|
pkgs=[package_path], settings=settings, local_source_root=source_absolute_path
|
|
128
212
|
)
|
|
129
|
-
_validate_workflow_entities(workflow_entities)
|
|
213
|
+
_validate_workflow_entities(workflow_entities, source_absolute_path)
|
|
130
214
|
|
|
131
215
|
workflow.flyte_entities = []
|
|
132
216
|
for entity in workflow_entities:
|
|
217
|
+
if isinstance(entity, FlyteLaunchPlan):
|
|
218
|
+
workflow_name = entity.spec.workflow_id.name
|
|
219
|
+
|
|
220
|
+
# this is the case when someone has a cron schedule. and this line is for handling default launch plan in this case.
|
|
221
|
+
if (
|
|
222
|
+
execution_config_store.get(workflow_name)
|
|
223
|
+
and workflow_name == entity.id.name
|
|
224
|
+
):
|
|
225
|
+
continue
|
|
226
|
+
# this is the case when someone does not have a cron schedule. and this line is for handling default launch plan in this case.
|
|
227
|
+
elif entity.id.name == workflow_name:
|
|
228
|
+
entity._id._name = TRUEFOUNDRY_LAUNCH_PLAN_NAME
|
|
229
|
+
# this the case when some workflow doesn't have cron schedule, neither it is default launch plan
|
|
230
|
+
elif entity.id.name != TRUEFOUNDRY_LAUNCH_PLAN_NAME:
|
|
231
|
+
raise ValueError(
|
|
232
|
+
f"Creating launch plans is not allowed. Found launch plan with name {entity.id.name}"
|
|
233
|
+
)
|
|
133
234
|
message_dict = MessageToDict(entity.to_flyte_idl())
|
|
134
235
|
# proto message to dict conversion converts all int to float. so we need this hack
|
|
135
236
|
if (
|
|
@@ -148,10 +249,29 @@ def _generate_manifest_for_workflow(
|
|
|
148
249
|
auto_gen_models.Workflow.validate({**workflow.dict()})
|
|
149
250
|
|
|
150
251
|
|
|
252
|
+
def _validate_workspace_fqn(
|
|
253
|
+
workflow: auto_gen_models.Workflow,
|
|
254
|
+
workspace_fqn: Optional[str] = None,
|
|
255
|
+
):
|
|
256
|
+
if not workspace_fqn:
|
|
257
|
+
raise ValueError(
|
|
258
|
+
"No Workspace FQN was provided. "
|
|
259
|
+
"Pass it explicitly using `--workspace-fqn` argument on CLI or `workspace_fqn` argument of `deploy_workflow`."
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
|
|
151
263
|
def deploy_workflow(
|
|
152
|
-
workflow: auto_gen_models.Workflow,
|
|
264
|
+
workflow: auto_gen_models.Workflow,
|
|
265
|
+
workspace_fqn: str,
|
|
266
|
+
wait: bool = True,
|
|
153
267
|
) -> Deployment:
|
|
154
268
|
_generate_manifest_for_workflow(workflow)
|
|
269
|
+
_validate_workspace_fqn(workflow, workspace_fqn)
|
|
270
|
+
|
|
271
|
+
# we need to rest the execution config store as it is a global variable and we don't want to keep the cron execution config for next workflow
|
|
272
|
+
# this is only needed for notebook environment
|
|
273
|
+
execution_config_store.reset()
|
|
274
|
+
|
|
155
275
|
workspace_id = get_workspace_by_fqn(workspace_fqn).id
|
|
156
276
|
|
|
157
277
|
logger.info(
|
|
@@ -67,7 +67,9 @@ class Application(models.Application, DeployablePatchedModelBase):
|
|
|
67
67
|
from truefoundry.deploy.v2.lib.deploy_workflow import deploy_workflow
|
|
68
68
|
|
|
69
69
|
return deploy_workflow(
|
|
70
|
-
workflow=self.__root__,
|
|
70
|
+
workflow=self.__root__,
|
|
71
|
+
workspace_fqn=workspace_fqn,
|
|
72
|
+
wait=wait,
|
|
71
73
|
)
|
|
72
74
|
else:
|
|
73
75
|
return deploy_component(
|
|
@@ -330,18 +330,6 @@ class Endpoint(models.Endpoint, PatchedModelBase):
|
|
|
330
330
|
pass
|
|
331
331
|
|
|
332
332
|
|
|
333
|
-
class TruefoundryImageBase(models.TruefoundryImageBase, PatchedModelBase):
|
|
334
|
-
type: Literal["truefoundrybase"] = "truefoundrybase"
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
class TruefoundryImageFull(models.TruefoundryImageFull, PatchedModelBase):
|
|
338
|
-
type: Literal["truefoundryfull"] = "truefoundryfull"
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
class CodeserverImage(models.CodeserverImage, PatchedModelBase):
|
|
342
|
-
type: Literal["codeserver"] = "codeserver"
|
|
343
|
-
|
|
344
|
-
|
|
345
333
|
class HelmRepo(models.HelmRepo, PatchedModelBase):
|
|
346
334
|
type: Literal["helm-repo"] = "helm-repo"
|
|
347
335
|
|
|
@@ -442,10 +430,6 @@ class ArtifactsDownload(models.ArtifactsDownload, PatchedModelBase):
|
|
|
442
430
|
pass
|
|
443
431
|
|
|
444
432
|
|
|
445
|
-
class CustomNotebookImage(models.CustomNotebookImage, PatchedModelBase):
|
|
446
|
-
type: Literal["customnotebook"] = "customnotebook"
|
|
447
|
-
|
|
448
|
-
|
|
449
433
|
class NvidiaGPU(models.NvidiaGPU, PatchedModelBase):
|
|
450
434
|
type: Literal["nvidia_gpu"] = "nvidia_gpu"
|
|
451
435
|
name: Optional[Union[GPUType, constr(regex=r"^tpu-[a-z\d\-]+$")]] = None
|
|
@@ -469,26 +453,6 @@ class GcpTPU(models.GcpTPU, PatchedModelBase):
|
|
|
469
453
|
name: Union[TPUType, Literal[r"tpu-[a-z\d\-]+"]]
|
|
470
454
|
|
|
471
455
|
|
|
472
|
-
class CustomCodeserverImage(models.CustomCodeserverImage, PatchedModelBase):
|
|
473
|
-
type: Literal["customcodeserver"] = "customcodeserver"
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
class CustomSSHServerImage(models.CustomSSHServerImage, PatchedModelBase):
|
|
477
|
-
type: Literal["custom-ssh-server"] = "custom-ssh-server"
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
class SSHServerImage(models.SSHServerImage, PatchedModelBase):
|
|
481
|
-
type: Literal["ssh-server"] = "ssh-server"
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
class TruefoundryImageCuda1180(models.TruefoundryImageCuda1180, PatchedModelBase):
|
|
485
|
-
type: Literal["truefoundrycuda1180"] = "truefoundrycuda1180"
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
class TruefoundryImageCuda1211(models.TruefoundryImageCuda1211, PatchedModelBase):
|
|
489
|
-
type: Literal["truefoundrycuda1211"] = "truefoundrycuda1211"
|
|
490
|
-
|
|
491
|
-
|
|
492
456
|
class DynamicVolumeConfig(models.DynamicVolumeConfig, PatchedModelBase):
|
|
493
457
|
type: Literal["dynamic"] = "dynamic"
|
|
494
458
|
|
truefoundry/version.py
CHANGED
truefoundry/workflow/__init__.py
CHANGED
|
@@ -16,4 +16,4 @@ from truefoundry.workflow.container_task import ContainerTask
|
|
|
16
16
|
from truefoundry.workflow.map_task import map_task
|
|
17
17
|
from truefoundry.workflow.python_task import PythonFunctionTask
|
|
18
18
|
from truefoundry.workflow.task import task
|
|
19
|
-
from truefoundry.workflow.workflow import workflow
|
|
19
|
+
from truefoundry.workflow.workflow import ExecutionConfig, workflow
|
|
@@ -5,8 +5,9 @@ from truefoundry.workflow import PythonTaskConfig, TaskPythonBuild, task, workfl
|
|
|
5
5
|
task_config=PythonTaskConfig(
|
|
6
6
|
image=TaskPythonBuild(
|
|
7
7
|
python_version="3.9",
|
|
8
|
-
pip_packages=["
|
|
9
|
-
)
|
|
8
|
+
pip_packages=["truefoundry[workflow]==0.3.0rc7"],
|
|
9
|
+
),
|
|
10
|
+
service_account="tfy-flyte-dataplane-devtest-s3",
|
|
10
11
|
)
|
|
11
12
|
)
|
|
12
13
|
def say_hello() -> str:
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from functools import partial
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import List, Tuple
|
|
4
|
+
from typing import List, Optional, Tuple
|
|
5
5
|
|
|
6
6
|
from truefoundry.deploy import Image, NvidiaGPU, Resources
|
|
7
7
|
from truefoundry.workflow import (
|
|
8
8
|
ContainerTask,
|
|
9
9
|
ContainerTaskConfig,
|
|
10
|
+
ExecutionConfig,
|
|
10
11
|
FlyteDirectory,
|
|
11
12
|
PythonTaskConfig,
|
|
12
13
|
TaskPythonBuild,
|
|
@@ -19,15 +20,17 @@ from truefoundry.workflow import (
|
|
|
19
20
|
cpu_task_config = PythonTaskConfig(
|
|
20
21
|
image=TaskPythonBuild(
|
|
21
22
|
python_version="3.9",
|
|
22
|
-
pip_packages=["
|
|
23
|
+
pip_packages=["truefoundry[workflow]==0.3.0rc7"],
|
|
23
24
|
),
|
|
24
25
|
resources=Resources(cpu_request=0.45),
|
|
26
|
+
service_account="tfy-flyte-dataplane-devtest-s3",
|
|
25
27
|
)
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
# figure out naming
|
|
29
31
|
@task(task_config=cpu_task_config)
|
|
30
32
|
def should_train_tokenizer(tokenizer: str) -> bool:
|
|
33
|
+
print("Should train tokenizer")
|
|
31
34
|
return not bool(tokenizer)
|
|
32
35
|
|
|
33
36
|
|
|
@@ -38,6 +41,7 @@ def should_train_tokenizer(tokenizer: str) -> bool:
|
|
|
38
41
|
# cache_version="1.0",
|
|
39
42
|
)
|
|
40
43
|
def train_tokenizer() -> str:
|
|
44
|
+
print("Training tokenizer")
|
|
41
45
|
return "trained_tokenizer"
|
|
42
46
|
|
|
43
47
|
|
|
@@ -45,7 +49,7 @@ def train_tokenizer() -> str:
|
|
|
45
49
|
task_config=PythonTaskConfig(
|
|
46
50
|
image=TaskPythonBuild(
|
|
47
51
|
python_version="3.9",
|
|
48
|
-
pip_packages=["
|
|
52
|
+
pip_packages=["truefoundry[workflow]==0.3.0rc7", "pynvml==11.5.0"],
|
|
49
53
|
cuda_version="11.5-cudnn8",
|
|
50
54
|
),
|
|
51
55
|
env={
|
|
@@ -53,17 +57,17 @@ def train_tokenizer() -> str:
|
|
|
53
57
|
"NVIDIA_VISIBLE_DEVICES": "all",
|
|
54
58
|
},
|
|
55
59
|
resources=Resources(cpu_request=0.45, devices=[NvidiaGPU(name="T4", count=1)]),
|
|
60
|
+
service_account="tfy-flyte-dataplane-devtest-s3",
|
|
56
61
|
),
|
|
57
62
|
)
|
|
58
63
|
def train_model(tokenizer: str) -> Tuple[FlyteDirectory, str]:
|
|
64
|
+
print("Training model")
|
|
59
65
|
import flytekit
|
|
60
|
-
from package.test_workflow import random
|
|
61
66
|
from pynvml import nvmlDeviceGetCount, nvmlInit
|
|
62
67
|
|
|
63
68
|
nvmlInit()
|
|
64
69
|
assert nvmlDeviceGetCount() > 0
|
|
65
70
|
|
|
66
|
-
random.random()
|
|
67
71
|
working_dir = flytekit.current_context().working_directory
|
|
68
72
|
local_dir = Path(os.path.join(working_dir, "csv_files"))
|
|
69
73
|
local_dir.mkdir(exist_ok=True)
|
|
@@ -76,6 +80,7 @@ def train_model(tokenizer: str) -> Tuple[FlyteDirectory, str]:
|
|
|
76
80
|
|
|
77
81
|
@task(task_config=cpu_task_config)
|
|
78
82
|
def get_validation_data() -> List[str]:
|
|
83
|
+
print("Getting validation data")
|
|
79
84
|
return ["foo", "bar", "baz"]
|
|
80
85
|
|
|
81
86
|
|
|
@@ -89,6 +94,7 @@ def validate_model(model: FlyteDirectory, tokenizer: str, validation_data: str)
|
|
|
89
94
|
|
|
90
95
|
@task(task_config=cpu_task_config)
|
|
91
96
|
def all_good(validations: List[bool]) -> bool:
|
|
97
|
+
print("Validations", validations)
|
|
92
98
|
return all(validations)
|
|
93
99
|
|
|
94
100
|
|
|
@@ -97,18 +103,33 @@ echo = ContainerTask(
|
|
|
97
103
|
task_config=ContainerTaskConfig(
|
|
98
104
|
image=Image(
|
|
99
105
|
image_uri="bash:4.1",
|
|
100
|
-
|
|
106
|
+
command=["echo", "hello"],
|
|
107
|
+
),
|
|
108
|
+
service_account="tfy-flyte-dataplane-devtest-s3",
|
|
101
109
|
),
|
|
102
110
|
)
|
|
103
111
|
|
|
104
112
|
|
|
105
113
|
@task(task_config=cpu_task_config)
|
|
106
114
|
def random(tokenizer: str) -> Tuple[FlyteDirectory, str]:
|
|
115
|
+
print(tokenizer)
|
|
107
116
|
return FlyteDirectory(path=""), "random"
|
|
108
117
|
|
|
109
118
|
|
|
110
|
-
@workflow
|
|
111
|
-
|
|
119
|
+
@workflow(
|
|
120
|
+
execution_configs=[
|
|
121
|
+
ExecutionConfig(
|
|
122
|
+
schedule="*/10 * * * *",
|
|
123
|
+
)
|
|
124
|
+
]
|
|
125
|
+
)
|
|
126
|
+
def train(
|
|
127
|
+
tokenizer: str = "",
|
|
128
|
+
test_v2: str = "",
|
|
129
|
+
optional_var: Optional[str] = "",
|
|
130
|
+
default_v: Optional[str] = "hello1",
|
|
131
|
+
default_v2: str = "hello2",
|
|
132
|
+
) -> bool:
|
|
112
133
|
stt = should_train_tokenizer(tokenizer=tokenizer)
|
|
113
134
|
model, t = (
|
|
114
135
|
conditional("train_tokenizer")
|
truefoundry/workflow/workflow.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
from typing import Any, Callable, Optional, Union
|
|
1
|
+
from typing import Any, Callable, Dict, List, Optional, Union
|
|
2
2
|
|
|
3
3
|
from flytekit.core.base_task import Task
|
|
4
|
+
from flytekit.core.launch_plan import LaunchPlan
|
|
5
|
+
from flytekit.core.schedule import CronSchedule
|
|
4
6
|
from flytekit.core.workflow import (
|
|
5
7
|
FuncOut,
|
|
6
8
|
PythonFunctionWorkflow,
|
|
@@ -8,11 +10,39 @@ from flytekit.core.workflow import (
|
|
|
8
10
|
)
|
|
9
11
|
from flytekit.core.workflow import workflow as flytekit_workflow
|
|
10
12
|
|
|
13
|
+
from truefoundry.pydantic_v1 import BaseModel
|
|
14
|
+
|
|
15
|
+
TRUEFOUNDRY_LAUNCH_PLAN_NAME = "default"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ExecutionConfig(BaseModel):
|
|
19
|
+
# I am not using job's Schedule here because:
|
|
20
|
+
# 1. flyte accepts schedule only as a string
|
|
21
|
+
# 2. flyte doesn't support setting concurrency policy
|
|
22
|
+
schedule: str
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ExecutionConfigStore(BaseModel):
|
|
26
|
+
execution_config_map: Dict[str, ExecutionConfig] = {}
|
|
27
|
+
|
|
28
|
+
def reset(self):
|
|
29
|
+
self.execution_config_map = {}
|
|
30
|
+
|
|
31
|
+
def get(self, key: str) -> Optional[ExecutionConfig]:
|
|
32
|
+
return self.execution_config_map.get(key)
|
|
33
|
+
|
|
34
|
+
def set(self, key: str, value: ExecutionConfig):
|
|
35
|
+
self.execution_config_map[key] = value
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
execution_config_store = ExecutionConfigStore()
|
|
39
|
+
|
|
11
40
|
|
|
12
41
|
def workflow(
|
|
13
42
|
_workflow_function: Optional[Callable[..., Any]] = None,
|
|
14
43
|
failure_policy: Optional[WorkflowFailurePolicy] = None,
|
|
15
44
|
on_failure: Optional[Task] = None,
|
|
45
|
+
execution_configs: Optional[List[ExecutionConfig]] = None,
|
|
16
46
|
) -> Union[
|
|
17
47
|
Callable[[Callable[..., FuncOut]], PythonFunctionWorkflow],
|
|
18
48
|
PythonFunctionWorkflow,
|
|
@@ -47,8 +77,38 @@ def workflow(
|
|
|
47
77
|
:param on_failure: Invoke this workflow or task on failure. The Workflow / task has to match the signature of
|
|
48
78
|
the current workflow, with an additional parameter called `error` Error
|
|
49
79
|
"""
|
|
50
|
-
|
|
80
|
+
if _workflow_function is None:
|
|
81
|
+
|
|
82
|
+
def wrapper(func: Callable[..., Any]) -> Any:
|
|
83
|
+
return workflow(
|
|
84
|
+
_workflow_function=func,
|
|
85
|
+
failure_policy=failure_policy,
|
|
86
|
+
on_failure=on_failure,
|
|
87
|
+
execution_configs=execution_configs,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
return wrapper
|
|
91
|
+
|
|
92
|
+
workflow_object = flytekit_workflow(
|
|
51
93
|
_workflow_function,
|
|
52
94
|
failure_policy=failure_policy,
|
|
53
95
|
on_failure=on_failure,
|
|
54
96
|
)
|
|
97
|
+
execution_configs = execution_configs or []
|
|
98
|
+
if len(execution_configs) > 1:
|
|
99
|
+
raise ValueError("Only one cron execution config is allowed per workflow")
|
|
100
|
+
|
|
101
|
+
if execution_configs:
|
|
102
|
+
execution_config = execution_configs[0]
|
|
103
|
+
# flyte maintains this in-memory and uses it while serialization
|
|
104
|
+
LaunchPlan.get_or_create(
|
|
105
|
+
workflow=workflow_object,
|
|
106
|
+
name=TRUEFOUNDRY_LAUNCH_PLAN_NAME,
|
|
107
|
+
schedule=CronSchedule(schedule=execution_config.schedule),
|
|
108
|
+
)
|
|
109
|
+
function_module = _workflow_function.__module__
|
|
110
|
+
function_name = _workflow_function.__name__
|
|
111
|
+
function_path = f"{function_module}.{function_name}"
|
|
112
|
+
execution_config_store.set(function_path, execution_config)
|
|
113
|
+
|
|
114
|
+
return workflow_object
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: truefoundry
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.0rc9
|
|
4
4
|
Summary: Truefoundry CLI
|
|
5
5
|
Author: Abhishek Choudhary
|
|
6
6
|
Author-email: abhishek@truefoundry.com
|
|
@@ -34,6 +34,7 @@ Requires-Dist: python-dotenv (>=1.0.1,<1.1.0)
|
|
|
34
34
|
Requires-Dist: python-socketio[client] (>=5.5.2,<6.0.0)
|
|
35
35
|
Requires-Dist: questionary (>=1.10.0,<2.0.0)
|
|
36
36
|
Requires-Dist: requests (>=2.31.0,<3.0.0)
|
|
37
|
+
Requires-Dist: requirements-parser (>=0.10.2,<0.11.0)
|
|
37
38
|
Requires-Dist: rich (>=13.7.1,<14.0.0)
|
|
38
39
|
Requires-Dist: rich-click (>=1.2.1,<2.0.0)
|
|
39
40
|
Requires-Dist: tqdm (>=4.0.0,<5.0.0)
|
|
@@ -25,13 +25,13 @@ truefoundry/autodeploy/utils/diff.py,sha256=Ef8Y-VffDKel_-q-GxRam6gqiv8qTLMcqVg6
|
|
|
25
25
|
truefoundry/autodeploy/utils/pydantic_compat.py,sha256=hEAUy5kLjhPdzw7yGZ2iXGMXbbMVXVlGzIofmyHafXQ,412
|
|
26
26
|
truefoundry/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
27
27
|
truefoundry/cli/__main__.py,sha256=Jap_IddZ9zNyMIyIkCw75xHQCN0WtV2dPZJ_pzdLsVc,916
|
|
28
|
-
truefoundry/deploy/__init__.py,sha256=
|
|
29
|
-
truefoundry/deploy/auto_gen/models.py,sha256=
|
|
30
|
-
truefoundry/deploy/builder/__init__.py,sha256=
|
|
28
|
+
truefoundry/deploy/__init__.py,sha256=hyBoxhL3SG37vduJBdUYJuy1EHGeSLPI4S8MuKhyCFo,2259
|
|
29
|
+
truefoundry/deploy/auto_gen/models.py,sha256=inof7aH6Wk1z15YYtCNJo7sp3Tixv5yaJzB_4fiZux4,78412
|
|
30
|
+
truefoundry/deploy/builder/__init__.py,sha256=a1qR6nicHGcxRaeNTxWRsmDs8zsmXc7j13-I8q0qqVk,4938
|
|
31
31
|
truefoundry/deploy/builder/builders/__init__.py,sha256=tlFLXqyDaKLd4iZbo4Hcu_8gOmgtL6drnXpbmQ6x1P8,636
|
|
32
32
|
truefoundry/deploy/builder/builders/dockerfile.py,sha256=AXXTziCkaqIhuM_bwyD1vT1znOwemN1TKgU7eyo-KuM,1522
|
|
33
|
-
truefoundry/deploy/builder/builders/tfy_notebook_buildpack/__init__.py,sha256=
|
|
34
|
-
truefoundry/deploy/builder/builders/tfy_notebook_buildpack/dockerfile_template.py,sha256=
|
|
33
|
+
truefoundry/deploy/builder/builders/tfy_notebook_buildpack/__init__.py,sha256=OK2lCwaPfhh7ALjNqfFBOTv7B9B3e9WDLoaSm0LWEkk,1436
|
|
34
|
+
truefoundry/deploy/builder/builders/tfy_notebook_buildpack/dockerfile_template.py,sha256=cEjpcz2L9lEEoEcF0rzuRpgXwNkuce8dbvdBvhTqDYk,1946
|
|
35
35
|
truefoundry/deploy/builder/builders/tfy_python_buildpack/__init__.py,sha256=n7MwUzIyn3mFqVkQqOuMeswmSPsydpYH4XMV5c8qAdQ,1381
|
|
36
36
|
truefoundry/deploy/builder/builders/tfy_python_buildpack/dockerfile_template.py,sha256=vFmFeK38-t8booJEGREapEjrIL8xnyOQeRSJQq7d3ZQ,6183
|
|
37
37
|
truefoundry/deploy/builder/docker_service.py,sha256=vQS15790njzlFJZ3JW6txYLBdT11ltxqqpf78ZFL_Ng,5208
|
|
@@ -43,13 +43,13 @@ truefoundry/deploy/cli/commands/build_command.py,sha256=QwKkZ3nVecPMzs-R57YP-_ih
|
|
|
43
43
|
truefoundry/deploy/cli/commands/build_logs_command.py,sha256=WrPOlFec_wwuzdJmKZ8mjca-oFVvxgfblcqj2LlhWJA,2804
|
|
44
44
|
truefoundry/deploy/cli/commands/create_command.py,sha256=ZjA4EP1jHYuVE1zx0kN-giBr3y0sEiXnu8xMsNyD2Rg,1850
|
|
45
45
|
truefoundry/deploy/cli/commands/delete_command.py,sha256=4tyIameA1pVu9uZZNJPK6rqdV-cJogf51iCCrG-9noI,2390
|
|
46
|
-
truefoundry/deploy/cli/commands/deploy_command.py,sha256=
|
|
46
|
+
truefoundry/deploy/cli/commands/deploy_command.py,sha256=SpCd_1OxA8ZEUyJ6Jkf5Ay8UNakCCLGR--svMHp9EEM,2858
|
|
47
47
|
truefoundry/deploy/cli/commands/get_command.py,sha256=w7h5C4bJpmHJ99rgiGg9J_X0xi8aZUeB6Q-SoZUV1tg,5979
|
|
48
48
|
truefoundry/deploy/cli/commands/list_command.py,sha256=cFARY22L5xspBX7TWsx41IF4RiRMok7KBwv7hQRFXNs,4498
|
|
49
49
|
truefoundry/deploy/cli/commands/login_command.py,sha256=Kin6ZdmeADvXOGA08M5_t1MwMnu3QEUfjz1seJurstw,1032
|
|
50
50
|
truefoundry/deploy/cli/commands/logout_command.py,sha256=hgw6LhJtF3xJ6YyQ_VrBuUWY0WmT8tPYbOEOhMu1eXU,550
|
|
51
51
|
truefoundry/deploy/cli/commands/logs_command.py,sha256=fQSY4o_B78WEJDD5qULWPFQJsCXLJLTr0RI1QjmX1WE,4154
|
|
52
|
-
truefoundry/deploy/cli/commands/patch_application_command.py,sha256=
|
|
52
|
+
truefoundry/deploy/cli/commands/patch_application_command.py,sha256=Zuswj36o-qniklOsOjEPUKnd9f5mHv_U7rOPPwALrZ8,2457
|
|
53
53
|
truefoundry/deploy/cli/commands/patch_command.py,sha256=OQCmxcn1Qd2iZfBUaqs48oUKjHVZ13SoMsWLhksPvks,1682
|
|
54
54
|
truefoundry/deploy/cli/commands/redeploy_command.py,sha256=-wMQLeMcBdJsQBMgTv7rS6hCqH1EJsSKgPrAXU9HjxU,1032
|
|
55
55
|
truefoundry/deploy/cli/commands/terminate_comand.py,sha256=RTNuykw5DBvid44u2nCka_Eu0XSK3Qrzwob9fybHLgQ,1097
|
|
@@ -102,11 +102,11 @@ truefoundry/deploy/lib/util.py,sha256=3Pc0gQgomapTSjMQo743STShBn1B6PNdBpw3bTpdxO
|
|
|
102
102
|
truefoundry/deploy/lib/win32.py,sha256=1RcvPTdlOAJ48rt8rCbE2Ufha2ztRqBAE9dueNXArrY,5009
|
|
103
103
|
truefoundry/deploy/v2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
104
104
|
truefoundry/deploy/v2/lib/__init__.py,sha256=WEiVMZXOVljzEE3tpGJil14liIn_PCDoACJ6b3tZ6sI,188
|
|
105
|
-
truefoundry/deploy/v2/lib/deploy.py,sha256=
|
|
106
|
-
truefoundry/deploy/v2/lib/deploy_workflow.py,sha256=
|
|
107
|
-
truefoundry/deploy/v2/lib/deployable_patched_models.py,sha256=
|
|
105
|
+
truefoundry/deploy/v2/lib/deploy.py,sha256=vmaevT86nfrgephRjinhSVFEZHVc9R09vZBKKUoeUWI,11640
|
|
106
|
+
truefoundry/deploy/v2/lib/deploy_workflow.py,sha256=o_8gd98SFgijvrYDubm6cJ7XNqlXRPwswq8nRXfqvDM,12171
|
|
107
|
+
truefoundry/deploy/v2/lib/deployable_patched_models.py,sha256=YVeTiasyf0s-QXjDqdvGSmN83oVAQ0h9g6F687PJyVI,3141
|
|
108
108
|
truefoundry/deploy/v2/lib/models.py,sha256=pSolLMTArDuYpeNsmeeS5DWliloN_iCDfZSpRllMHUg,1120
|
|
109
|
-
truefoundry/deploy/v2/lib/patched_models.py,sha256=
|
|
109
|
+
truefoundry/deploy/v2/lib/patched_models.py,sha256=qL3N7y6zf7jywx6uY-yMxsH65NB367V_82o47ZYJt1I,13820
|
|
110
110
|
truefoundry/deploy/v2/lib/source.py,sha256=VHKuFREiixUP40D3Mrz-TA70spu1M0RbCzl--qwlFaY,9263
|
|
111
111
|
truefoundry/langchain/__init__.py,sha256=zeYKxKrQhfYXQuBec3wvB_ZqKowDUUjLUKUhbiu9ZFs,558
|
|
112
112
|
truefoundry/langchain/deprecated.py,sha256=8tfLHXwcifGl7DYhMNfzc4zRVCVqEgARg5BsbZp11NE,10835
|
|
@@ -118,19 +118,19 @@ truefoundry/logger.py,sha256=7dLqW_Q2rEgo-_z1WZnQbGHaoy1L1MP3NqGgssaSS6o,685
|
|
|
118
118
|
truefoundry/ml/__init__.py,sha256=yFjvF-e1RW488vLHgn5M7TXoajqww6grkKHb3mhqDEw,179
|
|
119
119
|
truefoundry/pydantic_v1.py,sha256=IJy5FtaPg-_H5XLRd9nueTuyijEJPdCa1vZ7-pinmRI,158
|
|
120
120
|
truefoundry/python_deploy_codegen.py,sha256=hd8XRytuT-U6AXSzYSjISbtYY4HLB_B1EeLB5TRDfNw,3947
|
|
121
|
-
truefoundry/version.py,sha256=
|
|
122
|
-
truefoundry/workflow/__init__.py,sha256=
|
|
121
|
+
truefoundry/version.py,sha256=bqiT4Q-VWrTC6P4qfK43mez-Ppf-smWfrl6DcwV7mrw,137
|
|
122
|
+
truefoundry/workflow/__init__.py,sha256=m0puY8RJ3GBvdAXW0A9PLuCpmDdLqh6eF0t3DCEpZkg,659
|
|
123
123
|
truefoundry/workflow/container_task.py,sha256=8arieePsX4__OnG337hOtCiNgJwtKJJCsZcmFmCBJtk,402
|
|
124
124
|
truefoundry/workflow/example/deploy.sh,sha256=wfbPRrCi04WYRqCf4g-Xo12uWbcqPD6G_Tz0lV0jU_U,60
|
|
125
|
-
truefoundry/workflow/example/hello_world_package/workflow.py,sha256=
|
|
126
|
-
truefoundry/workflow/example/package/test_workflow.py,sha256
|
|
127
|
-
truefoundry/workflow/example/truefoundry.yaml,sha256=
|
|
125
|
+
truefoundry/workflow/example/hello_world_package/workflow.py,sha256=ACWJJWTY5NhYyU_dAEfdSqXgyLuNXPRDpOBuUkTEzhU,459
|
|
126
|
+
truefoundry/workflow/example/package/test_workflow.py,sha256=-CeCcMyI3fjRGSkzfmmnLcE2aFxceCUpEXx8dql8MBE,4015
|
|
127
|
+
truefoundry/workflow/example/truefoundry.yaml,sha256=LlPrMADSPJsiXRoK76N_RVjX1bnZ3FH1u2jXrwLfR9I,226
|
|
128
128
|
truefoundry/workflow/example/workflow.yaml,sha256=YtYdKXMuW_08gfEo21XSculj2MGI2lfEnGF8qCT8NKE,2858
|
|
129
129
|
truefoundry/workflow/map_task.py,sha256=2m3qGXQ90k9LdS45q8dqCCECc3qr8t2m_LMCVd1mZ7g,1737
|
|
130
130
|
truefoundry/workflow/python_task.py,sha256=SRXRLC4vdBqGjhkwuaY39LEWN6iPCpJAuW17URRdWTY,1128
|
|
131
131
|
truefoundry/workflow/task.py,sha256=ToitYiKcNzFCtOVQwz1W8sRjbR97eVS7vQBdbgUQtKg,1779
|
|
132
|
-
truefoundry/workflow/workflow.py,sha256=
|
|
133
|
-
truefoundry-0.3.
|
|
134
|
-
truefoundry-0.3.
|
|
135
|
-
truefoundry-0.3.
|
|
136
|
-
truefoundry-0.3.
|
|
132
|
+
truefoundry/workflow/workflow.py,sha256=WaTqUjhwfAXDWu4E5ehuwAxrCbDJkoAf1oWmR2E9Qy0,4575
|
|
133
|
+
truefoundry-0.3.0rc9.dist-info/METADATA,sha256=MoFxdl5KpAr9mCShojPeE2O2dXsgyB82DSjYKPIR9b0,2693
|
|
134
|
+
truefoundry-0.3.0rc9.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
135
|
+
truefoundry-0.3.0rc9.dist-info/entry_points.txt,sha256=TXvUxQkI6zmqJuycPsyxEIMr3oqfDjgrWj0m_9X12x4,95
|
|
136
|
+
truefoundry-0.3.0rc9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|