truefoundry 0.5.0rc7__py3-none-any.whl → 0.5.1__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/common/auth_service_client.py +2 -2
- truefoundry/common/constants.py +9 -0
- truefoundry/common/utils.py +81 -1
- truefoundry/deploy/__init__.py +5 -0
- truefoundry/deploy/builder/builders/tfy_notebook_buildpack/__init__.py +4 -2
- truefoundry/deploy/builder/builders/tfy_python_buildpack/__init__.py +7 -5
- truefoundry/deploy/builder/builders/tfy_python_buildpack/dockerfile_template.py +87 -28
- truefoundry/deploy/builder/constants.py +8 -0
- truefoundry/deploy/builder/utils.py +9 -4
- truefoundry/deploy/cli/cli.py +2 -0
- truefoundry/deploy/cli/commands/__init__.py +1 -0
- truefoundry/deploy/cli/commands/deploy_init_command.py +22 -0
- truefoundry/deploy/lib/dao/application.py +2 -1
- truefoundry/deploy/v2/lib/patched_models.py +8 -0
- truefoundry/ml/__init__.py +25 -16
- truefoundry/ml/autogen/client/__init__.py +21 -3
- truefoundry/ml/autogen/client/api/mlfoundry_artifacts_api.py +325 -0
- truefoundry/ml/autogen/client/models/__init__.py +21 -3
- truefoundry/ml/autogen/client/models/artifact_version_manifest.py +2 -2
- truefoundry/ml/autogen/client/models/export_deployment_files_request_dto.py +82 -0
- truefoundry/ml/autogen/client/models/infer_method_name.py +34 -0
- truefoundry/ml/autogen/client/models/model_server.py +34 -0
- truefoundry/ml/autogen/client/models/model_version_environment.py +1 -1
- truefoundry/ml/autogen/client/models/model_version_manifest.py +2 -8
- truefoundry/ml/autogen/client/models/sklearn_framework.py +15 -5
- truefoundry/ml/autogen/client/models/sklearn_model_schema.py +82 -0
- truefoundry/ml/autogen/client/models/{serialization_format.py → sklearn_serialization_format.py} +5 -5
- truefoundry/ml/autogen/client/models/transformers_framework.py +2 -2
- truefoundry/ml/autogen/client/models/validate_external_storage_root_request_dto.py +71 -0
- truefoundry/ml/autogen/client/models/validate_external_storage_root_response_dto.py +69 -0
- truefoundry/ml/autogen/client/models/xg_boost_framework.py +17 -5
- truefoundry/ml/autogen/client/models/xg_boost_model_schema.py +88 -0
- truefoundry/ml/autogen/client/models/xg_boost_serialization_format.py +36 -0
- truefoundry/ml/autogen/client_README.md +11 -1
- truefoundry/ml/autogen/entities/artifacts.py +95 -39
- truefoundry/ml/autogen/models/signature.py +6 -3
- truefoundry/ml/autogen/models/utils.py +12 -7
- truefoundry/ml/cli/commands/model_init.py +97 -0
- truefoundry/ml/cli/utils.py +34 -0
- truefoundry/ml/log_types/artifacts/model.py +50 -38
- truefoundry/ml/log_types/artifacts/utils.py +38 -2
- truefoundry/ml/mlfoundry_api.py +74 -80
- truefoundry/ml/mlfoundry_run.py +0 -32
- truefoundry/ml/model_framework.py +372 -3
- truefoundry/ml/validation_utils.py +2 -0
- {truefoundry-0.5.0rc7.dist-info → truefoundry-0.5.1.dist-info}/METADATA +1 -5
- {truefoundry-0.5.0rc7.dist-info → truefoundry-0.5.1.dist-info}/RECORD +49 -56
- truefoundry/deploy/function_service/__init__.py +0 -3
- truefoundry/deploy/function_service/__main__.py +0 -27
- truefoundry/deploy/function_service/app.py +0 -92
- truefoundry/deploy/function_service/build.py +0 -45
- truefoundry/deploy/function_service/remote/__init__.py +0 -6
- truefoundry/deploy/function_service/remote/context.py +0 -3
- truefoundry/deploy/function_service/remote/method.py +0 -67
- truefoundry/deploy/function_service/remote/remote.py +0 -144
- truefoundry/deploy/function_service/route.py +0 -137
- truefoundry/deploy/function_service/service.py +0 -113
- truefoundry/deploy/function_service/utils.py +0 -53
- truefoundry/langchain/__init__.py +0 -12
- truefoundry/langchain/deprecated.py +0 -302
- truefoundry/langchain/truefoundry_chat.py +0 -130
- truefoundry/langchain/truefoundry_embeddings.py +0 -171
- truefoundry/langchain/truefoundry_llm.py +0 -106
- truefoundry/langchain/utils.py +0 -44
- truefoundry/ml/log_types/artifacts/model_extras.py +0 -48
- {truefoundry-0.5.0rc7.dist-info → truefoundry-0.5.1.dist-info}/WHEEL +0 -0
- {truefoundry-0.5.0rc7.dist-info → truefoundry-0.5.1.dist-info}/entry_points.txt +0 -0
|
@@ -51,7 +51,7 @@ class ServiceFoundryServerAuthServiceClient(AuthServiceClient):
|
|
|
51
51
|
self._api_server_url = url
|
|
52
52
|
|
|
53
53
|
def refresh_token(self, token: Token, host: Optional[str] = None) -> Token:
|
|
54
|
-
host_arg_str =
|
|
54
|
+
host_arg_str = host if host else "HOST"
|
|
55
55
|
if not token.refresh_token:
|
|
56
56
|
# TODO: Add a way to propagate error messages without traceback to the output interface side
|
|
57
57
|
raise Exception(
|
|
@@ -128,7 +128,7 @@ class AuthServerServiceClient(AuthServiceClient):
|
|
|
128
128
|
self._auth_server_url = url
|
|
129
129
|
|
|
130
130
|
def refresh_token(self, token: Token, host: Optional[str] = None) -> Token:
|
|
131
|
-
host_arg_str =
|
|
131
|
+
host_arg_str = host if host else "HOST"
|
|
132
132
|
if not token.refresh_token:
|
|
133
133
|
# TODO: Add a way to propagate error messages without traceback to the output interface side
|
|
134
134
|
raise Exception(
|
truefoundry/common/constants.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import enum
|
|
1
2
|
import os
|
|
2
3
|
from pathlib import Path
|
|
3
4
|
from typing import Optional
|
|
@@ -15,6 +16,11 @@ TFY_INTERNAL_SIGNED_URL_SERVER_HOST_ENV_KEY = "TFY_INTERNAL_SIGNED_URL_SERVER_HO
|
|
|
15
16
|
TFY_INTERNAL_SIGNED_URL_SERVER_TOKEN_ENV_KEY = "TFY_INTERNAL_SIGNED_URL_SERVER_TOKEN"
|
|
16
17
|
|
|
17
18
|
|
|
19
|
+
class PythonPackageManager(str, enum.Enum):
|
|
20
|
+
PIP = "pip"
|
|
21
|
+
UV = "uv"
|
|
22
|
+
|
|
23
|
+
|
|
18
24
|
class TrueFoundrySdkEnv(BaseSettings):
|
|
19
25
|
# Note: Every field in this class should have a default value
|
|
20
26
|
# Never expect the user to set these values
|
|
@@ -46,6 +52,9 @@ class TrueFoundrySdkEnv(BaseSettings):
|
|
|
46
52
|
# For local development, this enables futher configuration via _TFYServersConfig
|
|
47
53
|
TFY_CLI_LOCAL_DEV_MODE: bool = False
|
|
48
54
|
|
|
55
|
+
TFY_PYTHON_BUILD_PACKAGE_MANAGER: PythonPackageManager = PythonPackageManager.PIP
|
|
56
|
+
TFY_PYTHON_BUILD_UV_IMAGE_URI: str = "ghcr.io/astral-sh/uv:latest"
|
|
57
|
+
|
|
49
58
|
|
|
50
59
|
ENV_VARS = TrueFoundrySdkEnv()
|
|
51
60
|
API_SERVER_RELATIVE_PATH = "api/svc"
|
truefoundry/common/utils.py
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
1
5
|
import time
|
|
6
|
+
from collections import namedtuple
|
|
2
7
|
from functools import lru_cache, wraps
|
|
8
|
+
from shutil import rmtree
|
|
9
|
+
from subprocess import check_output
|
|
3
10
|
from time import monotonic_ns
|
|
4
|
-
from typing import Callable, Generator, Optional, TypeVar
|
|
11
|
+
from typing import Callable, Generator, List, Optional, TypeVar
|
|
5
12
|
from urllib.parse import urljoin, urlparse
|
|
6
13
|
|
|
7
14
|
from truefoundry.common.constants import (
|
|
@@ -12,7 +19,10 @@ from truefoundry.common.constants import (
|
|
|
12
19
|
)
|
|
13
20
|
from truefoundry.pydantic_v1 import BaseSettings
|
|
14
21
|
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
15
24
|
T = TypeVar("T")
|
|
25
|
+
InstalledPipPackage = namedtuple("InstalledPipPackage", ["name", "version"])
|
|
16
26
|
|
|
17
27
|
|
|
18
28
|
class _TFYServersConfig(BaseSettings):
|
|
@@ -102,3 +112,73 @@ def resolve_tfy_host(tfy_host: Optional[str] = None) -> str:
|
|
|
102
112
|
tfy_host = tfy_host.strip("/")
|
|
103
113
|
validate_tfy_host(tfy_host)
|
|
104
114
|
return tfy_host
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class ContextualDirectoryManager:
|
|
118
|
+
def __init__(self, dir_path: str, cleanup_on_error: bool = True):
|
|
119
|
+
self.dir_path = dir_path
|
|
120
|
+
self.cleanup_on_error = cleanup_on_error
|
|
121
|
+
|
|
122
|
+
def __enter__(self):
|
|
123
|
+
if os.path.exists(self.dir_path):
|
|
124
|
+
raise FileExistsError(
|
|
125
|
+
f"The directory {self.dir_path!r} already exists. "
|
|
126
|
+
"Please provide a path with a different name that does not already exist."
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
os.makedirs(self.dir_path, exist_ok=False)
|
|
130
|
+
return self.dir_path
|
|
131
|
+
|
|
132
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
133
|
+
if self.cleanup_on_error and exc_type is not None:
|
|
134
|
+
# Only delete the directory if an exception occurred
|
|
135
|
+
if os.path.exists(self.dir_path):
|
|
136
|
+
rmtree(self.dir_path)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def get_python_version_major_minor() -> str:
|
|
140
|
+
"""
|
|
141
|
+
Returns the major.minor version of the Python interpreter
|
|
142
|
+
"""
|
|
143
|
+
version_info = sys.version_info
|
|
144
|
+
return f"{version_info.major}.{version_info.minor}"
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def list_pip_packages_installed(
|
|
148
|
+
filter_package_names: Optional[List[str]] = None,
|
|
149
|
+
) -> List[InstalledPipPackage]:
|
|
150
|
+
"""
|
|
151
|
+
List the installed package_names, along with their versions.
|
|
152
|
+
Args:
|
|
153
|
+
filter_package_names (List[str]): A list of specific libraries to filter for.
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
List[InstalledPipPackage]: A list of InstalledPipPackage namedtuples for each match.
|
|
157
|
+
"""
|
|
158
|
+
relevant_package_names: List[InstalledPipPackage] = []
|
|
159
|
+
|
|
160
|
+
# Get the installed packages in JSON format from pip
|
|
161
|
+
try:
|
|
162
|
+
output = check_output(
|
|
163
|
+
[
|
|
164
|
+
sys.executable,
|
|
165
|
+
"-m",
|
|
166
|
+
"pip",
|
|
167
|
+
"--disable-pip-version-check",
|
|
168
|
+
"list",
|
|
169
|
+
"--pre",
|
|
170
|
+
"--format=json",
|
|
171
|
+
]
|
|
172
|
+
)
|
|
173
|
+
installed_package_names = json.loads(output.decode("utf-8"))
|
|
174
|
+
except Exception:
|
|
175
|
+
logger.exception("Failed to list installed packages using pip.")
|
|
176
|
+
return relevant_package_names
|
|
177
|
+
|
|
178
|
+
package_names_to_check = set(filter_package_names or [])
|
|
179
|
+
for package in installed_package_names:
|
|
180
|
+
if package["name"] in package_names_to_check:
|
|
181
|
+
relevant_package_names.append(
|
|
182
|
+
InstalledPipPackage(package["name"], package["version"])
|
|
183
|
+
)
|
|
184
|
+
return relevant_package_names
|
truefoundry/deploy/__init__.py
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
from truefoundry.deploy.auto_gen.models import (
|
|
2
2
|
AppProtocol,
|
|
3
|
+
Autoshutdown,
|
|
3
4
|
CanaryStep,
|
|
4
5
|
CapacityType,
|
|
6
|
+
Claim,
|
|
5
7
|
ConcurrencyPolicy,
|
|
8
|
+
JobAlert,
|
|
6
9
|
Kustomize,
|
|
7
10
|
ParamType,
|
|
8
11
|
Protocol,
|
|
@@ -66,6 +69,7 @@ from truefoundry.deploy.v2.lib.patched_models import (
|
|
|
66
69
|
DynamicVolumeConfig,
|
|
67
70
|
Endpoint,
|
|
68
71
|
GcpTPU,
|
|
72
|
+
GitHelmRepo,
|
|
69
73
|
GitSource,
|
|
70
74
|
GPUType,
|
|
71
75
|
HealthProbe,
|
|
@@ -73,6 +77,7 @@ from truefoundry.deploy.v2.lib.patched_models import (
|
|
|
73
77
|
HttpProbe,
|
|
74
78
|
HuggingfaceArtifactSource,
|
|
75
79
|
Image,
|
|
80
|
+
JwtAuthCreds,
|
|
76
81
|
KafkaInputConfig,
|
|
77
82
|
KafkaMetricConfig,
|
|
78
83
|
KafkaOutputConfig,
|
|
@@ -8,7 +8,7 @@ from truefoundry.deploy.builder.builders.tfy_notebook_buildpack.dockerfile_templ
|
|
|
8
8
|
NotebookImageBuild,
|
|
9
9
|
generate_dockerfile_content,
|
|
10
10
|
)
|
|
11
|
-
from truefoundry.deploy.builder.utils import
|
|
11
|
+
from truefoundry.deploy.builder.utils import has_python_package_manager_conf_secret
|
|
12
12
|
|
|
13
13
|
__all__ = ["generate_dockerfile_content", "build"]
|
|
14
14
|
|
|
@@ -38,7 +38,9 @@ def build(
|
|
|
38
38
|
build_configuration: NotebookImageBuild,
|
|
39
39
|
extra_opts: Optional[List[str]] = None,
|
|
40
40
|
):
|
|
41
|
-
mount_pip_conf_secret =
|
|
41
|
+
mount_pip_conf_secret = (
|
|
42
|
+
has_python_package_manager_conf_secret(extra_opts) if extra_opts else False
|
|
43
|
+
)
|
|
42
44
|
with TemporaryDirectory() as local_dir:
|
|
43
45
|
docker_build_configuration = _convert_to_dockerfile_build_config(
|
|
44
46
|
build_configuration,
|
|
@@ -7,7 +7,7 @@ from truefoundry.deploy.builder.builders import dockerfile
|
|
|
7
7
|
from truefoundry.deploy.builder.builders.tfy_python_buildpack.dockerfile_template import (
|
|
8
8
|
generate_dockerfile_content,
|
|
9
9
|
)
|
|
10
|
-
from truefoundry.deploy.builder.utils import
|
|
10
|
+
from truefoundry.deploy.builder.utils import has_python_package_manager_conf_secret
|
|
11
11
|
|
|
12
12
|
__all__ = ["generate_dockerfile_content", "build"]
|
|
13
13
|
|
|
@@ -15,11 +15,11 @@ __all__ = ["generate_dockerfile_content", "build"]
|
|
|
15
15
|
def _convert_to_dockerfile_build_config(
|
|
16
16
|
build_configuration: PythonBuild,
|
|
17
17
|
dockerfile_path: str,
|
|
18
|
-
|
|
18
|
+
mount_python_package_manager_conf_secret: bool = False,
|
|
19
19
|
) -> DockerFileBuild:
|
|
20
20
|
dockerfile_content = generate_dockerfile_content(
|
|
21
21
|
build_configuration=build_configuration,
|
|
22
|
-
|
|
22
|
+
mount_python_package_manager_conf_secret=mount_python_package_manager_conf_secret,
|
|
23
23
|
)
|
|
24
24
|
with open(dockerfile_path, "w", encoding="utf8") as fp:
|
|
25
25
|
fp.write(dockerfile_content)
|
|
@@ -36,12 +36,14 @@ def build(
|
|
|
36
36
|
build_configuration: PythonBuild,
|
|
37
37
|
extra_opts: Optional[List[str]] = None,
|
|
38
38
|
):
|
|
39
|
-
|
|
39
|
+
mount_python_package_manager_conf_secret = (
|
|
40
|
+
has_python_package_manager_conf_secret(extra_opts) if extra_opts else False
|
|
41
|
+
)
|
|
40
42
|
with TemporaryDirectory() as local_dir:
|
|
41
43
|
docker_build_configuration = _convert_to_dockerfile_build_config(
|
|
42
44
|
build_configuration,
|
|
43
45
|
dockerfile_path=os.path.join(local_dir, "Dockerfile"),
|
|
44
|
-
|
|
46
|
+
mount_python_package_manager_conf_secret=mount_python_package_manager_conf_secret,
|
|
45
47
|
)
|
|
46
48
|
dockerfile.build(
|
|
47
49
|
tag=tag,
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import shlex
|
|
2
3
|
from typing import Dict, List, Optional
|
|
3
4
|
|
|
4
5
|
from mako.template import Template
|
|
5
6
|
|
|
6
|
-
from truefoundry.common.constants import ENV_VARS
|
|
7
|
+
from truefoundry.common.constants import ENV_VARS, PythonPackageManager
|
|
7
8
|
from truefoundry.deploy.auto_gen.models import PythonBuild
|
|
8
9
|
from truefoundry.deploy.builder.constants import (
|
|
9
10
|
PIP_CONF_BUILDKIT_SECRET_MOUNT,
|
|
10
11
|
PIP_CONF_SECRET_MOUNT_AS_ENV,
|
|
12
|
+
UV_CONF_BUILDKIT_SECRET_MOUNT,
|
|
13
|
+
UV_CONF_SECRET_MOUNT_AS_ENV,
|
|
11
14
|
)
|
|
12
15
|
from truefoundry.deploy.v2.lib.patched_models import CUDAVersion
|
|
13
16
|
|
|
@@ -22,8 +25,8 @@ RUN ${apt_install_command}
|
|
|
22
25
|
% if requirements_path is not None:
|
|
23
26
|
COPY ${requirements_path} ${requirements_destination_path}
|
|
24
27
|
% endif
|
|
25
|
-
% if
|
|
26
|
-
RUN ${
|
|
28
|
+
% if python_packages_install_command is not None:
|
|
29
|
+
RUN ${package_manager_config_secret_mount} ${python_packages_install_command}
|
|
27
30
|
% endif
|
|
28
31
|
COPY . /app
|
|
29
32
|
WORKDIR /app
|
|
@@ -114,44 +117,91 @@ def generate_pip_install_command(
|
|
|
114
117
|
mount_pip_conf_secret: bool = False,
|
|
115
118
|
) -> Optional[str]:
|
|
116
119
|
upgrade_pip_command = "python -m pip install -U pip setuptools wheel"
|
|
117
|
-
|
|
118
|
-
|
|
120
|
+
envs = []
|
|
121
|
+
if mount_pip_conf_secret:
|
|
122
|
+
envs.append(PIP_CONF_SECRET_MOUNT_AS_ENV)
|
|
123
|
+
|
|
124
|
+
command = ["python", "-m", "pip", "install", "--use-pep517", "--no-cache-dir"]
|
|
125
|
+
args = []
|
|
119
126
|
if requirements_path:
|
|
120
|
-
|
|
127
|
+
args.append("-r")
|
|
128
|
+
args.append(requirements_path)
|
|
121
129
|
|
|
122
130
|
if pip_packages:
|
|
123
|
-
|
|
124
|
-
final_pip_install_command or pip_install_base_command
|
|
125
|
-
)
|
|
126
|
-
final_pip_install_command += " " + " ".join(
|
|
127
|
-
f"'{package}'" for package in pip_packages
|
|
128
|
-
)
|
|
131
|
+
args.extend(pip_packages)
|
|
129
132
|
|
|
130
|
-
if not
|
|
133
|
+
if not args:
|
|
131
134
|
return None
|
|
132
135
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
136
|
+
final_pip_install_command = shlex.join(envs + command + args)
|
|
137
|
+
final_docker_run_command = " && ".join(
|
|
138
|
+
[upgrade_pip_command, final_pip_install_command]
|
|
139
|
+
)
|
|
140
|
+
return final_docker_run_command
|
|
137
141
|
|
|
138
|
-
|
|
142
|
+
|
|
143
|
+
def generate_uv_pip_install_command(
|
|
144
|
+
requirements_path: Optional[str],
|
|
145
|
+
pip_packages: Optional[List[str]],
|
|
146
|
+
mount_uv_conf_secret: bool = False,
|
|
147
|
+
) -> Optional[str]:
|
|
148
|
+
upgrade_pip_command = "python -m pip install -U pip setuptools wheel"
|
|
149
|
+
uv_mount = f"--mount=from={ENV_VARS.TFY_PYTHON_BUILD_UV_IMAGE_URI},source=/uv,target=/usr/local/bin/uv"
|
|
150
|
+
envs = [
|
|
151
|
+
"UV_SYSTEM_PYTHON=true",
|
|
152
|
+
"UV_LINK_MODE=copy",
|
|
153
|
+
"UV_PYTHON_DOWNLOADS=never",
|
|
154
|
+
"UV_INDEX_STRATEGY=unsafe-best-match",
|
|
155
|
+
]
|
|
156
|
+
if mount_uv_conf_secret:
|
|
157
|
+
envs.append(UV_CONF_SECRET_MOUNT_AS_ENV)
|
|
158
|
+
|
|
159
|
+
command = ["uv", "pip", "install", "--no-cache-dir"]
|
|
160
|
+
|
|
161
|
+
args = []
|
|
162
|
+
|
|
163
|
+
if requirements_path:
|
|
164
|
+
args.append("-r")
|
|
165
|
+
args.append(requirements_path)
|
|
166
|
+
|
|
167
|
+
if pip_packages:
|
|
168
|
+
args.extend(pip_packages)
|
|
169
|
+
|
|
170
|
+
if not args:
|
|
171
|
+
return None
|
|
172
|
+
|
|
173
|
+
uv_pip_install_command = shlex.join(envs + command + args)
|
|
174
|
+
shell_commands = " && ".join([upgrade_pip_command, uv_pip_install_command])
|
|
175
|
+
final_docker_run_command = " ".join([uv_mount, shell_commands])
|
|
176
|
+
|
|
177
|
+
return final_docker_run_command
|
|
139
178
|
|
|
140
179
|
|
|
141
180
|
def generate_dockerfile_content(
|
|
142
181
|
build_configuration: PythonBuild,
|
|
143
|
-
|
|
182
|
+
package_manager: str = ENV_VARS.TFY_PYTHON_BUILD_PACKAGE_MANAGER,
|
|
183
|
+
mount_python_package_manager_conf_secret: bool = False,
|
|
144
184
|
) -> str:
|
|
145
185
|
# TODO (chiragjn): Handle recursive references to other requirements files e.g. `-r requirements-gpu.txt`
|
|
146
186
|
requirements_path = resolve_requirements_txt_path(build_configuration)
|
|
147
187
|
requirements_destination_path = (
|
|
148
188
|
"/tmp/requirements.txt" if requirements_path else None
|
|
149
189
|
)
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
190
|
+
if package_manager == PythonPackageManager.PIP.value:
|
|
191
|
+
python_packages_install_command = generate_pip_install_command(
|
|
192
|
+
requirements_path=requirements_destination_path,
|
|
193
|
+
pip_packages=build_configuration.pip_packages,
|
|
194
|
+
mount_pip_conf_secret=mount_python_package_manager_conf_secret,
|
|
195
|
+
)
|
|
196
|
+
elif package_manager == PythonPackageManager.UV.value:
|
|
197
|
+
python_packages_install_command = generate_uv_pip_install_command(
|
|
198
|
+
requirements_path=requirements_destination_path,
|
|
199
|
+
pip_packages=build_configuration.pip_packages,
|
|
200
|
+
mount_uv_conf_secret=mount_python_package_manager_conf_secret,
|
|
201
|
+
)
|
|
202
|
+
else:
|
|
203
|
+
raise ValueError(f"Unsupported package manager: {package_manager}")
|
|
204
|
+
|
|
155
205
|
apt_install_command = generate_apt_install_command(
|
|
156
206
|
apt_packages=build_configuration.apt_packages
|
|
157
207
|
)
|
|
@@ -161,13 +211,22 @@ def generate_dockerfile_content(
|
|
|
161
211
|
"apt_install_command": apt_install_command,
|
|
162
212
|
"requirements_path": requirements_path,
|
|
163
213
|
"requirements_destination_path": requirements_destination_path,
|
|
164
|
-
"
|
|
214
|
+
"python_packages_install_command": python_packages_install_command,
|
|
165
215
|
}
|
|
166
216
|
|
|
167
|
-
if
|
|
168
|
-
|
|
217
|
+
if mount_python_package_manager_conf_secret:
|
|
218
|
+
if package_manager == PythonPackageManager.PIP.value:
|
|
219
|
+
template_args["package_manager_config_secret_mount"] = (
|
|
220
|
+
PIP_CONF_BUILDKIT_SECRET_MOUNT
|
|
221
|
+
)
|
|
222
|
+
elif package_manager == PythonPackageManager.UV.value:
|
|
223
|
+
template_args["package_manager_config_secret_mount"] = (
|
|
224
|
+
UV_CONF_BUILDKIT_SECRET_MOUNT
|
|
225
|
+
)
|
|
226
|
+
else:
|
|
227
|
+
raise ValueError(f"Unsupported package manager: {package_manager}")
|
|
169
228
|
else:
|
|
170
|
-
template_args["
|
|
229
|
+
template_args["package_manager_config_secret_mount"] = ""
|
|
171
230
|
|
|
172
231
|
if build_configuration.cuda_version:
|
|
173
232
|
template = CUDA_DOCKERFILE_TEMPLATE
|
|
@@ -5,3 +5,11 @@ PIP_CONF_BUILDKIT_SECRET_MOUNT = (
|
|
|
5
5
|
PIP_CONF_SECRET_MOUNT_AS_ENV = (
|
|
6
6
|
f"PIP_CONFIG_FILE=/run/secrets/{BUILDKIT_SECRET_MOUNT_PIP_CONF_ID}"
|
|
7
7
|
)
|
|
8
|
+
|
|
9
|
+
BUILDKIT_SECRET_MOUNT_UV_CONF_ID = "uv.toml"
|
|
10
|
+
UV_CONF_BUILDKIT_SECRET_MOUNT = (
|
|
11
|
+
f"--mount=type=secret,id={BUILDKIT_SECRET_MOUNT_UV_CONF_ID}"
|
|
12
|
+
)
|
|
13
|
+
UV_CONF_SECRET_MOUNT_AS_ENV = (
|
|
14
|
+
f"UV_CONFIG_FILE=/run/secrets/{BUILDKIT_SECRET_MOUNT_UV_CONF_ID}"
|
|
15
|
+
)
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
from typing import List, Optional
|
|
2
2
|
|
|
3
|
-
from truefoundry.deploy.builder.constants import
|
|
3
|
+
from truefoundry.deploy.builder.constants import (
|
|
4
|
+
BUILDKIT_SECRET_MOUNT_PIP_CONF_ID,
|
|
5
|
+
BUILDKIT_SECRET_MOUNT_UV_CONF_ID,
|
|
6
|
+
)
|
|
4
7
|
|
|
5
8
|
|
|
6
9
|
def _get_id_from_buildkit_secret_value(value: str) -> Optional[str]:
|
|
@@ -19,14 +22,16 @@ def _get_id_from_buildkit_secret_value(value: str) -> Optional[str]:
|
|
|
19
22
|
return None
|
|
20
23
|
|
|
21
24
|
|
|
22
|
-
def
|
|
25
|
+
def has_python_package_manager_conf_secret(docker_build_extra_args: List[str]) -> bool:
|
|
23
26
|
args = [arg.strip() for arg in docker_build_extra_args]
|
|
24
27
|
for i, arg in enumerate(docker_build_extra_args):
|
|
25
28
|
if (
|
|
26
29
|
arg == "--secret"
|
|
27
30
|
and i + 1 < len(args)
|
|
28
|
-
and
|
|
29
|
-
|
|
31
|
+
and (
|
|
32
|
+
_get_id_from_buildkit_secret_value(args[i + 1])
|
|
33
|
+
in (BUILDKIT_SECRET_MOUNT_PIP_CONF_ID, BUILDKIT_SECRET_MOUNT_UV_CONF_ID)
|
|
34
|
+
)
|
|
30
35
|
):
|
|
31
36
|
return True
|
|
32
37
|
return False
|
truefoundry/deploy/cli/cli.py
CHANGED
|
@@ -9,6 +9,7 @@ from truefoundry.deploy.cli.commands import (
|
|
|
9
9
|
get_build_command,
|
|
10
10
|
get_delete_command,
|
|
11
11
|
get_deploy_command,
|
|
12
|
+
get_deploy_init_command,
|
|
12
13
|
get_login_command,
|
|
13
14
|
get_logout_command,
|
|
14
15
|
get_patch_application_command,
|
|
@@ -36,6 +37,7 @@ def create_truefoundry_cli() -> click.MultiCommand:
|
|
|
36
37
|
cli.add_command(get_logout_command())
|
|
37
38
|
cli.add_command(get_apply_command())
|
|
38
39
|
cli.add_command(get_deploy_command())
|
|
40
|
+
cli.add_command(get_deploy_init_command())
|
|
39
41
|
cli.add_command(get_patch_application_command())
|
|
40
42
|
cli.add_command(get_delete_command())
|
|
41
43
|
cli.add_command(get_trigger_command())
|
|
@@ -4,6 +4,7 @@ from truefoundry.deploy.cli.commands.build_logs_command import get_build_logs_co
|
|
|
4
4
|
from truefoundry.deploy.cli.commands.create_command import get_create_command
|
|
5
5
|
from truefoundry.deploy.cli.commands.delete_command import get_delete_command
|
|
6
6
|
from truefoundry.deploy.cli.commands.deploy_command import get_deploy_command
|
|
7
|
+
from truefoundry.deploy.cli.commands.deploy_init_command import get_deploy_init_command
|
|
7
8
|
from truefoundry.deploy.cli.commands.get_command import get_get_command
|
|
8
9
|
from truefoundry.deploy.cli.commands.list_command import get_list_command
|
|
9
10
|
from truefoundry.deploy.cli.commands.login_command import get_login_command
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import rich_click as click
|
|
2
|
+
|
|
3
|
+
from truefoundry.deploy.cli.const import GROUP_CLS
|
|
4
|
+
from truefoundry.ml.cli.commands.model_init import get_model_init_command
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@click.group(
|
|
8
|
+
name="deploy-init",
|
|
9
|
+
cls=GROUP_CLS,
|
|
10
|
+
help="Initialize the TrueFoundry deployment configuration.",
|
|
11
|
+
)
|
|
12
|
+
def deploy_init_command(): ...
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_deploy_init_command():
|
|
16
|
+
"""
|
|
17
|
+
Generates the deploy-init command.
|
|
18
|
+
model: Initialize the TrueFoundry deployment configuration for a model. eg: tfy deploy-init model [--args]
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
deploy_init_command.add_command(get_model_init_command())
|
|
22
|
+
return deploy_init_command
|
|
@@ -179,10 +179,11 @@ def trigger_job(
|
|
|
179
179
|
command=command_str if command_str else None,
|
|
180
180
|
params=params if params else None,
|
|
181
181
|
)
|
|
182
|
+
jobRunName = result.jobRunName
|
|
182
183
|
previous_runs_url = f"{client.base_url.strip('/')}/deployments/{application_info.id}?tab=previousRuns"
|
|
183
184
|
logger.info(
|
|
184
185
|
f"{message}.\n"
|
|
185
|
-
f"You can check the status of your job run at {previous_runs_url}"
|
|
186
|
+
f"You can check the status of your job run at {previous_runs_url} with jobRunName: {jobRunName}"
|
|
186
187
|
)
|
|
187
188
|
return result
|
|
188
189
|
|
|
@@ -186,6 +186,10 @@ class BasicAuthCreds(models.BasicAuthCreds, PatchedModelBase):
|
|
|
186
186
|
type: Literal["basic_auth"] = "basic_auth"
|
|
187
187
|
|
|
188
188
|
|
|
189
|
+
class JwtAuthCreds(models.JwtAuthCreds, PatchedModelBase):
|
|
190
|
+
type: Literal["jwt_auth"] = "jwt_auth"
|
|
191
|
+
|
|
192
|
+
|
|
189
193
|
class HealthProbe(models.HealthProbe, PatchedModelBase):
|
|
190
194
|
pass
|
|
191
195
|
|
|
@@ -338,6 +342,10 @@ class HelmRepo(models.HelmRepo, PatchedModelBase):
|
|
|
338
342
|
type: Literal["helm-repo"] = "helm-repo"
|
|
339
343
|
|
|
340
344
|
|
|
345
|
+
class GitHelmRepo(models.GitHelmRepo, PatchedModelBase):
|
|
346
|
+
type: Literal["git-helm-repo"] = "git-helm-repo"
|
|
347
|
+
|
|
348
|
+
|
|
341
349
|
class OCIRepo(models.OCIRepo, PatchedModelBase):
|
|
342
350
|
type: Literal["oci-repo"] = "oci-repo"
|
|
343
351
|
|
truefoundry/ml/__init__.py
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
from truefoundry.ml.autogen.client.models import
|
|
1
|
+
from truefoundry.ml.autogen.client.models import (
|
|
2
|
+
LibraryName,
|
|
3
|
+
ModelVersionEnvironment,
|
|
4
|
+
SklearnModelSchema,
|
|
5
|
+
XGBoostModelSchema,
|
|
6
|
+
)
|
|
2
7
|
from truefoundry.ml.enums import (
|
|
3
8
|
DataSlice,
|
|
4
9
|
FileFormat,
|
|
@@ -14,9 +19,7 @@ from truefoundry.ml.log_types.artifacts.artifact import (
|
|
|
14
19
|
BlobStorageDirectory,
|
|
15
20
|
)
|
|
16
21
|
from truefoundry.ml.log_types.artifacts.dataset import DataDirectory, DataDirectoryPath
|
|
17
|
-
from truefoundry.ml.log_types.artifacts.model import
|
|
18
|
-
ModelVersion,
|
|
19
|
-
)
|
|
22
|
+
from truefoundry.ml.log_types.artifacts.model import ModelVersion
|
|
20
23
|
from truefoundry.ml.logger import init_logger
|
|
21
24
|
from truefoundry.ml.mlfoundry_api import get_client
|
|
22
25
|
from truefoundry.ml.mlfoundry_run import MlFoundryRun
|
|
@@ -36,6 +39,8 @@ from truefoundry.ml.model_framework import (
|
|
|
36
39
|
TensorFlowFramework,
|
|
37
40
|
TransformersFramework,
|
|
38
41
|
XGBoostFramework,
|
|
42
|
+
sklearn_infer_schema,
|
|
43
|
+
xgboost_infer_schema,
|
|
39
44
|
)
|
|
40
45
|
|
|
41
46
|
__all__ = [
|
|
@@ -45,33 +50,37 @@ __all__ = [
|
|
|
45
50
|
"DataDirectory",
|
|
46
51
|
"DataDirectoryPath",
|
|
47
52
|
"DataSlice",
|
|
53
|
+
"FastAIFramework",
|
|
48
54
|
"FileFormat",
|
|
55
|
+
"GluonFramework",
|
|
56
|
+
"H2OFramework",
|
|
49
57
|
"Image",
|
|
50
|
-
"
|
|
58
|
+
"KerasFramework",
|
|
59
|
+
"LibraryName",
|
|
60
|
+
"LightGBMFramework",
|
|
51
61
|
"MlFoundryException",
|
|
52
|
-
"
|
|
62
|
+
"MlFoundryRun",
|
|
53
63
|
"ModelFramework",
|
|
64
|
+
"ModelFrameworkType",
|
|
54
65
|
"ModelType",
|
|
55
66
|
"ModelVersion",
|
|
56
|
-
"
|
|
57
|
-
"ViewType",
|
|
58
|
-
"get_client",
|
|
59
|
-
"FastAIFramework",
|
|
60
|
-
"GluonFramework",
|
|
61
|
-
"H2OFramework",
|
|
62
|
-
"KerasFramework",
|
|
63
|
-
"LightGBMFramework",
|
|
67
|
+
"ModelVersionEnvironment",
|
|
64
68
|
"ONNXFramework",
|
|
65
69
|
"PaddleFramework",
|
|
70
|
+
"Plot",
|
|
66
71
|
"PyTorchFramework",
|
|
67
72
|
"SklearnFramework",
|
|
73
|
+
"SklearnModelSchema",
|
|
68
74
|
"SpaCyFramework",
|
|
69
75
|
"StatsModelsFramework",
|
|
70
76
|
"TensorFlowFramework",
|
|
71
77
|
"TransformersFramework",
|
|
78
|
+
"ViewType",
|
|
72
79
|
"XGBoostFramework",
|
|
73
|
-
"
|
|
74
|
-
"
|
|
80
|
+
"XGBoostModelSchema",
|
|
81
|
+
"get_client",
|
|
82
|
+
"sklearn_infer_schema",
|
|
83
|
+
"xgboost_infer_schema",
|
|
75
84
|
]
|
|
76
85
|
|
|
77
86
|
init_logger()
|