qwak-core 0.4.366__py3-none-any.whl → 0.4.392__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.
- _qwak_proto/qwak/administration/runtime_configuration/v0/external/databricks/auth_pb2.py +6 -4
- _qwak_proto/qwak/administration/runtime_configuration/v0/external/databricks/auth_pb2.pyi +27 -4
- _qwak_proto/qwak/administration/runtime_configuration/v0/hosting/azure/auth_pb2.py +5 -3
- _qwak_proto/qwak/administration/runtime_configuration/v0/hosting/azure/auth_pb2.pyi +21 -1
- _qwak_proto/qwak/batch_job/v1/batch_job_service_pb2.pyi +1 -1
- _qwak_proto/qwak/builds/build_pb2.py +42 -41
- _qwak_proto/qwak/builds/build_pb2.pyi +8 -1
- _qwak_proto/qwak/builds/build_values_pb2.py +76 -0
- _qwak_proto/qwak/builds/build_values_pb2.pyi +533 -0
- _qwak_proto/qwak/builds/build_values_pb2_grpc.py +4 -0
- _qwak_proto/qwak/kube_deployment_captain/batch_job_pb2.pyi +1 -1
- _qwak_proto/qwak/projects/projects_pb2.py +17 -15
- qwak/__init__.py +1 -1
- qwak/clients/model_management/client.py +0 -5
- qwak/clients/project/client.py +0 -7
- qwak/feature_store/_common/packaging.py +11 -5
- qwak/inner/const.py +0 -2
- qwak/inner/di_configuration/account.py +6 -66
- qwak/inner/tool/auth.py +0 -86
- qwak/inner/tool/grpc/grpc_auth.py +0 -32
- qwak/inner/tool/grpc/grpc_tools.py +2 -8
- qwak/inner/tool/grpc/grpc_try_wrapping.py +3 -1
- qwak/qwak_client/client.py +2 -8
- qwak/vector_store/rest_helpers.py +4 -16
- qwak_core-0.4.392.dist-info/METADATA +50 -0
- {qwak_core-0.4.366.dist-info → qwak_core-0.4.392.dist-info}/RECORD +27 -62
- frogml_storage/__init__.py +0 -1
- frogml_storage/artifactory/__init__.py +0 -1
- frogml_storage/artifactory/_artifactory_api.py +0 -315
- frogml_storage/authentication/login/__init__.py +0 -1
- frogml_storage/authentication/login/_login_cli.py +0 -239
- frogml_storage/authentication/login/_login_command.py +0 -74
- frogml_storage/authentication/models/__init__.py +0 -3
- frogml_storage/authentication/models/_auth.py +0 -24
- frogml_storage/authentication/models/_auth_config.py +0 -70
- frogml_storage/authentication/models/_login.py +0 -22
- frogml_storage/authentication/utils/__init__.py +0 -17
- frogml_storage/authentication/utils/_authentication_utils.py +0 -281
- frogml_storage/authentication/utils/_login_checks_utils.py +0 -114
- frogml_storage/base_storage.py +0 -140
- frogml_storage/constants.py +0 -56
- frogml_storage/exceptions/checksum_verification_error.py +0 -3
- frogml_storage/exceptions/validation_error.py +0 -4
- frogml_storage/frog_ml.py +0 -668
- frogml_storage/http/__init__.py +0 -1
- frogml_storage/http/http_client.py +0 -83
- frogml_storage/logging/__init__.py +0 -1
- frogml_storage/logging/_log_config.py +0 -45
- frogml_storage/logging/log_utils.py +0 -21
- frogml_storage/models/__init__.py +0 -1
- frogml_storage/models/_download_context.py +0 -54
- frogml_storage/models/dataset_manifest.py +0 -13
- frogml_storage/models/entity_manifest.py +0 -93
- frogml_storage/models/frogml_dataset_version.py +0 -21
- frogml_storage/models/frogml_entity_type_info.py +0 -50
- frogml_storage/models/frogml_entity_version.py +0 -34
- frogml_storage/models/frogml_model_version.py +0 -21
- frogml_storage/models/model_manifest.py +0 -60
- frogml_storage/models/serialization_metadata.py +0 -15
- frogml_storage/utils/__init__.py +0 -12
- frogml_storage/utils/_environment.py +0 -21
- frogml_storage/utils/_input_checks_utility.py +0 -104
- frogml_storage/utils/_storage_utils.py +0 -15
- frogml_storage/utils/_url_utils.py +0 -27
- qwak_core-0.4.366.dist-info/METADATA +0 -414
- {qwak_core-0.4.366.dist-info → qwak_core-0.4.392.dist-info}/WHEEL +0 -0
qwak/clients/project/client.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
1
|
import grpc
|
|
4
2
|
from _qwak_proto.qwak.projects.projects_pb2 import (
|
|
5
3
|
CreateProjectRequest,
|
|
@@ -8,7 +6,6 @@ from _qwak_proto.qwak.projects.projects_pb2 import (
|
|
|
8
6
|
ListProjectsRequest,
|
|
9
7
|
)
|
|
10
8
|
from _qwak_proto.qwak.projects.projects_pb2_grpc import ProjectsManagementServiceStub
|
|
11
|
-
from _qwak_proto.qwak.projects.jfrog_project_spec_pb2 import ModelRepositoryJFrogSpec
|
|
12
9
|
from dependency_injector.wiring import Provide, inject
|
|
13
10
|
from qwak.exceptions import QwakException
|
|
14
11
|
from qwak.inner.di_configuration import QwakContainer
|
|
@@ -34,16 +31,12 @@ class ProjectsManagementClient:
|
|
|
34
31
|
self,
|
|
35
32
|
project_name,
|
|
36
33
|
project_description,
|
|
37
|
-
jfrog_project_key: Optional[str] = None,
|
|
38
34
|
):
|
|
39
35
|
try:
|
|
40
36
|
return self._projects_management_service.CreateProject(
|
|
41
37
|
CreateProjectRequest(
|
|
42
38
|
project_name=project_name,
|
|
43
39
|
project_description=project_description,
|
|
44
|
-
jfrog_spec=ModelRepositoryJFrogSpec(
|
|
45
|
-
jfrog_project_key=jfrog_project_key
|
|
46
|
-
),
|
|
47
40
|
)
|
|
48
41
|
)
|
|
49
42
|
|
|
@@ -16,6 +16,7 @@ from qwak.feature_store._common.value import (
|
|
|
16
16
|
UPDATE_QWAK_SDK_WITH_FEATURE_STORE_EXTRA_MSG,
|
|
17
17
|
)
|
|
18
18
|
from requests import HTTPError, Response
|
|
19
|
+
from urllib.parse import urlparse, ParseResult
|
|
19
20
|
|
|
20
21
|
ZIP_FUNCTION_CONTENT_TYPE = "text/plain"
|
|
21
22
|
|
|
@@ -220,17 +221,22 @@ def put_files_content(
|
|
|
220
221
|
|
|
221
222
|
|
|
222
223
|
def upload_to_s3(presign_url: str, in_memory_zip: bytes, content_type: str) -> str:
|
|
224
|
+
parsed_url: ParseResult = urlparse(presign_url)
|
|
225
|
+
extra_headers: Dict[str, str] = (
|
|
226
|
+
{"x-ms-blob-type": "BlockBlob"}
|
|
227
|
+
if parsed_url.hostname.endswith(".blob.core.windows.net")
|
|
228
|
+
else None
|
|
229
|
+
)
|
|
223
230
|
put_files_content(
|
|
224
231
|
url=presign_url,
|
|
225
232
|
content=in_memory_zip,
|
|
226
233
|
content_type=content_type,
|
|
234
|
+
extra_headers=extra_headers,
|
|
227
235
|
)
|
|
228
|
-
from urllib.parse import urlparse
|
|
229
236
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
s3_path = f"s3://{bucket}{postfix}" # noqa: E231
|
|
237
|
+
postfix: str = parsed_url.path
|
|
238
|
+
bucket: str = parsed_url.hostname.split(".s3.")[0]
|
|
239
|
+
s3_path: str = f"s3://{bucket}{postfix}" # noqa: E231
|
|
234
240
|
return s3_path
|
|
235
241
|
|
|
236
242
|
|
qwak/inner/const.py
CHANGED
|
@@ -2,13 +2,12 @@ import configparser
|
|
|
2
2
|
import errno
|
|
3
3
|
import os
|
|
4
4
|
from dataclasses import dataclass
|
|
5
|
-
from typing import Optional, Type
|
|
5
|
+
from typing import Optional, Type
|
|
6
6
|
|
|
7
7
|
from qwak.exceptions import QwakLoginException
|
|
8
8
|
from qwak.inner.const import QwakConstants
|
|
9
9
|
from qwak.inner.di_configuration.session import Session
|
|
10
|
-
from qwak.inner.tool.auth import Auth0ClientBase
|
|
11
|
-
from frogml_storage.authentication.login import frogml_login
|
|
10
|
+
from qwak.inner.tool.auth import Auth0ClientBase
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
@dataclass
|
|
@@ -23,18 +22,6 @@ class UserAccount:
|
|
|
23
22
|
# Assigned username
|
|
24
23
|
username: Optional[str] = None
|
|
25
24
|
|
|
26
|
-
# Assigned password
|
|
27
|
-
password: Optional[str] = None
|
|
28
|
-
|
|
29
|
-
# Assigned URL
|
|
30
|
-
url: Optional[str] = None
|
|
31
|
-
|
|
32
|
-
# Anonymous login
|
|
33
|
-
anonymous: bool = False
|
|
34
|
-
|
|
35
|
-
# Interactive login
|
|
36
|
-
is_interactive: bool = False
|
|
37
|
-
|
|
38
25
|
|
|
39
26
|
class UserAccountConfiguration:
|
|
40
27
|
USER_FIELD = "user"
|
|
@@ -43,9 +30,9 @@ class UserAccountConfiguration:
|
|
|
43
30
|
|
|
44
31
|
def __init__(
|
|
45
32
|
self,
|
|
46
|
-
config_file=QwakConstants.QWAK_CONFIG_FILE,
|
|
47
|
-
auth_file=QwakConstants.QWAK_AUTHORIZATION_FILE,
|
|
48
|
-
auth_client:
|
|
33
|
+
config_file: str = QwakConstants.QWAK_CONFIG_FILE,
|
|
34
|
+
auth_file: str = QwakConstants.QWAK_AUTHORIZATION_FILE,
|
|
35
|
+
auth_client: Type[Auth0ClientBase] = Auth0ClientBase,
|
|
49
36
|
):
|
|
50
37
|
self._config_file = config_file
|
|
51
38
|
self._auth_file = auth_file
|
|
@@ -53,52 +40,12 @@ class UserAccountConfiguration:
|
|
|
53
40
|
self._auth = configparser.ConfigParser()
|
|
54
41
|
self._environment = Session().get_environment()
|
|
55
42
|
self._auth_client = auth_client
|
|
56
|
-
self._force_qwak_auth = os.getenv("FORCE_QWAK_AUTH", "False") == "True"
|
|
57
|
-
|
|
58
|
-
if not self._auth_client:
|
|
59
|
-
# Determine auth client based on FrogML configuration
|
|
60
|
-
try:
|
|
61
|
-
from frogml_storage.authentication.utils import (
|
|
62
|
-
get_frogml_configuration,
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
if (
|
|
66
|
-
get_frogml_configuration() or os.getenv("JF_URL")
|
|
67
|
-
) and not self._force_qwak_auth:
|
|
68
|
-
self._auth_client = FrogMLAuthClient
|
|
69
|
-
else:
|
|
70
|
-
self._auth_client = Auth0ClientBase
|
|
71
|
-
except (ImportError, Exception):
|
|
72
|
-
self._auth_client = Auth0ClientBase
|
|
73
43
|
|
|
74
44
|
def configure_user(self, user_account: UserAccount):
|
|
75
45
|
"""
|
|
76
46
|
Configure user authentication based on the authentication client type
|
|
77
47
|
"""
|
|
78
|
-
|
|
79
|
-
# Existing Qwak authentication flow
|
|
80
|
-
self.__qwak_login(user_account)
|
|
81
|
-
|
|
82
|
-
elif issubclass(self._auth_client, FrogMLAuthClient):
|
|
83
|
-
# Use FrogML's login flow
|
|
84
|
-
success = frogml_login(
|
|
85
|
-
url=user_account.url,
|
|
86
|
-
username=user_account.username,
|
|
87
|
-
password=user_account.password,
|
|
88
|
-
token=user_account.api_key,
|
|
89
|
-
anonymous=user_account.anonymous,
|
|
90
|
-
is_interactive=user_account.is_interactive,
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
if not success:
|
|
94
|
-
raise QwakLoginException("Failed to authenticate with JFrog")
|
|
95
|
-
# Validate access token
|
|
96
|
-
# TODO: Remove once we support reference token
|
|
97
|
-
token = self._auth_client().get_token()
|
|
98
|
-
if not token or len(token) <= 64:
|
|
99
|
-
raise QwakLoginException(
|
|
100
|
-
"Authentication with JFrog failed: Only Access Tokens are supported. Please ensure you are using a valid Access Token."
|
|
101
|
-
)
|
|
48
|
+
self.__qwak_login(user_account)
|
|
102
49
|
|
|
103
50
|
def __qwak_login(self, user_account: UserAccount):
|
|
104
51
|
self._auth.read(self._auth_file)
|
|
@@ -139,8 +86,6 @@ class UserAccountConfiguration:
|
|
|
139
86
|
:return:
|
|
140
87
|
"""
|
|
141
88
|
try:
|
|
142
|
-
if issubclass(self._auth_client, FrogMLAuthClient):
|
|
143
|
-
return UserAccount()
|
|
144
89
|
username = os.environ.get("QWAK_USERNAME")
|
|
145
90
|
api_key = os.environ.get("QWAK_API_KEY")
|
|
146
91
|
if not api_key and (
|
|
@@ -179,8 +124,6 @@ class UserAccountConfiguration:
|
|
|
179
124
|
:return:
|
|
180
125
|
"""
|
|
181
126
|
try:
|
|
182
|
-
if issubclass(self._auth_client, FrogMLAuthClient):
|
|
183
|
-
return ""
|
|
184
127
|
api_key = os.environ.get("QWAK_API_KEY")
|
|
185
128
|
if api_key:
|
|
186
129
|
Session().set_environment(api_key)
|
|
@@ -213,7 +156,4 @@ class UserAccountConfiguration:
|
|
|
213
156
|
auth_client_instance = self._auth_client()
|
|
214
157
|
base_url = auth_client_instance.get_base_url()
|
|
215
158
|
|
|
216
|
-
if issubclass(self._auth_client, FrogMLAuthClient):
|
|
217
|
-
return f"{base_url}/ui/ml"
|
|
218
|
-
|
|
219
159
|
return base_url
|
qwak/inner/tool/auth.py
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import warnings
|
|
2
2
|
from filelock import FileLock
|
|
3
|
-
from typing_extensions import Self
|
|
4
3
|
|
|
5
4
|
from qwak.inner.di_configuration.session import Session
|
|
6
5
|
from abc import ABC, abstractmethod
|
|
7
6
|
from typing import Optional
|
|
8
|
-
from frogml_storage.authentication.utils import get_credentials
|
|
9
|
-
from frogml_storage.authentication.models import AuthConfig
|
|
10
7
|
|
|
11
8
|
warnings.filterwarnings(action="ignore", module=".*jose.*")
|
|
12
9
|
|
|
@@ -140,86 +137,3 @@ class Auth0ClientBase(BaseAuthClient):
|
|
|
140
137
|
raise e
|
|
141
138
|
except Exception:
|
|
142
139
|
raise QwakLoginException()
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
class FrogMLAuthClient(BaseAuthClient):
|
|
146
|
-
__MIN_TOKEN_LENGTH: int = 64
|
|
147
|
-
|
|
148
|
-
def __init__(self, auth_config: Optional[AuthConfig] = None):
|
|
149
|
-
self.auth_config = auth_config
|
|
150
|
-
self._token = None
|
|
151
|
-
self._tenant_id = None
|
|
152
|
-
|
|
153
|
-
def get_token(self) -> Optional[str]:
|
|
154
|
-
if not self._token:
|
|
155
|
-
self.login()
|
|
156
|
-
return self._token
|
|
157
|
-
|
|
158
|
-
def get_tenant_id(self) -> Optional[str]:
|
|
159
|
-
if not self._tenant_id:
|
|
160
|
-
self.login()
|
|
161
|
-
return self._tenant_id
|
|
162
|
-
|
|
163
|
-
def get_base_url(self) -> str:
|
|
164
|
-
artifactory_url, _ = get_credentials(self.auth_config)
|
|
165
|
-
return self.__format_artifactory_url(artifactory_url)
|
|
166
|
-
|
|
167
|
-
def login(self) -> None:
|
|
168
|
-
artifactory_url, auth = get_credentials(self.auth_config)
|
|
169
|
-
# For now, we only support Bearer token authentication
|
|
170
|
-
if not hasattr(auth, "token"):
|
|
171
|
-
return
|
|
172
|
-
|
|
173
|
-
# noinspection PyUnresolvedReferences
|
|
174
|
-
self._token = auth.token
|
|
175
|
-
self.__validate_token()
|
|
176
|
-
|
|
177
|
-
base_url = self.__format_artifactory_url(artifactory_url)
|
|
178
|
-
try:
|
|
179
|
-
response = requests.get(
|
|
180
|
-
f"{base_url}/ui/api/v1/system/auth/screen/footer",
|
|
181
|
-
headers={"Authorization": f"Bearer {self._token}"},
|
|
182
|
-
timeout=60,
|
|
183
|
-
)
|
|
184
|
-
response.raise_for_status() # Raises an HTTPError for bad responses
|
|
185
|
-
response_data = response.json()
|
|
186
|
-
if "serverId" not in response_data:
|
|
187
|
-
response = requests.get(
|
|
188
|
-
f"{base_url}/jfconnect/api/v1/system/jpd_id",
|
|
189
|
-
headers={"Authorization": f"Bearer {self._token}"},
|
|
190
|
-
timeout=60,
|
|
191
|
-
)
|
|
192
|
-
if response.status_code == 200:
|
|
193
|
-
self._tenant_id = response.text
|
|
194
|
-
elif response.status_code == 401:
|
|
195
|
-
raise QwakLoginException(
|
|
196
|
-
"Failed to authenticate with JFrog. Please check your credentials"
|
|
197
|
-
)
|
|
198
|
-
else:
|
|
199
|
-
raise QwakLoginException(
|
|
200
|
-
"Failed to authenticate with JFrog. Please check your artifactory configuration"
|
|
201
|
-
)
|
|
202
|
-
else:
|
|
203
|
-
self._tenant_id = response_data["serverId"]
|
|
204
|
-
except requests.exceptions.RequestException:
|
|
205
|
-
raise QwakLoginException(
|
|
206
|
-
"Failed to authenticate with JFrog. Please check your artifactory configuration"
|
|
207
|
-
)
|
|
208
|
-
except ValueError: # This catches JSON decode errors
|
|
209
|
-
raise QwakLoginException(
|
|
210
|
-
"Failed to authenticate with JFrog. Please check your artifactory configuration"
|
|
211
|
-
)
|
|
212
|
-
|
|
213
|
-
def __validate_token(self: Self):
|
|
214
|
-
if self._token is None or len(self._token) <= self.__MIN_TOKEN_LENGTH:
|
|
215
|
-
raise QwakLoginException(
|
|
216
|
-
"Authentication with JFrog failed: Only JWT Access Tokens are supported. "
|
|
217
|
-
"Please ensure you are using a valid JWT Access Token."
|
|
218
|
-
)
|
|
219
|
-
|
|
220
|
-
@staticmethod
|
|
221
|
-
def __format_artifactory_url(artifactory_url: str) -> str:
|
|
222
|
-
# Remove '/artifactory' from the URL
|
|
223
|
-
base_url: str = artifactory_url.replace("/artifactory", "")
|
|
224
|
-
# Remove trailing slash if exists
|
|
225
|
-
return base_url.rstrip("/")
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from typing import Callable, Tuple
|
|
2
2
|
|
|
3
3
|
import grpc
|
|
4
|
-
from qwak.inner.const import QwakConstants
|
|
5
4
|
|
|
6
5
|
_SIGNATURE_HEADER_KEY = "authorization"
|
|
7
6
|
|
|
@@ -35,34 +34,3 @@ class Auth0Client(grpc.AuthMetadataPlugin):
|
|
|
35
34
|
|
|
36
35
|
self._auth_client = Auth0ClientBase()
|
|
37
36
|
return self._auth_client.get_token()
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
class FrogMLGrpcClient(grpc.AuthMetadataPlugin):
|
|
41
|
-
def __init__(self):
|
|
42
|
-
self._auth_client = None
|
|
43
|
-
|
|
44
|
-
def __call__(
|
|
45
|
-
self,
|
|
46
|
-
context: grpc.AuthMetadataContext,
|
|
47
|
-
callback: Callable[[Tuple[Tuple[str, str]], None], None],
|
|
48
|
-
):
|
|
49
|
-
"""Implements authentication by passing metadata to a callback.
|
|
50
|
-
|
|
51
|
-
Args:
|
|
52
|
-
context: An AuthMetadataContext providing information on the RPC that
|
|
53
|
-
the plugin is being called to authenticate.
|
|
54
|
-
callback: A callback that accepts a tuple of metadata key/value pairs and a None
|
|
55
|
-
parameter.
|
|
56
|
-
"""
|
|
57
|
-
# Get token from FrogML client
|
|
58
|
-
if not self._auth_client:
|
|
59
|
-
from qwak.inner.tool.auth import FrogMLAuthClient
|
|
60
|
-
|
|
61
|
-
self._auth_client = FrogMLAuthClient()
|
|
62
|
-
token = self._auth_client.get_token()
|
|
63
|
-
jfrog_tenant_id = self._auth_client.get_tenant_id()
|
|
64
|
-
metadata = (
|
|
65
|
-
(_SIGNATURE_HEADER_KEY, f"Bearer {token}"),
|
|
66
|
-
(QwakConstants.JFROG_TENANT_HEADER_KEY.lower(), jfrog_tenant_id),
|
|
67
|
-
)
|
|
68
|
-
callback(metadata, None)
|
|
@@ -6,10 +6,8 @@ from typing import Callable, Optional, Tuple
|
|
|
6
6
|
|
|
7
7
|
import grpc
|
|
8
8
|
from qwak.exceptions import QwakException
|
|
9
|
-
from qwak.inner.di_configuration.account import UserAccountConfiguration
|
|
10
|
-
from qwak.inner.tool.auth import Auth0ClientBase
|
|
11
9
|
|
|
12
|
-
from .grpc_auth import Auth0Client
|
|
10
|
+
from .grpc_auth import Auth0Client
|
|
13
11
|
|
|
14
12
|
logger = logging.getLogger()
|
|
15
13
|
|
|
@@ -49,11 +47,7 @@ def create_grpc_channel(
|
|
|
49
47
|
credentials = grpc.ssl_channel_credentials()
|
|
50
48
|
if enable_auth:
|
|
51
49
|
if auth_metadata_plugin is None:
|
|
52
|
-
|
|
53
|
-
if issubclass(user_config._auth_client, Auth0ClientBase):
|
|
54
|
-
auth_metadata_plugin = Auth0Client()
|
|
55
|
-
else:
|
|
56
|
-
auth_metadata_plugin = FrogMLGrpcClient()
|
|
50
|
+
auth_metadata_plugin = Auth0Client()
|
|
57
51
|
credentials = grpc.composite_channel_credentials(
|
|
58
52
|
credentials, grpc.metadata_call_credentials(auth_metadata_plugin)
|
|
59
53
|
)
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
import functools
|
|
2
3
|
import inspect
|
|
3
4
|
from inspect import BoundArguments, Signature
|
|
4
5
|
from typing import Any, Callable, Optional
|
|
5
6
|
|
|
6
7
|
import grpc
|
|
7
|
-
from frogml_storage.logging import logger
|
|
8
8
|
from qwak.exceptions import QwakException
|
|
9
9
|
|
|
10
|
+
logger = logging.getLogger()
|
|
11
|
+
|
|
10
12
|
|
|
11
13
|
def grpc_try_catch_wrapper(
|
|
12
14
|
exception_message: str,
|
qwak/qwak_client/client.py
CHANGED
|
@@ -238,8 +238,8 @@ class QwakClient:
|
|
|
238
238
|
model = self._get_model_management().get_model(model_id=model_id)
|
|
239
239
|
model_uuid = model.uuid
|
|
240
240
|
|
|
241
|
-
metric_filters =
|
|
242
|
-
parameter_filters =
|
|
241
|
+
metric_filters = []
|
|
242
|
+
parameter_filters = []
|
|
243
243
|
|
|
244
244
|
for build_filter in filters:
|
|
245
245
|
if isinstance(build_filter, MetricFilter):
|
|
@@ -356,7 +356,6 @@ class QwakClient:
|
|
|
356
356
|
self,
|
|
357
357
|
project_name: str,
|
|
358
358
|
project_description: str,
|
|
359
|
-
jfrog_project_key: Optional[str] = None,
|
|
360
359
|
) -> str:
|
|
361
360
|
"""
|
|
362
361
|
Create project
|
|
@@ -364,7 +363,6 @@ class QwakClient:
|
|
|
364
363
|
Args:
|
|
365
364
|
project_name (str): The requested name
|
|
366
365
|
project_description (str): The requested description
|
|
367
|
-
jfrog_project_key (Optional[str]): The requested jfrog project key
|
|
368
366
|
|
|
369
367
|
Returns:
|
|
370
368
|
str: The project ID of the newly created project
|
|
@@ -373,7 +371,6 @@ class QwakClient:
|
|
|
373
371
|
project = self._get_project_management().create_project(
|
|
374
372
|
project_name=project_name,
|
|
375
373
|
project_description=project_description,
|
|
376
|
-
jfrog_project_key=jfrog_project_key,
|
|
377
374
|
)
|
|
378
375
|
|
|
379
376
|
return project.project.project_id
|
|
@@ -419,7 +416,6 @@ class QwakClient:
|
|
|
419
416
|
project_id: str,
|
|
420
417
|
model_name: str,
|
|
421
418
|
model_description: str,
|
|
422
|
-
jfrog_project_key: Optional[str] = None,
|
|
423
419
|
) -> str:
|
|
424
420
|
"""
|
|
425
421
|
Create model
|
|
@@ -428,7 +424,6 @@ class QwakClient:
|
|
|
428
424
|
project_id (str): The project ID to associate the model
|
|
429
425
|
model_name (str): The requested name
|
|
430
426
|
model_description (str): The requested description
|
|
431
|
-
jfrog_project_key (Optional[str]): The jfrog project key
|
|
432
427
|
|
|
433
428
|
Returns:
|
|
434
429
|
str: The model ID of the newly created project
|
|
@@ -438,7 +433,6 @@ class QwakClient:
|
|
|
438
433
|
project_id=project_id,
|
|
439
434
|
model_name=model_name,
|
|
440
435
|
model_description=model_description,
|
|
441
|
-
jfrog_project_key=jfrog_project_key,
|
|
442
436
|
)
|
|
443
437
|
|
|
444
438
|
return model.model_id
|
|
@@ -4,25 +4,16 @@ import socket
|
|
|
4
4
|
from datetime import datetime
|
|
5
5
|
|
|
6
6
|
import requests
|
|
7
|
-
from qwak.inner.
|
|
8
|
-
from qwak.inner.tool.auth import Auth0ClientBase, FrogMLAuthClient
|
|
9
|
-
from qwak.inner.const import QwakConstants
|
|
7
|
+
from qwak.inner.tool.auth import Auth0ClientBase
|
|
10
8
|
|
|
11
9
|
|
|
12
10
|
def _get_authorization():
|
|
13
|
-
|
|
14
|
-
if issubclass(user_account_configuration._auth_client, Auth0ClientBase):
|
|
15
|
-
auth_client = Auth0ClientBase()
|
|
16
|
-
tenant_id = None
|
|
17
|
-
else:
|
|
18
|
-
auth_client = FrogMLAuthClient()
|
|
19
|
-
tenant_id = auth_client.get_tenant_id()
|
|
20
|
-
|
|
11
|
+
auth_client = Auth0ClientBase()
|
|
21
12
|
token = auth_client.get_token()
|
|
22
13
|
token_split = token.split(".")
|
|
23
14
|
decoded_token = json.loads(_base64url_decode(token_split[1]).decode("utf-8"))
|
|
24
15
|
token_expiration = datetime.fromtimestamp(decoded_token["exp"])
|
|
25
|
-
return f"Bearer {token}", token_expiration
|
|
16
|
+
return f"Bearer {token}", token_expiration
|
|
26
17
|
|
|
27
18
|
|
|
28
19
|
def _base64url_decode(input):
|
|
@@ -77,8 +68,5 @@ class RestSession(requests.Session):
|
|
|
77
68
|
return super().prepare_request(request)
|
|
78
69
|
|
|
79
70
|
def prepare_request_token(self):
|
|
80
|
-
auth_token, self.jwt_expiration
|
|
71
|
+
auth_token, self.jwt_expiration = _get_authorization()
|
|
81
72
|
self.headers["Authorization"] = auth_token
|
|
82
|
-
|
|
83
|
-
if tenant_id:
|
|
84
|
-
self.headers[QwakConstants.JFROG_TENANT_HEADER_KEY] = tenant_id
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: qwak-core
|
|
3
|
+
Version: 0.4.392
|
|
4
|
+
Summary: Qwak Core contains the necessary objects and communication tools for using the Qwak Platform
|
|
5
|
+
License: Apache-2.0
|
|
6
|
+
Keywords: mlops,ml,deployment,serving,model
|
|
7
|
+
Author: Qwak
|
|
8
|
+
Author-email: info@qwak.com
|
|
9
|
+
Requires-Python: >=3.9,<3.12
|
|
10
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Provides-Extra: feature-store
|
|
21
|
+
Requires-Dist: PyYAML (>=6.0.2)
|
|
22
|
+
Requires-Dist: cachetools
|
|
23
|
+
Requires-Dist: chevron (==0.14.0)
|
|
24
|
+
Requires-Dist: cloudpickle (==2.2.1) ; extra == "feature-store"
|
|
25
|
+
Requires-Dist: dacite (==1.8.1)
|
|
26
|
+
Requires-Dist: dependency-injector (>=4.0)
|
|
27
|
+
Requires-Dist: filelock
|
|
28
|
+
Requires-Dist: grpcio (>=1.71.2)
|
|
29
|
+
Requires-Dist: joblib (>=1.3.2,<2.0.0)
|
|
30
|
+
Requires-Dist: marshmallow-dataclass (>=8.5.8,<9.0.0)
|
|
31
|
+
Requires-Dist: protobuf (>=4.25.8,<5)
|
|
32
|
+
Requires-Dist: pyarrow (>=20.0.0) ; extra == "feature-store"
|
|
33
|
+
Requires-Dist: pyathena (>=2.2.0,!=2.18.0) ; extra == "feature-store"
|
|
34
|
+
Requires-Dist: pydantic
|
|
35
|
+
Requires-Dist: pyspark (==3.4.2) ; extra == "feature-store"
|
|
36
|
+
Requires-Dist: python-jose[cryptography] (>=3.4.0)
|
|
37
|
+
Requires-Dist: python-json-logger (>=2.0.2)
|
|
38
|
+
Requires-Dist: requests
|
|
39
|
+
Requires-Dist: retrying (==1.3.4)
|
|
40
|
+
Requires-Dist: tqdm
|
|
41
|
+
Requires-Dist: typeguard (>=2,<3)
|
|
42
|
+
Requires-Dist: typer
|
|
43
|
+
Project-URL: Home page, https://www.qwak.com/
|
|
44
|
+
Description-Content-Type: text/markdown
|
|
45
|
+
|
|
46
|
+
# Qwak Core
|
|
47
|
+
|
|
48
|
+
Qwak is an end-to-end production ML platform designed to allow data scientists to build, deploy, and monitor their models in production with minimal engineering friction.
|
|
49
|
+
Qwak Core contains all the objects and tools necessary to use the Qwak Platform
|
|
50
|
+
|