truefoundry 0.4.1__py3-none-any.whl → 0.4.2rc1__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.

@@ -8,7 +8,7 @@ from truefoundry.common.constants import VERSION_PREFIX
8
8
  from truefoundry.common.entities import DeviceCode, Token
9
9
  from truefoundry.common.exceptions import BadRequestException
10
10
  from truefoundry.common.request_utils import request_handling, requests_retry_session
11
- from truefoundry.common.utils import poll_for_function
11
+ from truefoundry.common.utils import poll_for_function, relogin_error_message
12
12
  from truefoundry.logger import logger
13
13
 
14
14
 
@@ -16,6 +16,7 @@ class AuthServiceClient(ABC):
16
16
  def __init__(self, tenant_name: str):
17
17
  self._tenant_name = tenant_name
18
18
 
19
+ # TODO (chiragjn): Rename base_url to tfy_host
19
20
  @classmethod
20
21
  def from_base_url(cls, base_url: str) -> "AuthServiceClient":
21
22
  from truefoundry.common.servicefoundry_client import (
@@ -54,7 +55,9 @@ class ServiceFoundryServerAuthServiceClient(AuthServiceClient):
54
55
  if not token.refresh_token:
55
56
  # TODO: Add a way to propagate error messages without traceback to the output interface side
56
57
  raise Exception(
57
- f"Unable to resume login session. Please log in again using `tfy login {host_arg_str} --relogin`"
58
+ relogin_error_message(
59
+ "Unable to resume login session.", host=host_arg_str
60
+ )
58
61
  )
59
62
  url = f"{self._api_server_url}/{VERSION_PREFIX}/oauth2/token"
60
63
  data = {
@@ -70,7 +73,9 @@ class ServiceFoundryServerAuthServiceClient(AuthServiceClient):
70
73
  return Token.parse_obj(response_data)
71
74
  except BadRequestException as ex:
72
75
  raise Exception(
73
- f"Unable to resume login session. Please log in again using `tfy login {host_arg_str} --relogin`"
76
+ relogin_error_message(
77
+ "Unable to resume login session.", host=host_arg_str
78
+ )
74
79
  ) from ex
75
80
 
76
81
  def get_device_code(self) -> DeviceCode:
@@ -127,7 +132,9 @@ class AuthServerServiceClient(AuthServiceClient):
127
132
  if not token.refresh_token:
128
133
  # TODO: Add a way to propagate error messages without traceback to the output interface side
129
134
  raise Exception(
130
- f"Unable to resume login session. Please log in again using `tfy login {host_arg_str} --relogin`"
135
+ relogin_error_message(
136
+ "Unable to resume login session.", host=host_arg_str
137
+ )
131
138
  )
132
139
  url = f"{self._auth_server_url}/api/{VERSION_PREFIX}/oauth/token/refresh"
133
140
  data = {
@@ -141,7 +148,9 @@ class AuthServerServiceClient(AuthServiceClient):
141
148
  return Token.parse_obj(response_data)
142
149
  except BadRequestException as ex:
143
150
  raise Exception(
144
- f"Unable to resume login session. Please log in again using `tfy login {host_arg_str} --relogin`"
151
+ relogin_error_message(
152
+ "Unable to resume login session.", host=host_arg_str
153
+ )
145
154
  ) from ex
146
155
 
147
156
  def get_device_code(self) -> DeviceCode:
@@ -10,6 +10,7 @@ from filelock import FileLock, Timeout
10
10
 
11
11
  from truefoundry.common.constants import CREDENTIAL_FILEPATH
12
12
  from truefoundry.common.entities import CredentialsFileContent
13
+ from truefoundry.common.utils import relogin_error_message
13
14
  from truefoundry.logger import logger
14
15
 
15
16
 
@@ -87,9 +88,9 @@ class CredentialsFileManager:
87
88
  return CredentialsFileContent.parse_file(self._credentials_file_path)
88
89
  except Exception as ex:
89
90
  raise Exception(
90
- "Error while reading the credentials file "
91
- f"{self._credentials_file_path}. Please login again "
92
- "using `tfy login --relogin` or `tfy.login(relogin=True)` function"
91
+ relogin_error_message(
92
+ f"Error while reading the credentials file {self._credentials_file_path}"
93
+ )
93
94
  ) from ex
94
95
 
95
96
  @_ensure_lock_taken
@@ -6,7 +6,7 @@ from truefoundry.common.auth_service_client import AuthServiceClient
6
6
  from truefoundry.common.constants import TFY_API_KEY_ENV_KEY
7
7
  from truefoundry.common.credential_file_manager import CredentialsFileManager
8
8
  from truefoundry.common.entities import CredentialsFileContent, Token
9
- from truefoundry.common.utils import resolve_base_url
9
+ from truefoundry.common.utils import resolve_tfy_host
10
10
  from truefoundry.logger import logger
11
11
 
12
12
  TOKEN_REFRESH_LOCK = threading.RLock()
@@ -17,6 +17,7 @@ class CredentialProvider(ABC):
17
17
  @abstractmethod
18
18
  def token(self) -> Token: ...
19
19
 
20
+ # TODO (chiragjn): Rename base_url to tfy_host
20
21
  @property
21
22
  @abstractmethod
22
23
  def base_url(self) -> str: ...
@@ -34,10 +35,8 @@ class EnvCredentialProvider(CredentialProvider):
34
35
  raise Exception(
35
36
  f"Value of {TFY_API_KEY_ENV_KEY} env var should be non-empty string"
36
37
  )
37
- # TODO: Read host from cred file as well.
38
- base_url = resolve_base_url().strip("/")
39
- self._host = base_url
40
- self._auth_service = AuthServiceClient.from_base_url(base_url=base_url)
38
+ self._host = resolve_tfy_host()
39
+ self._auth_service = AuthServiceClient.from_base_url(base_url=self._host)
41
40
  self._token: Token = Token(access_token=api_key, refresh_token=None) # type: ignore[call-arg]
42
41
 
43
42
  @staticmethod
@@ -68,6 +68,7 @@ def _cached_get_python_sdk_config(api_server_url: str) -> PythonSDKConfig:
68
68
 
69
69
 
70
70
  class ServiceFoundryServiceClient:
71
+ # TODO (chiragjn): Rename base_url to tfy_host
71
72
  def __init__(self, base_url: str):
72
73
  self._base_url = base_url.strip("/")
73
74
  self._api_server_url = append_servicefoundry_path_to_base_url(self._base_url)
@@ -14,6 +14,17 @@ from truefoundry.common.constants import (
14
14
  T = TypeVar("T")
15
15
 
16
16
 
17
+ def relogin_error_message(message: str, host: str = "HOST") -> str:
18
+ suffix = ""
19
+ if host == "HOST":
20
+ suffix = " where HOST is TrueFoundry platform URL"
21
+ return (
22
+ f"{message}\n"
23
+ f"Please login again using `tfy login --host {host} --relogin` "
24
+ f"or `truefoundry.login(host={host!r}, relogin=True)` function" + suffix
25
+ )
26
+
27
+
17
28
  def timed_lru_cache(
18
29
  seconds: int = 300, maxsize: Optional[int] = None
19
30
  ) -> Callable[[Callable[..., T]], Callable[..., T]]:
@@ -42,14 +53,25 @@ def poll_for_function(
42
53
  time.sleep(poll_after_secs)
43
54
 
44
55
 
45
- def resolve_base_url(host: Optional[str] = None) -> str:
46
- if not host and not os.getenv(TFY_HOST_ENV_KEY):
56
+ def validate_tfy_host(tfy_host: str) -> str:
57
+ if not (tfy_host.startswith("https://") or tfy_host.startswith("http://")):
58
+ raise ValueError(
59
+ f"Invalid host {tfy_host!r}. It should start with https:// or http://"
60
+ )
61
+
62
+
63
+ def resolve_tfy_host(tfy_host: Optional[str] = None) -> str:
64
+ if not tfy_host and not os.getenv(TFY_HOST_ENV_KEY):
47
65
  raise ValueError(
48
- f"Either `host` should be provided by --host <value>, or `{TFY_HOST_ENV_KEY}` env must be set"
66
+ f"Either `host` should be provided using `--host <value>`, or `{TFY_HOST_ENV_KEY}` env must be set"
49
67
  )
50
- return host or os.getenv(TFY_HOST_ENV_KEY)
68
+ tfy_host = tfy_host or os.getenv(TFY_HOST_ENV_KEY)
69
+ tfy_host = tfy_host.strip("/")
70
+ validate_tfy_host(tfy_host)
71
+ return tfy_host
51
72
 
52
73
 
74
+ # TODO (chiragjn): Rename base_url to tfy_host
53
75
  def append_servicefoundry_path_to_base_url(base_url: str):
54
76
  if urlsplit(base_url).netloc.startswith("localhost"):
55
77
  return os.getenv(SERVICEFOUNDRY_SERVER_URL_ENV_KEY)
@@ -8,6 +8,7 @@ from truefoundry.common.credential_provider import (
8
8
  FileCredentialProvider,
9
9
  )
10
10
  from truefoundry.common.entities import UserInfo
11
+ from truefoundry.common.utils import relogin_error_message
11
12
  from truefoundry.logger import logger
12
13
 
13
14
  ACTIVE_SESSION: Optional[ServiceFoundrySession] = None
@@ -41,8 +42,9 @@ class ServiceFoundrySession:
41
42
  break
42
43
  if final_cred_provider is None:
43
44
  raise Exception(
44
- "Please login again using `tfy login --relogin`"
45
- "or `tfy.login(relogin=True)` function"
45
+ relogin_error_message(
46
+ "No active session found. Perhaps you are not logged in?",
47
+ )
46
48
  )
47
49
  return final_cred_provider
48
50
 
@@ -76,6 +76,7 @@ def _upload_packaged_code(metadata, package_file):
76
76
 
77
77
 
78
78
  class ServiceFoundryServiceClient(BaseServiceFoundryServiceClient):
79
+ # TODO (chiragjn): Rename base_url to tfy_host
79
80
  def __init__(self, init_session: bool = True, base_url: Optional[str] = None):
80
81
  self._session: Optional[ServiceFoundrySession] = None
81
82
  if init_session:
@@ -8,7 +8,7 @@ from truefoundry.common.constants import TFY_API_KEY_ENV_KEY, TFY_HOST_ENV_KEY
8
8
  from truefoundry.common.credential_file_manager import CredentialsFileManager
9
9
  from truefoundry.common.credential_provider import EnvCredentialProvider
10
10
  from truefoundry.common.entities import CredentialsFileContent, Token
11
- from truefoundry.common.utils import resolve_base_url
11
+ from truefoundry.common.utils import relogin_error_message, resolve_tfy_host
12
12
  from truefoundry.deploy.io.output_callback import OutputCallBack
13
13
  from truefoundry.deploy.lib.const import (
14
14
  RICH_OUTPUT_CALLBACK,
@@ -43,7 +43,7 @@ def login(
43
43
  "Login will just save the credentials on disk."
44
44
  )
45
45
 
46
- host = resolve_base_url(host).strip("/")
46
+ host = resolve_tfy_host(host)
47
47
 
48
48
  with CredentialsFileManager() as cred_file:
49
49
  if not relogin and cred_file.exists():
@@ -58,10 +58,10 @@ def login(
58
58
  user_info = cred_file_content.to_token().to_user_info()
59
59
  user_name_display_info = user_info.email or user_info.user_type.value
60
60
  output_hook.print_line(
61
- f"Already logged in to {cred_file_content.host!r} as "
62
- f"{user_info.user_id!r} ({user_name_display_info})\n"
63
- "Please use `tfy login --relogin` or `tfy.login(relogin=True)` "
64
- "to force relogin"
61
+ relogin_error_message(
62
+ f"Already logged in to {cred_file_content.host!r} as {user_info.user_id!r} ({user_name_display_info})",
63
+ host=host,
64
+ )
65
65
  )
66
66
  return False
67
67
 
@@ -144,6 +144,9 @@ from truefoundry.ml.autogen.client.models.delete_artifact_versions_request_dto i
144
144
  from truefoundry.ml.autogen.client.models.delete_dataset_request_dto import (
145
145
  DeleteDatasetRequestDto,
146
146
  )
147
+ from truefoundry.ml.autogen.client.models.delete_files_for_dataset_request_dto import (
148
+ DeleteFilesForDatasetRequestDto,
149
+ )
147
150
  from truefoundry.ml.autogen.client.models.delete_model_version_request_dto import (
148
151
  DeleteModelVersionRequestDto,
149
152
  )
@@ -73,6 +73,9 @@ from truefoundry.ml.autogen.client.models.delete_artifact_versions_request_dto i
73
73
  from truefoundry.ml.autogen.client.models.delete_dataset_request_dto import (
74
74
  DeleteDatasetRequestDto,
75
75
  )
76
+ from truefoundry.ml.autogen.client.models.delete_files_for_dataset_request_dto import (
77
+ DeleteFilesForDatasetRequestDto,
78
+ )
76
79
  from truefoundry.ml.autogen.client.models.delete_model_version_request_dto import (
77
80
  DeleteModelVersionRequestDto,
78
81
  )
@@ -2280,6 +2283,166 @@ class MlfoundryArtifactsApi:
2280
2283
  _request_auth=_params.get("_request_auth"),
2281
2284
  )
2282
2285
 
2286
+ @validate_arguments
2287
+ def delete_files_for_dataset_delete(
2288
+ self,
2289
+ delete_files_for_dataset_request_dto: DeleteFilesForDatasetRequestDto,
2290
+ **kwargs,
2291
+ ) -> object: # noqa: E501
2292
+ """Delete Files For Dataset # noqa: E501
2293
+
2294
+ Delete files from the dataset. # noqa: E501
2295
+ This method makes a synchronous HTTP request by default. To make an
2296
+ asynchronous HTTP request, please pass async_req=True
2297
+
2298
+ >>> thread = api.delete_files_for_dataset_delete(delete_files_for_dataset_request_dto, async_req=True)
2299
+ >>> result = thread.get()
2300
+
2301
+ :param delete_files_for_dataset_request_dto: (required)
2302
+ :type delete_files_for_dataset_request_dto: DeleteFilesForDatasetRequestDto
2303
+ :param async_req: Whether to execute the request asynchronously.
2304
+ :type async_req: bool, optional
2305
+ :param _request_timeout: timeout setting for this request.
2306
+ If one number provided, it will be total request
2307
+ timeout. It can also be a pair (tuple) of
2308
+ (connection, read) timeouts.
2309
+ :return: Returns the result object.
2310
+ If the method is called asynchronously,
2311
+ returns the request thread.
2312
+ :rtype: object
2313
+ """
2314
+ kwargs["_return_http_data_only"] = True
2315
+ if "_preload_content" in kwargs:
2316
+ message = "Error! Please call the delete_files_for_dataset_delete_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" # noqa: E501
2317
+ raise ValueError(message)
2318
+ return self.delete_files_for_dataset_delete_with_http_info(
2319
+ delete_files_for_dataset_request_dto, **kwargs
2320
+ ) # noqa: E501
2321
+
2322
+ @validate_arguments
2323
+ def delete_files_for_dataset_delete_with_http_info(
2324
+ self,
2325
+ delete_files_for_dataset_request_dto: DeleteFilesForDatasetRequestDto,
2326
+ **kwargs,
2327
+ ) -> ApiResponse: # noqa: E501
2328
+ """Delete Files For Dataset # noqa: E501
2329
+
2330
+ Delete files from the dataset. # noqa: E501
2331
+ This method makes a synchronous HTTP request by default. To make an
2332
+ asynchronous HTTP request, please pass async_req=True
2333
+
2334
+ >>> thread = api.delete_files_for_dataset_delete_with_http_info(delete_files_for_dataset_request_dto, async_req=True)
2335
+ >>> result = thread.get()
2336
+
2337
+ :param delete_files_for_dataset_request_dto: (required)
2338
+ :type delete_files_for_dataset_request_dto: DeleteFilesForDatasetRequestDto
2339
+ :param async_req: Whether to execute the request asynchronously.
2340
+ :type async_req: bool, optional
2341
+ :param _preload_content: if False, the ApiResponse.data will
2342
+ be set to none and raw_data will store the
2343
+ HTTP response body without reading/decoding.
2344
+ Default is True.
2345
+ :type _preload_content: bool, optional
2346
+ :param _return_http_data_only: response data instead of ApiResponse
2347
+ object with status code, headers, etc
2348
+ :type _return_http_data_only: bool, optional
2349
+ :param _request_timeout: timeout setting for this request. If one
2350
+ number provided, it will be total request
2351
+ timeout. It can also be a pair (tuple) of
2352
+ (connection, read) timeouts.
2353
+ :param _request_auth: set to override the auth_settings for an a single
2354
+ request; this effectively ignores the authentication
2355
+ in the spec for a single request.
2356
+ :type _request_auth: dict, optional
2357
+ :type _content_type: string, optional: force content-type for the request
2358
+ :return: Returns the result object.
2359
+ If the method is called asynchronously,
2360
+ returns the request thread.
2361
+ :rtype: tuple(object, status_code(int), headers(HTTPHeaderDict))
2362
+ """
2363
+
2364
+ _params = locals()
2365
+
2366
+ _all_params = ["delete_files_for_dataset_request_dto"]
2367
+ _all_params.extend(
2368
+ [
2369
+ "async_req",
2370
+ "_return_http_data_only",
2371
+ "_preload_content",
2372
+ "_request_timeout",
2373
+ "_request_auth",
2374
+ "_content_type",
2375
+ "_headers",
2376
+ ]
2377
+ )
2378
+
2379
+ # validate the arguments
2380
+ for _key, _val in _params["kwargs"].items():
2381
+ if _key not in _all_params:
2382
+ raise ApiTypeError(
2383
+ "Got an unexpected keyword argument '%s'"
2384
+ " to method delete_files_for_dataset_delete" % _key
2385
+ )
2386
+ _params[_key] = _val
2387
+ del _params["kwargs"]
2388
+
2389
+ _collection_formats = {}
2390
+
2391
+ # process the path parameters
2392
+ _path_params = {}
2393
+
2394
+ # process the query parameters
2395
+ _query_params = []
2396
+ # process the header parameters
2397
+ _header_params = dict(_params.get("_headers", {}))
2398
+ # process the form parameters
2399
+ _form_params = []
2400
+ _files = {}
2401
+ # process the body parameter
2402
+ _body_params = None
2403
+ if _params["delete_files_for_dataset_request_dto"] is not None:
2404
+ _body_params = _params["delete_files_for_dataset_request_dto"]
2405
+
2406
+ # set the HTTP header `Accept`
2407
+ _header_params["Accept"] = self.api_client.select_header_accept(
2408
+ ["application/json"]
2409
+ ) # noqa: E501
2410
+
2411
+ # set the HTTP header `Content-Type`
2412
+ _content_types_list = _params.get(
2413
+ "_content_type",
2414
+ self.api_client.select_header_content_type(["application/json"]),
2415
+ )
2416
+ if _content_types_list:
2417
+ _header_params["Content-Type"] = _content_types_list
2418
+
2419
+ # authentication setting
2420
+ _auth_settings = ["HTTPBearer", "APIKeyCookie"] # noqa: E501
2421
+
2422
+ _response_types_map = {
2423
+ "200": "object",
2424
+ "422": "HTTPValidationError",
2425
+ }
2426
+
2427
+ return self.api_client.call_api(
2428
+ "/api/2.0/mlflow/mlfoundry-artifacts/datasets/files/",
2429
+ "DELETE",
2430
+ _path_params,
2431
+ _query_params,
2432
+ _header_params,
2433
+ body=_body_params,
2434
+ post_params=_form_params,
2435
+ files=_files,
2436
+ response_types_map=_response_types_map,
2437
+ auth_settings=_auth_settings,
2438
+ async_req=_params.get("async_req"),
2439
+ _return_http_data_only=_params.get("_return_http_data_only"), # noqa: E501
2440
+ _preload_content=_params.get("_preload_content", True),
2441
+ _request_timeout=_params.get("_request_timeout"),
2442
+ collection_formats=_collection_formats,
2443
+ _request_auth=_params.get("_request_auth"),
2444
+ )
2445
+
2283
2446
  @validate_arguments
2284
2447
  def delete_model_version_post(
2285
2448
  self, delete_model_version_request_dto: DeleteModelVersionRequestDto, **kwargs
@@ -115,6 +115,9 @@ from truefoundry.ml.autogen.client.models.delete_artifact_versions_request_dto i
115
115
  from truefoundry.ml.autogen.client.models.delete_dataset_request_dto import (
116
116
  DeleteDatasetRequestDto,
117
117
  )
118
+ from truefoundry.ml.autogen.client.models.delete_files_for_dataset_request_dto import (
119
+ DeleteFilesForDatasetRequestDto,
120
+ )
118
121
  from truefoundry.ml.autogen.client.models.delete_model_version_request_dto import (
119
122
  DeleteModelVersionRequestDto,
120
123
  )
@@ -0,0 +1,68 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ FastAPI
5
+
6
+ No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
7
+
8
+ The version of the OpenAPI document: 0.1.0
9
+ Generated by OpenAPI Generator (https://openapi-generator.tech)
10
+
11
+ Do not edit the class manually.
12
+ """ # noqa: E501
13
+
14
+ from __future__ import annotations
15
+
16
+ import json
17
+ import pprint
18
+ import re # noqa: F401
19
+
20
+ from truefoundry.pydantic_v1 import BaseModel, Field, StrictStr, conlist
21
+
22
+
23
+ class DeleteFilesForDatasetRequestDto(BaseModel):
24
+ """
25
+ DeleteFilesForDatasetRequestDto
26
+ """
27
+
28
+ dataset_fqn: StrictStr = Field(...)
29
+ paths: conlist(StrictStr, max_items=100) = Field(...)
30
+ __properties = ["dataset_fqn", "paths"]
31
+
32
+ class Config:
33
+ """Pydantic configuration"""
34
+
35
+ allow_population_by_field_name = True
36
+ validate_assignment = True
37
+
38
+ def to_str(self) -> str:
39
+ """Returns the string representation of the model using alias"""
40
+ return pprint.pformat(self.dict(by_alias=True))
41
+
42
+ def to_json(self) -> str:
43
+ """Returns the JSON representation of the model using alias"""
44
+ return json.dumps(self.to_dict())
45
+
46
+ @classmethod
47
+ def from_json(cls, json_str: str) -> DeleteFilesForDatasetRequestDto:
48
+ """Create an instance of DeleteFilesForDatasetRequestDto from a JSON string"""
49
+ return cls.from_dict(json.loads(json_str))
50
+
51
+ def to_dict(self):
52
+ """Returns the dictionary representation of the model using alias"""
53
+ _dict = self.dict(by_alias=True, exclude={}, exclude_none=True)
54
+ return _dict
55
+
56
+ @classmethod
57
+ def from_dict(cls, obj: dict) -> DeleteFilesForDatasetRequestDto:
58
+ """Create an instance of DeleteFilesForDatasetRequestDto from a dict"""
59
+ if obj is None:
60
+ return None
61
+
62
+ if not isinstance(obj, dict):
63
+ return DeleteFilesForDatasetRequestDto.parse_obj(obj)
64
+
65
+ _obj = DeleteFilesForDatasetRequestDto.parse_obj(
66
+ {"dataset_fqn": obj.get("dataset_fqn"), "paths": obj.get("paths")}
67
+ )
68
+ return _obj
@@ -98,6 +98,7 @@ Class | Method | HTTP request | Description
98
98
  *MlfoundryArtifactsApi* | [**delete_artifact_post**](truefoundry/ml/autogen/client/docs/MlfoundryArtifactsApi.md#delete_artifact_post) | **POST** /api/2.0/mlflow/mlfoundry-artifacts/artifact/delete | Delete Artifact
99
99
  *MlfoundryArtifactsApi* | [**delete_artifact_version_post**](truefoundry/ml/autogen/client/docs/MlfoundryArtifactsApi.md#delete_artifact_version_post) | **POST** /api/2.0/mlflow/mlfoundry-artifacts/artifact-versions/delete | Delete Artifact Version
100
100
  *MlfoundryArtifactsApi* | [**delete_dataset_post**](truefoundry/ml/autogen/client/docs/MlfoundryArtifactsApi.md#delete_dataset_post) | **POST** /api/2.0/mlflow/mlfoundry-artifacts/datasets/delete | Delete Dataset
101
+ *MlfoundryArtifactsApi* | [**delete_files_for_dataset_delete**](truefoundry/ml/autogen/client/docs/MlfoundryArtifactsApi.md#delete_files_for_dataset_delete) | **DELETE** /api/2.0/mlflow/mlfoundry-artifacts/datasets/files/ | Delete Files For Dataset
101
102
  *MlfoundryArtifactsApi* | [**delete_model_version_post**](truefoundry/ml/autogen/client/docs/MlfoundryArtifactsApi.md#delete_model_version_post) | **POST** /api/2.0/mlflow/mlfoundry-artifacts/model-versions/delete | Delete Model Version
102
103
  *MlfoundryArtifactsApi* | [**finalize_artifact_version_post**](truefoundry/ml/autogen/client/docs/MlfoundryArtifactsApi.md#finalize_artifact_version_post) | **POST** /api/2.0/mlflow/mlfoundry-artifacts/artifact-versions/finalize | Finalize Artifact Version
103
104
  *MlfoundryArtifactsApi* | [**get_artifact_by_fqn_get**](truefoundry/ml/autogen/client/docs/MlfoundryArtifactsApi.md#get_artifact_by_fqn_get) | **GET** /api/2.0/mlflow/mlfoundry-artifacts/artifacts/get-by-fqn | Get Artifact By Fqn
@@ -197,6 +198,7 @@ Class | Method | HTTP request | Description
197
198
  - [DatasetResponseDto](truefoundry/ml/autogen/client/docs/DatasetResponseDto.md)
198
199
  - [DeleteArtifactVersionsRequestDto](truefoundry/ml/autogen/client/docs/DeleteArtifactVersionsRequestDto.md)
199
200
  - [DeleteDatasetRequestDto](truefoundry/ml/autogen/client/docs/DeleteDatasetRequestDto.md)
201
+ - [DeleteFilesForDatasetRequestDto](truefoundry/ml/autogen/client/docs/DeleteFilesForDatasetRequestDto.md)
200
202
  - [DeleteModelVersionRequestDto](truefoundry/ml/autogen/client/docs/DeleteModelVersionRequestDto.md)
201
203
  - [DeleteRunRequest](truefoundry/ml/autogen/client/docs/DeleteRunRequest.md)
202
204
  - [DeleteTagRequestDto](truefoundry/ml/autogen/client/docs/DeleteTagRequestDto.md)
@@ -0,0 +1,286 @@
1
+ # generated by datamodel-codegen:
2
+ # filename: artifacts.json
3
+ # timestamp: 2024-09-12T13:40:36+00:00
4
+
5
+ from __future__ import annotations
6
+
7
+ from enum import Enum
8
+ from typing import Any, Dict, List, Literal, Optional, Union
9
+
10
+ from truefoundry.pydantic_v1 import BaseModel, Field, constr
11
+
12
+
13
+ class Agent(BaseModel):
14
+ type: Literal["agent"] = Field(..., description="+value=agent")
15
+ name: constr(regex=r"^[a-zA-Z][a-zA-Z0-9\-]{1,30}[a-zA-Z0-9]$") = Field(
16
+ ..., description="Names cannot repeat accross agent\n+uiType=Hidden"
17
+ )
18
+ available_tools: List[constr(min_length=1)] = Field(
19
+ ..., description="+sort=30\n+uiType=Hidden"
20
+ )
21
+ goal: constr(min_length=1, max_length=128) = Field(
22
+ ..., description="+sort=10\n+uiType=TextArea"
23
+ )
24
+ instruction: constr(min_length=1, max_length=2620) = Field(
25
+ ...,
26
+ description='`instruction` is the system prompt for now. (2.5 * 1024)\n+sort=20\n+uiType=AgentInstructions\n+uiProps={"helpText":"Use the syntax ${Tool FQN} to reference a tool, and ${AGENT FQN} to reference another agent"}',
27
+ )
28
+ model_id: constr(min_length=1) = Field(
29
+ ...,
30
+ description='+sort=40\n+uiType=EnabledModelSelector\n+uiProps={"searchable":true,"modelType":"chat","providerType":"openai"}',
31
+ )
32
+
33
+
34
+ class Method(str, Enum):
35
+ """
36
+ +sort=50
37
+ +uiType=Hidden
38
+ """
39
+
40
+ get = "get"
41
+ post = "post"
42
+ put = "put"
43
+ delete = "delete"
44
+ patch = "patch"
45
+
46
+
47
+ class AgentWithFQN(Agent):
48
+ id: str
49
+ fqn: str
50
+
51
+
52
+ class MimeType(str, Enum):
53
+ """
54
+ +label=MIME Type
55
+ +usage=MIME type of the content
56
+ """
57
+
58
+ text_plain = "text/plain"
59
+ application_json = "application/json"
60
+ image_png = "image/png"
61
+ image_jpeg = "image/jpeg"
62
+ application_x_directory = "application/x-directory"
63
+
64
+
65
+ class BlobStorageReference(BaseModel):
66
+ """
67
+ +usage=Blob Storage Location
68
+ +label=Blob Storage Location
69
+ +docs=Defines the structure for blob storage content references, including type, path, and mime_type
70
+ """
71
+
72
+ type: Literal["blob-storage"]
73
+ path: constr(regex=r"^.{1,}$") = Field(
74
+ ..., description="+label=Path\n+usage=Path to the content in blob storage"
75
+ )
76
+ mime_type: MimeType = Field(
77
+ ..., description="+label=MIME Type\n+usage=MIME type of the content"
78
+ )
79
+
80
+
81
+ class ImageUrl(BaseModel):
82
+ """
83
+ +label=URL for the image
84
+ +usage=The URL for the image, must be a non-empty valid HTTPS URL or a data URL
85
+ """
86
+
87
+ url: Union[
88
+ constr(
89
+ regex=r"^\b((https?://)?(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}(?:[-a-zA-Z0-9()@:%_\+.~#?&/=]*)|data:image/[a-zA-Z]+;base64,[a-zA-Z0-9+/=\s]+)$"
90
+ ),
91
+ BlobStorageReference,
92
+ ] = Field(
93
+ ...,
94
+ description="+label=URL for the image\n+usage=The URL for the image, must be a non-empty valid HTTPS URL or a data URL",
95
+ )
96
+
97
+
98
+ class ImageContentPart(BaseModel):
99
+ """
100
+ +usage=Image URL
101
+ +label=Image URL
102
+ """
103
+
104
+ type: Literal["image_url"]
105
+ image_url: ImageUrl = Field(
106
+ ...,
107
+ description="+label=URL for the image\n+usage=The URL for the image, must be a non-empty valid HTTPS URL or a data URL",
108
+ )
109
+
110
+
111
+ class Parameters(BaseModel):
112
+ """
113
+ +usage=Parameters for the provider
114
+ +label=Parameters
115
+ +docs=Key-value pairs to store additional parameters for the provider
116
+ """
117
+
118
+ max_tokens: Optional[int] = None
119
+ temperature: Optional[float] = None
120
+ top_k: Optional[float] = None
121
+ top_p: Optional[float] = None
122
+ stop: Optional[Union[List[str], str]] = None
123
+
124
+
125
+ class ModelConfiguration(BaseModel):
126
+ """
127
+ +label=Model Configuration
128
+ +icon=fa-cogs:#326ce5
129
+ +message=Configuration details for the provider and corresponding config
130
+ +usage=Define the provider and its configuration
131
+ +docs=Configuration settings specific to the provider, including model settings and other parameters.
132
+ """
133
+
134
+ provider: str = Field(
135
+ ...,
136
+ description='+label=Provider Name\n+usage=Name of the provider, must be non-empty, e.g., "openai", "google_gemini"',
137
+ )
138
+ model: constr(regex=r"^[a-zA-Z][a-zA-Z0-9\-]{1,30}[a-zA-Z0-9]$") = Field(
139
+ ..., description="+label=Model name\n+usage=Model name, must be non-empty"
140
+ )
141
+ parameters: Optional[Parameters] = Field(
142
+ None,
143
+ description="+usage=Parameters for the provider\n+label=Parameters\n+docs=Key-value pairs to store additional parameters for the provider",
144
+ )
145
+ extra_parameters: Optional[Dict[str, Any]] = Field(
146
+ None,
147
+ description="+usage=Extra parameters for the provider\n+label=Extra Parameters\n+docs=Additional parameters for the provider",
148
+ )
149
+
150
+
151
+ class SystemMessage(BaseModel):
152
+ """
153
+ +usage=System message
154
+ +docs=Defines the structure of a system message, including role and content
155
+ +label=System Message
156
+ """
157
+
158
+ role: Literal["system"]
159
+ content: Union[constr(regex=r"^.[\s\S]*$"), BlobStorageReference] = Field(
160
+ ..., description="+label=Content\n+usage=Text content for the system message"
161
+ )
162
+ name: Optional[str] = Field(
163
+ None, description="+label=Name\n+usage=Name of the system"
164
+ )
165
+
166
+
167
+ class TextContentPart(BaseModel):
168
+ """
169
+ +usage=Text content
170
+ +label=Text content
171
+ """
172
+
173
+ type: Literal["text"]
174
+ text: Union[constr(regex=r"^.[\s\S]*$"), BlobStorageReference]
175
+
176
+
177
+ class UserMessage(BaseModel):
178
+ """
179
+ +usage=User message
180
+ +docs=Defines the structure of a user message, including role and content
181
+ +label=User Message
182
+ """
183
+
184
+ role: Literal["user"]
185
+ content: Union[
186
+ constr(regex=r"^.[\s\S]*$"),
187
+ BlobStorageReference,
188
+ List[Union[TextContentPart, ImageContentPart]],
189
+ ] = Field(
190
+ ..., description="+label=Content\n+usage=Text content for the user message"
191
+ )
192
+ name: Optional[str] = Field(
193
+ None, description="+label=Name\n+usage=Name of the user message"
194
+ )
195
+
196
+
197
+ class AgentOpenAPITool(BaseModel):
198
+ type: Literal["openapi-tool"] = Field(..., description="+value=openapi-tool")
199
+ name: constr(regex=r"^[a-zA-Z][a-zA-Z0-9\-]{1,30}[a-zA-Z0-9]$") = Field(
200
+ ..., description="Names cannot repeat accross tools\n+uiType=Hidden"
201
+ )
202
+ description: constr(min_length=1, max_length=128) = Field(
203
+ ..., description="+sort=10\n+uiType=TextArea"
204
+ )
205
+ openapi_spec: Union[BlobStorageReference, Dict[str, Any]] = Field(
206
+ ..., description="+sort=20\n+uiType=OpenapiSchema"
207
+ )
208
+ base_url: constr(
209
+ regex=r"^(https?://)?(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}(?:[-a-zA-Z0-9()@:%_\+.~#?&/=]*)$"
210
+ ) = Field(..., description="+sort=30")
211
+ path: constr(min_length=1) = Field(
212
+ ...,
213
+ description="+sort=40\n+uiType=MethodPathSelector\n+label=Method + Path\n+usage=Select one Method and Path for this tool",
214
+ )
215
+ method: Method = Field(..., description="+sort=50\n+uiType=Hidden")
216
+ headers: Optional[Dict[str, str]] = Field(
217
+ None,
218
+ description='+sort=60\n+uiType=KV\n+uiProps={"allowSecrets":true,"secretConfig":{"enableNew":true,"hideOptions":true}}',
219
+ )
220
+
221
+
222
+ class AgentOpenAPIToolWithFQN(AgentOpenAPITool):
223
+ id: str
224
+ fqn: str
225
+
226
+
227
+ class AssistantMessage(BaseModel):
228
+ """
229
+ +usage=Assistant message
230
+ +docs=Defines the structure of an assistant message, including role and content
231
+ +label=Assistant Message
232
+ """
233
+
234
+ role: Literal["assistant"]
235
+ content: Union[constr(regex=r"^.[\s\S]*$"), BlobStorageReference] = Field(
236
+ ..., description="+label=Content\n+usage=Text content for the assistant message"
237
+ )
238
+ name: Optional[str] = Field(
239
+ None, description="+label=Name\n+usage=Name of the assistant message"
240
+ )
241
+
242
+
243
+ class BasePrompt(BaseModel):
244
+ """
245
+ Main prompt structure
246
+ """
247
+
248
+ name: constr(regex=r"^[a-zA-Z][a-zA-Z0-9-_]{0,254}[a-zA-Z0-9]$") = Field(
249
+ ...,
250
+ description="+label=Prompt Name\n+icon=fa-desktop:#326ce5\n+message=Alphanumeric word, may contain '-' with a maximum length of 256 characters\n+sort=1000\n+usage=Name of the Prompt. This uniquely identifies it in the workspace.\n+docs=The unique name for the prompt, consisting of alphanumeric characters and dashes, max length 100.",
251
+ )
252
+ description: Optional[constr(min_length=1, max_length=512)] = Field(
253
+ None,
254
+ description="+label=Description\n+icon=fa-desktop:#326ce5\n+message=Description in a maximum of 512 characters\n+sort=2000\n+usage=Description of the prompt\n+docs=An optional description for the prompt, with a maximum length of 512 characters.\n+optional",
255
+ )
256
+ model_configuration: ModelConfiguration
257
+ metadata: Dict[str, str] = Field(
258
+ ...,
259
+ description="+label=Metadata\n+icon=fa-info-circle:#326ce5\n+message=Additional metadata for the prompt\n+sort=7000\n+usage=Define additional metadata for the prompt\n+docs=Key-value pairs to store additional metadata related to the prompt.",
260
+ )
261
+
262
+
263
+ class ChatPrompt(BasePrompt):
264
+ type: Literal["chat_prompt"] = Field(
265
+ ...,
266
+ description='+label=Type\n+icon=fa-desktop:#326ce5\n+message=Type of the prompt\n+sort=3000\n+usage=Type of the prompt\n+docs=Type of the prompt, set to "chat_prompt"\n+default="chat_prompt"',
267
+ )
268
+ messages: List[Union[SystemMessage, AssistantMessage, UserMessage]] = Field(
269
+ ...,
270
+ description="+sort=4000\n+usage=Chat completion messages\n+label=Messages in the chat conversation\n+message=Chat completion messages\n+usage=List of messages in the chat conversation, must be non-empty\n+docs=Messages that define the chat conversation, including system, assistant, and user messages.",
271
+ )
272
+ variables: Optional[Dict[str, Optional[str]]] = Field(
273
+ None,
274
+ description="+label=Variables\n+usage=Variables for the chat completion messages to be used in the prompt messages\n+sort=5000",
275
+ )
276
+
277
+
278
+ class AgentApp(BaseModel):
279
+ type: Literal["agent-app"] = Field(..., description="+value=agent-app")
280
+ tools: List[AgentOpenAPIToolWithFQN]
281
+ agents: List[AgentWithFQN]
282
+ root_agent: constr(min_length=1)
283
+
284
+
285
+ class Artifacts(BaseModel):
286
+ __root__: Union[ChatPrompt, AgentOpenAPITool, Agent, AgentApp]
@@ -16,6 +16,7 @@ from truefoundry.ml.run_utils import append_servicefoundry_path_to_tracking_uri
16
16
 
17
17
 
18
18
  class ServiceFoundryServiceClient(BaseServiceFoundryServiceClient):
19
+ # TODO (chiragjn): Rename tracking_uri to tfy_host
19
20
  def __init__(self, tracking_uri: str, token: Optional[str] = None):
20
21
  super().__init__(base_url=tracking_uri)
21
22
  self.host_creds = HostCreds(
@@ -5,7 +5,7 @@ import os
5
5
  import tempfile
6
6
  import uuid
7
7
  from pathlib import Path
8
- from typing import TYPE_CHECKING, Any, Dict, NamedTuple, Optional, Tuple, Union
8
+ from typing import TYPE_CHECKING, Any, Dict, List, NamedTuple, Optional, Tuple, Union
9
9
 
10
10
  from truefoundry.ml.artifact.truefoundry_artifact_repo import (
11
11
  ArtifactIdentifier,
@@ -25,6 +25,7 @@ from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
25
25
  from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
26
26
  InternalMetadata as InternalMetadataDto,
27
27
  )
28
+ from truefoundry.ml.autogen.entities.artifacts import ChatPrompt
28
29
  from truefoundry.ml.exceptions import MlFoundryException
29
30
  from truefoundry.ml.log_types.artifacts.constants import INTERNAL_METADATA_PATH
30
31
  from truefoundry.ml.log_types.artifacts.utils import (
@@ -351,6 +352,63 @@ class ArtifactVersion:
351
352
  self._set_mutable_attrs()
352
353
 
353
354
 
355
+ class ChatPromptVersion(ArtifactVersion):
356
+ def __init__(self, artifact_version: ArtifactVersionDto, artifact: ArtifactDto):
357
+ if artifact.type != ArtifactType.CHAT_PROMPT:
358
+ raise ValueError(
359
+ f"{artifact_version.fqn!r} is not a chat prompt type artifact"
360
+ )
361
+ super().__init__(
362
+ artifact_version=artifact_version,
363
+ artifact=artifact,
364
+ )
365
+ self._chat_prompt = ChatPrompt.parse_obj(
366
+ artifact_version.internal_metadata.to_dict()
367
+ )
368
+
369
+ @classmethod
370
+ def from_fqn(cls, fqn: str) -> "ChatPromptVersion":
371
+ api_client = _get_api_client()
372
+ mlfoundry_artifacts_api = MlfoundryArtifactsApi(api_client=api_client)
373
+ _artifact_version = mlfoundry_artifacts_api.get_artifact_version_by_fqn_get(
374
+ fqn=fqn
375
+ )
376
+ artifact_version = _artifact_version.artifact_version
377
+ _artifact = mlfoundry_artifacts_api.get_artifact_by_id_get(
378
+ id=artifact_version.artifact_id
379
+ )
380
+ return cls(
381
+ artifact_version=_artifact_version.artifact_version,
382
+ artifact=_artifact.artifact,
383
+ )
384
+
385
+ @property
386
+ def model(self) -> str:
387
+ return self._chat_prompt.model_configuration.model
388
+
389
+ @property
390
+ def provider(self) -> str:
391
+ return self._chat_prompt.model_configuration.provider
392
+
393
+ @property
394
+ def messages(self) -> List[Dict[str, Any]]:
395
+ return [message.dict() for message in self._chat_prompt.messages]
396
+
397
+ @property
398
+ def parameters(self) -> Dict[str, Any]:
399
+ _parameters = self._chat_prompt.model_configuration.parameters
400
+ return _parameters.dict(exclude_unset=True) if _parameters else {}
401
+
402
+ @property
403
+ def extra_parameters(self) -> Dict[str, Any]:
404
+ _extra_parameters = self._chat_prompt.model_configuration.extra_parameters
405
+ return _extra_parameters.dict(exclude_unset=True) if _extra_parameters else {}
406
+
407
+ @property
408
+ def variables(self) -> Dict[str, Any]:
409
+ return self._chat_prompt.variables or {}
410
+
411
+
354
412
  def _log_artifact_version_helper(
355
413
  run: "MlFoundryRun",
356
414
  name: str,
@@ -7,6 +7,7 @@ from typing import Any, Dict, Iterator, List, Optional, Sequence, Tuple, Union
7
7
  import coolname
8
8
  import pandas as pd
9
9
 
10
+ from truefoundry.common.utils import relogin_error_message
10
11
  from truefoundry.ml import constants, env_vars
11
12
  from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
12
13
  ArtifactDto,
@@ -34,7 +35,11 @@ from truefoundry.ml.clients.servicefoundry_client import ServiceFoundryServiceCl
34
35
  from truefoundry.ml.enums import ModelFramework, ViewType
35
36
  from truefoundry.ml.exceptions import MlFoundryException
36
37
  from truefoundry.ml.internal_namespace import NAMESPACE
37
- from truefoundry.ml.log_types.artifacts.artifact import ArtifactPath, ArtifactVersion
38
+ from truefoundry.ml.log_types.artifacts.artifact import (
39
+ ArtifactPath,
40
+ ArtifactVersion,
41
+ ChatPromptVersion,
42
+ )
38
43
  from truefoundry.ml.log_types.artifacts.dataset import DataDirectory
39
44
  from truefoundry.ml.log_types.artifacts.general_artifact import _log_artifact_version
40
45
  from truefoundry.ml.log_types.artifacts.model import ModelVersion, _log_model_version
@@ -209,8 +214,9 @@ class MlFoundry:
209
214
  session = get_active_session()
210
215
  if session is None:
211
216
  raise MlFoundryException(
212
- "No active session found. Perhaps you are not logged in?\n"
213
- "Please log in using `tfy login [--host HOST] --relogin"
217
+ relogin_error_message(
218
+ "No active session found. Perhaps you are not logged in?",
219
+ )
214
220
  )
215
221
  servicefoundry_client = ServiceFoundryServiceClient(
216
222
  tracking_uri=self.get_tracking_uri(),
@@ -1554,6 +1560,45 @@ class MlFoundry:
1554
1560
  if not datasets or not page_token:
1555
1561
  done = True
1556
1562
 
1563
+ def get_chat_prompt_version_by_fqn(self, fqn: str) -> ChatPromptVersion:
1564
+ """
1565
+ Get the prompt by prompt version FQN
1566
+ Args:
1567
+ fqn (str): Fully qualified name of the chat prompt version.
1568
+ Returns:
1569
+ ChatPromptVersion: An instance of the ChatPromptVersion class with the fetched prompt details.
1570
+
1571
+ Examples:
1572
+ ```python
1573
+ from truefoundry.ml import get_client
1574
+ client = get_client()
1575
+
1576
+ # Get the chat prompt by FQN
1577
+ fqn = 'chat_prompt:truefoundry/prompt-demo/demo-prompt-1:2'
1578
+ chat_prompt = client.get_chat_prompt_version_by_fqn(fqn=fqn)
1579
+
1580
+ # Check the chat prompt values
1581
+ print(chat_prompt)
1582
+
1583
+ # Use with OpenAI client
1584
+ from openai import OpenAI
1585
+ openai_client = OpenAI(api_key="api_key")
1586
+
1587
+ # Make the OpenAI call
1588
+ response = openai_client.chat.completions.create(
1589
+ model=chat_prompt.model,
1590
+ messages=chat_prompt.messages,
1591
+ **chat_prompt.parameters,
1592
+ **chat_prompt.extra_parameters
1593
+ )
1594
+
1595
+ # Extract the content from the response
1596
+ response_content = response.choices[0].message.content
1597
+ print(response_content)
1598
+ ```
1599
+ """
1600
+ return ChatPromptVersion.from_fqn(fqn=fqn)
1601
+
1557
1602
 
1558
1603
  def get_client() -> MlFoundry:
1559
1604
  """Initializes and returns the mlfoundry client.
@@ -19,6 +19,7 @@ from typing import (
19
19
  from urllib.parse import urljoin, urlsplit
20
20
 
21
21
  from truefoundry import version
22
+ from truefoundry.common.utils import relogin_error_message
22
23
  from truefoundry.ml import constants, enums
23
24
  from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
24
25
  ArtifactType,
@@ -222,8 +223,9 @@ class MlFoundryRun:
222
223
  session = get_active_session()
223
224
  if session is None:
224
225
  raise MlFoundryException(
225
- "No active session found. Perhaps you are not logged in?\n"
226
- "Please log in using `tfy login [--host HOST] --relogin"
226
+ relogin_error_message(
227
+ "No active session found. Perhaps you are not logged in?",
228
+ )
227
229
  )
228
230
  base_url = "{uri.scheme}://{uri.netloc}/".format(
229
231
  uri=urlsplit(session.tracking_uri)
truefoundry/ml/session.py CHANGED
@@ -10,6 +10,7 @@ from truefoundry.common.credential_provider import (
10
10
  )
11
11
  from truefoundry.common.entities import Token, UserInfo
12
12
  from truefoundry.common.request_utils import urllib3_retry
13
+ from truefoundry.common.utils import relogin_error_message
13
14
  from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
14
15
  ApiClient,
15
16
  Configuration,
@@ -83,6 +84,7 @@ class Session:
83
84
  self._assert_not_closed()
84
85
  return self._user_info
85
86
 
87
+ # TODO (chiragjn): Rename tracking_uri to tfy_host
86
88
  @property
87
89
  def tracking_uri(self) -> str:
88
90
  return self._cred_provider.base_url
@@ -120,8 +122,9 @@ def _get_api_client(
120
122
  return ApiClient()
121
123
  else:
122
124
  raise MlFoundryException(
123
- "No active session found. Perhaps you are not logged in?\n"
124
- "Please log in using `tfy login [--host HOST] --relogin"
125
+ relogin_error_message(
126
+ "No active session found. Perhaps you are not logged in?",
127
+ )
125
128
  )
126
129
 
127
130
  creds = session.get_host_creds()
@@ -144,8 +147,9 @@ def init_session() -> Session:
144
147
  break
145
148
  if final_cred_provider is None:
146
149
  raise MlFoundryException(
147
- "Please login using `tfy login` command "
148
- "or `truefoundry.login()` function call"
150
+ relogin_error_message(
151
+ "No active session found. Perhaps you are not logged in?",
152
+ )
149
153
  )
150
154
  new_session = Session(cred_provider=final_cred_provider)
151
155
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: truefoundry
3
- Version: 0.4.1
3
+ Version: 0.4.2rc1
4
4
  Summary: Truefoundry CLI
5
5
  Author: Abhishek Choudhary
6
6
  Author-email: abhishek@truefoundry.com
@@ -26,15 +26,15 @@ truefoundry/autodeploy/utils/pydantic_compat.py,sha256=hEAUy5kLjhPdzw7yGZ2iXGMXb
26
26
  truefoundry/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
27
  truefoundry/cli/__main__.py,sha256=-NkhYlT3mC5MhtekueKAvCw-sWvguj0LJRpXWzvvFjc,727
28
28
  truefoundry/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
- truefoundry/common/auth_service_client.py,sha256=upUTo6VODAaOKtszCQZNWnPpRT8CEhpCq9RLBJ0RrRY,7840
29
+ truefoundry/common/auth_service_client.py,sha256=tZOa0NdATnItsMeTnEnUeTZQIgUJtpU-nvLdWtB4Px8,7978
30
30
  truefoundry/common/constants.py,sha256=kHP5ebp7EMfEYaOC-K8T_XPfYi7mXttYgrXYS8bOgkg,359
31
- truefoundry/common/credential_file_manager.py,sha256=MRn5h9Gm4pxZEF_XT-_b2agMBiqyw0o2SLpq9ty_1lY,4255
32
- truefoundry/common/credential_provider.py,sha256=UHr3tH39wGjhC3XdRUdgW7IZeh0cHSIEYJMVO8B4eyw,4107
31
+ truefoundry/common/credential_file_manager.py,sha256=1yEk1Zm2xS4G0VDFwKSZ4w0VUrcPWQ1nJnoBaz9xyKA,4251
32
+ truefoundry/common/credential_provider.py,sha256=YQ6HKl8ZZFTg48vBZMauEAnM6IrEO3oOzM2DA47N-P0,4071
33
33
  truefoundry/common/entities.py,sha256=8O-EGPk4PKqnyoFMKUTxISCU19rz0KBnfRDJU695DhY,3797
34
34
  truefoundry/common/exceptions.py,sha256=ePpiQ_zmWe4e94gOgeMiyP_AZnKwjEBfyXsB5ScGYcI,329
35
35
  truefoundry/common/request_utils.py,sha256=-ss8033PClJOMJuS5Ue1zCFRVK7ZW9vjtva1b5G9uok,2849
36
- truefoundry/common/servicefoundry_client.py,sha256=ornmmhjSY2y-NJeBcoHPKxX3q9Z9XilcHERFSFk-dSU,2886
37
- truefoundry/common/utils.py,sha256=DbyLQM4WiKxzIStg2Ekv7fLs8amZR0HtsF75uqy8tMc,1741
36
+ truefoundry/common/servicefoundry_client.py,sha256=qYSrsbFH8b7N_2oxlXfbJnWfdqHCBQ1dQ5Rr2tdp3zQ,2937
37
+ truefoundry/common/utils.py,sha256=f5Av8X70vZf6eUK4Axm8q75It2-C-3o3uomA0GrFt_4,2506
38
38
  truefoundry/deploy/__init__.py,sha256=ugawKF2G02EmEXX35oZ2tec12d9oWN28Sf6mtGGIERY,2281
39
39
  truefoundry/deploy/auto_gen/models.py,sha256=I4-tV2V74mljN7lH606pCD5LArK6MvND_i7Vt_aRI5Q,79952
40
40
  truefoundry/deploy/builder/__init__.py,sha256=a1qR6nicHGcxRaeNTxWRsmDs8zsmXc7j13-I8q0qqVk,4938
@@ -88,9 +88,9 @@ truefoundry/deploy/io/output_callback.py,sha256=V2YwUFec4G4a67lM4r-x_64AqdOVNo_9
88
88
  truefoundry/deploy/io/rich_output_callback.py,sha256=TJLiRD-EnFVwgcepxR7WN0koKqW1X2DevETPhNPi_nU,829
89
89
  truefoundry/deploy/json_util.py,sha256=x_-7YYQ4_HUIJ8ofOcclAp9JWhgTWjR9Th6Q0FuRqGk,175
90
90
  truefoundry/deploy/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
- truefoundry/deploy/lib/auth/servicefoundry_session.py,sha256=d4M56O_ZftFeDRiyRci11QABU9B1HW2eVOeVIrFvevE,1842
91
+ truefoundry/deploy/lib/auth/servicefoundry_session.py,sha256=5TCYPunAygtn5mb0mp_VcWKEalKMKPbyWMWer-Vty2g,1916
92
92
  truefoundry/deploy/lib/clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
93
- truefoundry/deploy/lib/clients/servicefoundry_client.py,sha256=fgou4wjuWJzqQgW7iatbSCvmstSjY0iUJldQK5vsruE,26018
93
+ truefoundry/deploy/lib/clients/servicefoundry_client.py,sha256=yzbXnVGmILD5BUMLzCHloJiz7YBWU0OCtrE3V09R9vA,26069
94
94
  truefoundry/deploy/lib/clients/shell_client.py,sha256=tMrc0Ha1DmGtUCJrZD8eusOzfe8R_WIe6AAH7nxL0xA,461
95
95
  truefoundry/deploy/lib/const.py,sha256=FCQfnO7IecB1ikQHdLGNvvubq_iF900C9l5TJtDfvFc,314
96
96
  truefoundry/deploy/lib/dao/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -103,7 +103,7 @@ truefoundry/deploy/lib/logs_utils.py,sha256=SQxRv3jDDmgHdOUMhlMaAPGYskybnBUMpst7
103
103
  truefoundry/deploy/lib/messages.py,sha256=nhp0bCYf_XpUM68hTq5lBY-__vtEyV2uP7NgnJXJ_Vg,925
104
104
  truefoundry/deploy/lib/model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
105
105
  truefoundry/deploy/lib/model/entity.py,sha256=8J8yd98iWtSy8giShdDRNyzbN1UgSXx4XtmZLljdWnE,8552
106
- truefoundry/deploy/lib/session.py,sha256=e0iA-fWPBzxm5JqT4hnfv4NOpYexbrtRLSWLqqVtFzs,4986
106
+ truefoundry/deploy/lib/session.py,sha256=Vg6rCA315T0yS0xG4ayJ84Ia_9ZfibH8utOSwPBMAmw,4953
107
107
  truefoundry/deploy/lib/util.py,sha256=RlL3bjZu5Z0LU_OKYaMVfcMU8k7_rmkAp89_0CrZDLk,1520
108
108
  truefoundry/deploy/lib/win32.py,sha256=1RcvPTdlOAJ48rt8rCbE2Ufha2ztRqBAE9dueNXArrY,5009
109
109
  truefoundry/deploy/python_deploy_codegen.py,sha256=Ok7ufDY2x3aMJv9KpaRqxiS-ZI-kxBWauIUHst-ug7E,4020
@@ -126,14 +126,14 @@ truefoundry/ml/__init__.py,sha256=2A1l7pgqbVRt3cRW_0Lxg92hyJEkMxkCUh1EFprrmc0,94
126
126
  truefoundry/ml/artifact/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
127
127
  truefoundry/ml/artifact/truefoundry_artifact_repo.py,sha256=dA_QYAyNCcCuOw5eVxPbU5OeMK8YBNh42vBnGf6I0Sw,44911
128
128
  truefoundry/ml/autogen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
129
- truefoundry/ml/autogen/client/__init__.py,sha256=9tmMg8M1td9h0zbAAdl8Lla3A33iU1XNMKx6pZj1yzA,16524
129
+ truefoundry/ml/autogen/client/__init__.py,sha256=M68r1z8Mi6dEFFKDsWPJ9NGdNOYdm6pcdH7_srCwkCI,16651
130
130
  truefoundry/ml/autogen/client/api/__init__.py,sha256=3sMSljMIS3UHYeF0BcNvrPPx6VbBSRt_1IfDn-13Kyc,752
131
131
  truefoundry/ml/autogen/client/api/auth_api.py,sha256=zpWzJhUmW6HHMY_atlUf0B25k77E1kue2hmix5I5Ih0,7017
132
132
  truefoundry/ml/autogen/client/api/deprecated_api.py,sha256=JCQ39Y3VHdgJ1zM4XVabdTl6QpOHtQFjh04XUb6mN9A,24218
133
133
  truefoundry/ml/autogen/client/api/experiments_api.py,sha256=vzlPMzclwk7oD2ekUBInIAHLNO3qCAPF38AAvxfDBSY,80682
134
134
  truefoundry/ml/autogen/client/api/health_api.py,sha256=IAPhRAo9CLUT5ipVR1fCf-qDx57UR0wg5ekhtUl8lug,11554
135
135
  truefoundry/ml/autogen/client/api/metrics_api.py,sha256=q3L38eD-2hu4_9YvcSdnWDYXD2V8il-X9reinOAABek,14908
136
- truefoundry/ml/autogen/client/api/mlfoundry_artifacts_api.py,sha256=CzhvDh_ZrsKmVVeX2fqNbfbWkCvosUQhkTEHx2pLGCo,306479
136
+ truefoundry/ml/autogen/client/api/mlfoundry_artifacts_api.py,sha256=Le1fSNI8NwsYKhs-LTpH1fVuTP5YUp99D3WbZkQeo_8,313447
137
137
  truefoundry/ml/autogen/client/api/python_deployment_config_api.py,sha256=8P53aegaaZp1LEV9_GDNSCofgxRXP3Atyprc2bUvvpI,8348
138
138
  truefoundry/ml/autogen/client/api/run_artifacts_api.py,sha256=x-vVnY2LEFChZxiiFauswRWwFz6Qqh30PKXjzuTvxmc,8799
139
139
  truefoundry/ml/autogen/client/api/runs_api.py,sha256=-aghrZ2VYuZOw_vBtOzWDsnK7Ji29oZQxK2CLRgyo2w,119232
@@ -141,7 +141,7 @@ truefoundry/ml/autogen/client/api_client.py,sha256=8qg-WpadDuKgbRt5yABJ4wVS4IRxd
141
141
  truefoundry/ml/autogen/client/api_response.py,sha256=KRyvecPMXF05PaxILHZ8JHoP4rgKBjKONMgG83aU-rM,844
142
142
  truefoundry/ml/autogen/client/configuration.py,sha256=V1oaEnxt-NfpaNmp-EZpf2glovzVhM2coWYt8HBNB4M,15723
143
143
  truefoundry/ml/autogen/client/exceptions.py,sha256=XbCbDHhYT3BVejdoGNPgEa4oS56ypkwFdxk1iOc_tFY,5355
144
- truefoundry/ml/autogen/client/models/__init__.py,sha256=IS04fIw-KPC87XbVETy7dFS2Exrpm3IMupfBf8E5ym8,15140
144
+ truefoundry/ml/autogen/client/models/__init__.py,sha256=9zOPn2LD-j3EbZmtt8ShBU8uGMRVpTW2-kvooBG9feE,15267
145
145
  truefoundry/ml/autogen/client/models/add_custom_metrics_to_model_version_request_dto.py,sha256=_ISDspicTGjBCYYXubKfRYYSSQVyW3AvG-jFh47-Zfc,2163
146
146
  truefoundry/ml/autogen/client/models/add_features_to_model_version_request_dto.py,sha256=rU0h96pEE8K1Ukw2pzDSjq0e6BgtDEuOctI-aZMrpUY,2653
147
147
  truefoundry/ml/autogen/client/models/agent.py,sha256=fnMWdEPe5Iw50WKydtu7QAxU419j3ju1IukpChUnGqY,3871
@@ -186,6 +186,7 @@ truefoundry/ml/autogen/client/models/dataset_dto.py,sha256=2GqBLyIFXjNJ8stQRQgB1
186
186
  truefoundry/ml/autogen/client/models/dataset_response_dto.py,sha256=5h3eHpiG4Zzqn5Hm0WpZgyXGjxujKem42_8YnGq5KLo,2205
187
187
  truefoundry/ml/autogen/client/models/delete_artifact_versions_request_dto.py,sha256=JF2dQuEe_W1c2ox9zZDER_pZSTbKwSnns8hIfG5o7oA,1905
188
188
  truefoundry/ml/autogen/client/models/delete_dataset_request_dto.py,sha256=bfzzgBoekOBcGg2Uzzel80rf2Z5fDgggShkYd0ZlbSM,2143
189
+ truefoundry/ml/autogen/client/models/delete_files_for_dataset_request_dto.py,sha256=-J1HeTo1utlA9FtoUGXuLXxKZeHLRux1VnpiiwINPLE,2058
189
190
  truefoundry/ml/autogen/client/models/delete_model_version_request_dto.py,sha256=6abYuueylSgv7TLkIHq8X0NWeFr-J5k72caAyOnn6fw,1873
190
191
  truefoundry/ml/autogen/client/models/delete_run_request.py,sha256=jXQmROKfkPA8idoxkUXT-2O6QJ4OgxgFX-CEmjryIpY,1793
191
192
  truefoundry/ml/autogen/client/models/delete_tag_request_dto.py,sha256=eQSPMamCJbsehcwWoMxQxlzZKQfX5GEwm3KHGF2Ajts,1901
@@ -287,14 +288,15 @@ truefoundry/ml/autogen/client/models/user_message.py,sha256=6QOmKT_SDfAVZA8V3Bzo
287
288
  truefoundry/ml/autogen/client/models/validation_error.py,sha256=mFjwoc8g2-Usu1HXZhOQKQ4TGvLy4lwCzk8dHrJ69aA,2597
288
289
  truefoundry/ml/autogen/client/models/validation_error_loc_inner.py,sha256=nThJ5Gmy8W2Wok-ZOI4sK7uRe1BAkLS0qzq-XZbq8zs,4915
289
290
  truefoundry/ml/autogen/client/rest.py,sha256=9goba8qHjQuVx5O_yRaTKu7PvBnb7r7swfy3dwuTEgk,14281
290
- truefoundry/ml/autogen/client_README.md,sha256=lobq-OlEcetj90WhMC1EmFQ85Bivmg2OPY2_CT1zc94,32876
291
+ truefoundry/ml/autogen/client_README.md,sha256=8Pd74fIjHyzidtS6HGpusUgHj__nIdd_W6mBsi7tgRQ,33233
292
+ truefoundry/ml/autogen/entities/artifacts.py,sha256=iIzfMPKLXZpzxu55lG0k3edraaZqXS4DLc6-FMzxk6g,10159
291
293
  truefoundry/ml/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
292
294
  truefoundry/ml/cli/cli.py,sha256=ckBcjUpqfhgrPE1okqT_G2iouOLt-0KjpLhHp2YdVFU,256
293
295
  truefoundry/ml/cli/commands/__init__.py,sha256=diDUiRUX4l6TtNLI4iF-ZblczkELM7FRViJ-8gGNJQY,82
294
296
  truefoundry/ml/cli/commands/download.py,sha256=cbz9KijiLKXj4-twlig3xZLTVRNm4fnjwpy0leZr31w,2342
295
297
  truefoundry/ml/clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
296
298
  truefoundry/ml/clients/entities.py,sha256=sNP4DnAVdQoMfc06s0r3VTzKHTo7jmxAOuTlQOVmsMs,151
297
- truefoundry/ml/clients/servicefoundry_client.py,sha256=lK7mepLNRHHS65Eebynk5HyCMSxqmduXRHO2k8pTIK0,1680
299
+ truefoundry/ml/clients/servicefoundry_client.py,sha256=w8fgZWZF_JjRpL_ZRmLw1BiI7aqDHnJcAXluBgwft0s,1735
298
300
  truefoundry/ml/clients/utils.py,sha256=c0LdC8moejs-Zm30hu1sCqifLEmqhdq4SfZ_m0nUIDk,4402
299
301
  truefoundry/ml/constants.py,sha256=vDq72d4C9FSWqr9MMdjgTF4TuyNFApvo_6RVsSeAjB4,2837
300
302
  truefoundry/ml/entities.py,sha256=si5GAqZsWzKu5MPrU4Hk6se7bebHOYhTiNw69ai-Uk8,1485
@@ -304,7 +306,7 @@ truefoundry/ml/exceptions.py,sha256=8aJm2NYtAWWsRLu4MbzaoOqHsQZ6RjOFwBWQWqb6qrc,
304
306
  truefoundry/ml/git_info.py,sha256=jvAVm9ilqivnGq8qJdUvYdd8Siv0PLtqurB-PXsS5ho,2023
305
307
  truefoundry/ml/internal_namespace.py,sha256=QcqMHp6-C2im2H_02hlhi01EIcr1HhNaZprszs13EMU,1790
306
308
  truefoundry/ml/log_types/__init__.py,sha256=g4u4D4Jaj0aBK5GtrLV88-qThKZR9pSZ17vFEkN-LmM,125
307
- truefoundry/ml/log_types/artifacts/artifact.py,sha256=KrQhROx82rT9Trzoj_-Lq6Ya5vuIzoRVIbjBiPz_sNc,15511
309
+ truefoundry/ml/log_types/artifacts/artifact.py,sha256=pNgLc6GaQ0UVJ6gaSRzpAW5CmGpJMC4iBgBY5FLlofc,17640
308
310
  truefoundry/ml/log_types/artifacts/constants.py,sha256=qKxQ5mMvJE4j83BvGW3qNTKunxCiBg_EEjTdgbgJtyE,1036
309
311
  truefoundry/ml/log_types/artifacts/dataset.py,sha256=oXi7itXOe3PrnN4_KY7s1GdhWV1lyvWXRWgY6_vPTAs,12981
310
312
  truefoundry/ml/log_types/artifacts/general_artifact.py,sha256=fY74EUeCGdHdlkrp_GMoaZPvl7EQctt8OlRM6yFgLF8,3772
@@ -320,10 +322,10 @@ truefoundry/ml/log_types/plot.py,sha256=oFnXNb2o5fVF0zsnRjvqjSjLaphQWUnQCdw72e2u
320
322
  truefoundry/ml/log_types/pydantic_base.py,sha256=eBlw_AEyAz4iJKDP4zgJOCFWcldwQqpf7FADW1jzIQY,272
321
323
  truefoundry/ml/log_types/utils.py,sha256=xjJ21jdPScvFmw3TbVh5NCzbzJwaqiXJyiiT4xxX1EI,335
322
324
  truefoundry/ml/logger.py,sha256=VT-BF3BnBYTWVq87O58F0c8uXMu94gYzsiFlGY3_7Ao,458
323
- truefoundry/ml/mlfoundry_api.py,sha256=7RZZaMd6Z1f-qekpEFhjgqgDAFUZ3_7iZbzrRAhVj58,59379
324
- truefoundry/ml/mlfoundry_run.py,sha256=CTUgf2-kPANie9Kog_rJRvpkDfotVzWTHvBg2ofv_FA,44341
325
+ truefoundry/ml/mlfoundry_api.py,sha256=I2T8tXeAIWpD8EH05fm80mNyX6cs2S1ORI4qoo0HTpQ,60847
326
+ truefoundry/ml/mlfoundry_run.py,sha256=gl1aA_j7KwtyOpZgTTi3boWxpdTyssGGFh_lP40mc1o,44387
325
327
  truefoundry/ml/run_utils.py,sha256=dzbQ_TGkSCYO-gg8tlr5tglR0p2SIQdy0wl4IEQE5JA,2899
326
- truefoundry/ml/session.py,sha256=gASORQ7TZ3kqAyqG64YPfn5Z8Uo2BjOvfhMmTX-X7uM,5263
328
+ truefoundry/ml/session.py,sha256=_WmaGNiZCwQVmB-brbX-z38nFvuqP8f7jGxfqJoq3TM,5385
327
329
  truefoundry/ml/validation_utils.py,sha256=XBSUd9OoyriWJpT3M5LKz17iWY3yVMr3hM5vdaVjtf0,12082
328
330
  truefoundry/pydantic_v1.py,sha256=jSuhGtz0Mbk1qYu8jJ1AcnIDK4oxUsdhALc4spqstmM,345
329
331
  truefoundry/version.py,sha256=bqiT4Q-VWrTC6P4qfK43mez-Ppf-smWfrl6DcwV7mrw,137
@@ -338,7 +340,7 @@ truefoundry/workflow/map_task.py,sha256=2m3qGXQ90k9LdS45q8dqCCECc3qr8t2m_LMCVd1m
338
340
  truefoundry/workflow/python_task.py,sha256=SRXRLC4vdBqGjhkwuaY39LEWN6iPCpJAuW17URRdWTY,1128
339
341
  truefoundry/workflow/task.py,sha256=ToitYiKcNzFCtOVQwz1W8sRjbR97eVS7vQBdbgUQtKg,1779
340
342
  truefoundry/workflow/workflow.py,sha256=WaTqUjhwfAXDWu4E5ehuwAxrCbDJkoAf1oWmR2E9Qy0,4575
341
- truefoundry-0.4.1.dist-info/METADATA,sha256=rPzMg57cm984bDhYSIO7oqFqYCy-shU4fXOiVceU35Y,3137
342
- truefoundry-0.4.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
343
- truefoundry-0.4.1.dist-info/entry_points.txt,sha256=TXvUxQkI6zmqJuycPsyxEIMr3oqfDjgrWj0m_9X12x4,95
344
- truefoundry-0.4.1.dist-info/RECORD,,
343
+ truefoundry-0.4.2rc1.dist-info/METADATA,sha256=WmKC8UIgG2oVxwmlurcKI9T3aL0TTxfB8oiKuywh-uU,3140
344
+ truefoundry-0.4.2rc1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
345
+ truefoundry-0.4.2rc1.dist-info/entry_points.txt,sha256=TXvUxQkI6zmqJuycPsyxEIMr3oqfDjgrWj0m_9X12x4,95
346
+ truefoundry-0.4.2rc1.dist-info/RECORD,,