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

Files changed (99) hide show
  1. truefoundry/__init__.py +1 -0
  2. truefoundry/autodeploy/cli.py +31 -18
  3. truefoundry/deploy/__init__.py +118 -1
  4. truefoundry/deploy/auto_gen/models.py +1675 -0
  5. truefoundry/deploy/builder/__init__.py +116 -0
  6. truefoundry/deploy/builder/builders/__init__.py +22 -0
  7. truefoundry/deploy/builder/builders/dockerfile.py +57 -0
  8. truefoundry/deploy/builder/builders/tfy_notebook_buildpack/__init__.py +44 -0
  9. truefoundry/deploy/builder/builders/tfy_notebook_buildpack/dockerfile_template.py +51 -0
  10. truefoundry/deploy/builder/builders/tfy_python_buildpack/__init__.py +44 -0
  11. truefoundry/deploy/builder/builders/tfy_python_buildpack/dockerfile_template.py +158 -0
  12. truefoundry/deploy/builder/docker_service.py +168 -0
  13. truefoundry/deploy/cli/cli.py +19 -26
  14. truefoundry/deploy/cli/commands/__init__.py +18 -0
  15. truefoundry/deploy/cli/commands/apply_command.py +52 -0
  16. truefoundry/deploy/cli/commands/build_command.py +45 -0
  17. truefoundry/deploy/cli/commands/build_logs_command.py +89 -0
  18. truefoundry/deploy/cli/commands/create_command.py +75 -0
  19. truefoundry/deploy/cli/commands/delete_command.py +77 -0
  20. truefoundry/deploy/cli/commands/deploy_command.py +99 -0
  21. truefoundry/deploy/cli/commands/get_command.py +216 -0
  22. truefoundry/deploy/cli/commands/list_command.py +171 -0
  23. truefoundry/deploy/cli/commands/login_command.py +33 -0
  24. truefoundry/deploy/cli/commands/logout_command.py +20 -0
  25. truefoundry/deploy/cli/commands/logs_command.py +134 -0
  26. truefoundry/deploy/cli/commands/patch_application_command.py +79 -0
  27. truefoundry/deploy/cli/commands/patch_command.py +70 -0
  28. truefoundry/deploy/cli/commands/redeploy_command.py +41 -0
  29. truefoundry/deploy/cli/commands/terminate_comand.py +44 -0
  30. truefoundry/deploy/cli/commands/trigger_command.py +87 -0
  31. truefoundry/deploy/cli/config.py +10 -0
  32. truefoundry/deploy/cli/console.py +5 -0
  33. truefoundry/deploy/cli/const.py +12 -0
  34. truefoundry/deploy/cli/display_util.py +118 -0
  35. truefoundry/deploy/cli/util.py +92 -0
  36. truefoundry/deploy/core/__init__.py +7 -0
  37. truefoundry/deploy/core/login.py +9 -0
  38. truefoundry/deploy/core/logout.py +5 -0
  39. truefoundry/deploy/function_service/__init__.py +3 -0
  40. truefoundry/deploy/function_service/__main__.py +27 -0
  41. truefoundry/deploy/function_service/app.py +92 -0
  42. truefoundry/deploy/function_service/build.py +45 -0
  43. truefoundry/deploy/function_service/remote/__init__.py +6 -0
  44. truefoundry/deploy/function_service/remote/context.py +3 -0
  45. truefoundry/deploy/function_service/remote/method.py +67 -0
  46. truefoundry/deploy/function_service/remote/remote.py +144 -0
  47. truefoundry/deploy/function_service/route.py +137 -0
  48. truefoundry/deploy/function_service/service.py +113 -0
  49. truefoundry/deploy/function_service/utils.py +53 -0
  50. truefoundry/deploy/io/__init__.py +0 -0
  51. truefoundry/deploy/io/output_callback.py +23 -0
  52. truefoundry/deploy/io/rich_output_callback.py +27 -0
  53. truefoundry/deploy/json_util.py +7 -0
  54. truefoundry/deploy/lib/__init__.py +0 -0
  55. truefoundry/deploy/lib/auth/auth_service_client.py +81 -0
  56. truefoundry/deploy/lib/auth/credential_file_manager.py +115 -0
  57. truefoundry/deploy/lib/auth/credential_provider.py +131 -0
  58. truefoundry/deploy/lib/auth/servicefoundry_session.py +59 -0
  59. truefoundry/deploy/lib/clients/__init__.py +0 -0
  60. truefoundry/deploy/lib/clients/servicefoundry_client.py +723 -0
  61. truefoundry/deploy/lib/clients/shell_client.py +13 -0
  62. truefoundry/deploy/lib/clients/utils.py +41 -0
  63. truefoundry/deploy/lib/const.py +43 -0
  64. truefoundry/deploy/lib/dao/__init__.py +0 -0
  65. truefoundry/deploy/lib/dao/application.py +246 -0
  66. truefoundry/deploy/lib/dao/apply.py +80 -0
  67. truefoundry/deploy/lib/dao/version.py +33 -0
  68. truefoundry/deploy/lib/dao/workspace.py +71 -0
  69. truefoundry/deploy/lib/exceptions.py +23 -0
  70. truefoundry/deploy/lib/logs_utils.py +43 -0
  71. truefoundry/deploy/lib/messages.py +12 -0
  72. truefoundry/deploy/lib/model/__init__.py +0 -0
  73. truefoundry/deploy/lib/model/entity.py +382 -0
  74. truefoundry/deploy/lib/session.py +146 -0
  75. truefoundry/deploy/lib/util.py +70 -0
  76. truefoundry/deploy/lib/win32.py +129 -0
  77. truefoundry/deploy/v2/__init__.py +0 -0
  78. truefoundry/deploy/v2/lib/__init__.py +3 -0
  79. truefoundry/deploy/v2/lib/deploy.py +232 -0
  80. truefoundry/deploy/v2/lib/deployable_patched_models.py +68 -0
  81. truefoundry/deploy/v2/lib/models.py +53 -0
  82. truefoundry/deploy/v2/lib/patched_models.py +497 -0
  83. truefoundry/deploy/v2/lib/source.py +267 -0
  84. truefoundry/langchain/__init__.py +12 -1
  85. truefoundry/langchain/deprecated.py +302 -0
  86. truefoundry/langchain/truefoundry_chat.py +130 -0
  87. truefoundry/langchain/truefoundry_embeddings.py +171 -0
  88. truefoundry/langchain/truefoundry_llm.py +106 -0
  89. truefoundry/langchain/utils.py +85 -0
  90. truefoundry/logger.py +17 -0
  91. truefoundry/pydantic_v1.py +5 -0
  92. truefoundry/python_deploy_codegen.py +132 -0
  93. {truefoundry-0.2.10.dist-info → truefoundry-0.3.0rc1.dist-info}/METADATA +22 -5
  94. truefoundry-0.3.0rc1.dist-info/RECORD +124 -0
  95. truefoundry/deploy/cli/deploy.py +0 -165
  96. truefoundry-0.2.10.dist-info/RECORD +0 -38
  97. /truefoundry/{deploy/cli/version.py → version.py} +0 -0
  98. {truefoundry-0.2.10.dist-info → truefoundry-0.3.0rc1.dist-info}/WHEEL +0 -0
  99. {truefoundry-0.2.10.dist-info → truefoundry-0.3.0rc1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,115 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import threading
5
+ from functools import lru_cache, wraps
6
+ from pathlib import Path
7
+ from typing import Optional
8
+
9
+ from filelock import FileLock, Timeout
10
+
11
+ from truefoundry.deploy.lib.const import CREDENTIAL_FILEPATH
12
+ from truefoundry.deploy.lib.model.entity import CredentialsFileContent
13
+ from truefoundry.logger import logger
14
+
15
+
16
+ def _ensure_lock_taken(method):
17
+ @wraps(method)
18
+ def lock_guard(self, *method_args, **method_kwargs):
19
+ if not self.lock_taken():
20
+ raise Exception(
21
+ "Trying to write to credential file without using with block"
22
+ )
23
+ return method(self, *method_args, **method_kwargs)
24
+
25
+ return lock_guard
26
+
27
+
28
+ CRED_FILE_THREAD_LOCK = threading.RLock()
29
+
30
+
31
+ @lru_cache(maxsize=None)
32
+ def get_file_lock(lock_file_path: str) -> FileLock:
33
+ return FileLock(lock_file_path)
34
+
35
+
36
+ class CredentialsFileManager:
37
+ def __init__(
38
+ self,
39
+ credentials_file_path: Path = CREDENTIAL_FILEPATH,
40
+ lock_timeout: float = 60.0,
41
+ ) -> None:
42
+ credentials_file_path = credentials_file_path.absolute()
43
+ logger.debug("credential file path %r", credentials_file_path)
44
+
45
+ credentials_lock_file_path = f"{credentials_file_path}.lock"
46
+ logger.debug("credential lock file path %r", credentials_lock_file_path)
47
+
48
+ self._credentials_file_path = credentials_file_path
49
+ cred_file_dir = credentials_file_path.parent
50
+ cred_file_dir.mkdir(exist_ok=True, parents=True)
51
+
52
+ self._file_lock = get_file_lock(credentials_lock_file_path)
53
+ self._lock_timeout = lock_timeout
54
+ self._lock_owner: Optional[int] = None
55
+
56
+ def __enter__(self) -> CredentialsFileManager:
57
+ # The lock objects are recursive locks, which means that once acquired, they will not block on successive lock requests:
58
+ lock_aquired = CRED_FILE_THREAD_LOCK.acquire(timeout=self._lock_timeout)
59
+ if not lock_aquired:
60
+ raise Exception(
61
+ "Could not aquire CRED_FILE_THREAD_LOCK"
62
+ f" in {self._lock_timeout} seconds"
63
+ )
64
+ try:
65
+ self._file_lock.acquire(timeout=self._lock_timeout)
66
+ except Timeout as ex:
67
+ raise Exception(
68
+ f"Failed to aquire lock on credential file within {self._lock_timeout} seconds.\n"
69
+ "Is any other process trying to login?"
70
+ ) from ex
71
+ logger.debug("Acquired file and thread lock to access credential file")
72
+ self._lock_owner = threading.get_ident()
73
+ return self
74
+
75
+ def __exit__(self, exc_type, exc_val, exc_tb) -> None:
76
+ self._file_lock.release()
77
+ CRED_FILE_THREAD_LOCK.release()
78
+ logger.debug("Released file and thread lock to access credential file")
79
+ self._lock_owner = None
80
+
81
+ def lock_taken(self) -> bool:
82
+ return self._lock_owner == threading.get_ident()
83
+
84
+ @_ensure_lock_taken
85
+ def read(self) -> CredentialsFileContent:
86
+ try:
87
+ return CredentialsFileContent.parse_file(self._credentials_file_path)
88
+ except Exception as ex:
89
+ 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"
93
+ ) from ex
94
+
95
+ @_ensure_lock_taken
96
+ def write(self, credentials_file_content: CredentialsFileContent) -> None:
97
+ if not isinstance(credentials_file_content, CredentialsFileContent):
98
+ raise Exception(
99
+ "Only object of type `CredentialsFileContent` is allowed. "
100
+ f"Got {type(credentials_file_content)}"
101
+ )
102
+ logger.debug("Updating the credential file content")
103
+ with open(self._credentials_file_path, "w", encoding="utf8") as file:
104
+ file.write(credentials_file_content.json())
105
+
106
+ @_ensure_lock_taken
107
+ def delete(self) -> bool:
108
+ if not os.path.exists(self._credentials_file_path):
109
+ return False
110
+ os.remove(self._credentials_file_path)
111
+ return True
112
+
113
+ @_ensure_lock_taken
114
+ def exists(self) -> bool:
115
+ return self._credentials_file_path.exists()
@@ -0,0 +1,131 @@
1
+ import os
2
+ import threading
3
+ from abc import ABC, abstractmethod
4
+
5
+ from truefoundry.deploy.lib.auth.auth_service_client import AuthServiceClient
6
+ from truefoundry.deploy.lib.auth.credential_file_manager import (
7
+ CredentialsFileContent,
8
+ CredentialsFileManager,
9
+ )
10
+ from truefoundry.deploy.lib.clients.utils import resolve_base_url
11
+ from truefoundry.deploy.lib.const import API_KEY_ENV_NAME
12
+ from truefoundry.deploy.lib.model.entity import Token
13
+ from truefoundry.logger import logger
14
+
15
+ TOKEN_REFRESH_LOCK = threading.RLock()
16
+
17
+
18
+ class CredentialProvider(ABC):
19
+ @property
20
+ @abstractmethod
21
+ def token(self) -> Token: ...
22
+
23
+ @property
24
+ @abstractmethod
25
+ def base_url(self) -> str: ...
26
+
27
+ @staticmethod
28
+ @abstractmethod
29
+ def can_provide() -> bool: ...
30
+
31
+
32
+ class EnvCredentialProvider(CredentialProvider):
33
+ def __init__(self) -> None:
34
+ from truefoundry.deploy.lib.clients.servicefoundry_client import (
35
+ ServiceFoundryServiceClient,
36
+ )
37
+
38
+ logger.debug("Using env var credential provider")
39
+ api_key = os.getenv(API_KEY_ENV_NAME)
40
+ if not api_key:
41
+ raise Exception(
42
+ f"Value of {API_KEY_ENV_NAME} env var should be non-empty string"
43
+ )
44
+ # TODO: Read host from cred file as well.
45
+ base_url = resolve_base_url().strip("/")
46
+ self._host = base_url
47
+ self._auth_service = AuthServiceClient(base_url=base_url)
48
+
49
+ servicefoundry_client = ServiceFoundryServiceClient(
50
+ init_session=False, base_url=base_url
51
+ )
52
+ self._token: Token = servicefoundry_client.get_token_from_api_key(
53
+ api_key=api_key
54
+ )
55
+
56
+ @staticmethod
57
+ def can_provide() -> bool:
58
+ return API_KEY_ENV_NAME in os.environ
59
+
60
+ @property
61
+ def token(self) -> Token:
62
+ with TOKEN_REFRESH_LOCK:
63
+ if self._token.is_going_to_be_expired():
64
+ logger.info("Refreshing access token")
65
+ self._token = self._auth_service.refresh_token(
66
+ self._token, self.base_url
67
+ )
68
+ return self._token
69
+
70
+ @property
71
+ def base_url(self) -> str:
72
+ return self._host
73
+
74
+
75
+ class FileCredentialProvider(CredentialProvider):
76
+ def __init__(self) -> None:
77
+ logger.debug("Using file credential provider")
78
+ self._cred_file = CredentialsFileManager()
79
+
80
+ with self._cred_file:
81
+ self._last_cred_file_content = self._cred_file.read()
82
+ self._token = self._last_cred_file_content.to_token()
83
+ self._host = self._last_cred_file_content.host
84
+
85
+ self._auth_service = AuthServiceClient(base_url=self._host)
86
+
87
+ @staticmethod
88
+ def can_provide() -> bool:
89
+ with CredentialsFileManager() as cred_file:
90
+ return cred_file.exists()
91
+
92
+ @property
93
+ def token(self) -> Token:
94
+ with TOKEN_REFRESH_LOCK:
95
+ if not self._token.is_going_to_be_expired():
96
+ return self._token
97
+
98
+ logger.info("Refreshing access token")
99
+ with self._cred_file:
100
+ new_cred_file_content = self._cred_file.read()
101
+ new_token = new_cred_file_content.to_token()
102
+ new_host = new_cred_file_content.host
103
+
104
+ if new_cred_file_content == self._last_cred_file_content:
105
+ self._token = self._auth_service.refresh_token(
106
+ self._token, self.base_url
107
+ )
108
+ self._last_cred_file_content = CredentialsFileContent(
109
+ host=self._host,
110
+ access_token=self._token.access_token,
111
+ refresh_token=self._token.refresh_token,
112
+ )
113
+ self._cred_file.write(self._last_cred_file_content)
114
+ return self._token
115
+
116
+ if (
117
+ new_host == self._host
118
+ and new_token.to_user_info() == self._token.to_user_info()
119
+ ):
120
+ self._last_cred_file_content = new_cred_file_content
121
+ self._token = new_token
122
+ # recursive
123
+ return self.token
124
+
125
+ raise Exception(
126
+ "Credentials on disk changed while mlfoundry was running."
127
+ )
128
+
129
+ @property
130
+ def base_url(self) -> str:
131
+ return self._host
@@ -0,0 +1,59 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Optional
4
+
5
+ from truefoundry.deploy.lib.auth.credential_provider import (
6
+ CredentialProvider,
7
+ EnvCredentialProvider,
8
+ FileCredentialProvider,
9
+ )
10
+ from truefoundry.deploy.lib.model.entity import UserInfo
11
+ from truefoundry.logger import logger
12
+
13
+ ACTIVE_SESSION: Optional[ServiceFoundrySession] = None
14
+
15
+
16
+ class ServiceFoundrySession:
17
+ def __init__(self) -> None:
18
+ self._cred_provider = self._get_cred_provider()
19
+ self._user_info: UserInfo = self._cred_provider.token.to_user_info()
20
+
21
+ global ACTIVE_SESSION
22
+ if (ACTIVE_SESSION is None) or (
23
+ ACTIVE_SESSION
24
+ and ACTIVE_SESSION.base_url != self.base_url
25
+ and ACTIVE_SESSION.user_info != self.user_info
26
+ ):
27
+ logger.info(
28
+ "Logged in to %r as %r (%s)",
29
+ self.base_url,
30
+ self.user_info.user_id,
31
+ self.user_info.email or self.user_info.user_type.value,
32
+ )
33
+ ACTIVE_SESSION = self
34
+
35
+ @staticmethod
36
+ def _get_cred_provider() -> CredentialProvider:
37
+ final_cred_provider = None
38
+ for cred_provider in [EnvCredentialProvider, FileCredentialProvider]:
39
+ if cred_provider.can_provide():
40
+ final_cred_provider = cred_provider()
41
+ break
42
+ if final_cred_provider is None:
43
+ raise Exception(
44
+ "Please login again using `tfy login --relogin`"
45
+ "or `tfy.login(relogin=True)` function"
46
+ )
47
+ return final_cred_provider
48
+
49
+ @property
50
+ def access_token(self) -> str:
51
+ return self._cred_provider.token.access_token
52
+
53
+ @property
54
+ def base_url(self) -> str:
55
+ return self._cred_provider.base_url
56
+
57
+ @property
58
+ def user_info(self) -> UserInfo:
59
+ return self._user_info
File without changes