trismik 0.9.1__py3-none-any.whl → 0.9.5__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.
- trismik/__init__.py +10 -21
- trismik/_mapper.py +327 -47
- trismik/_utils.py +92 -15
- trismik/adaptive_test.py +671 -0
- trismik/client_async.py +250 -184
- trismik/exceptions.py +57 -6
- trismik/settings.py +15 -0
- trismik/types.py +246 -88
- trismik-0.9.5.dist-info/METADATA +174 -0
- trismik-0.9.5.dist-info/RECORD +12 -0
- {trismik-0.9.1.dist-info → trismik-0.9.5.dist-info}/WHEEL +1 -1
- trismik/client.py +0 -330
- trismik/runner.py +0 -119
- trismik/runner_async.py +0 -121
- trismik-0.9.1.dist-info/METADATA +0 -54
- trismik-0.9.1.dist-info/RECORD +0 -13
- {trismik-0.9.1.dist-info → trismik-0.9.5.dist-info/licenses}/LICENSE +0 -0
trismik/__init__.py
CHANGED
|
@@ -1,21 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
from .
|
|
10
|
-
|
|
11
|
-
TrismikAuth,
|
|
12
|
-
TrismikSession,
|
|
13
|
-
TrismikItem,
|
|
14
|
-
TrismikMultipleChoiceTextItem,
|
|
15
|
-
TrismikChoice,
|
|
16
|
-
TrismikTextChoice,
|
|
17
|
-
TrismikResult,
|
|
18
|
-
TrismikResponse,
|
|
19
|
-
TrismikRunResults,
|
|
20
|
-
TrismikSessionMetadata,
|
|
21
|
-
)
|
|
1
|
+
"""
|
|
2
|
+
Trismik Python Client.
|
|
3
|
+
|
|
4
|
+
A Python client for the Trismik API.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import importlib.metadata
|
|
8
|
+
|
|
9
|
+
# get version from pyproject.toml
|
|
10
|
+
__version__ = importlib.metadata.version(__package__ or __name__)
|
trismik/_mapper.py
CHANGED
|
@@ -1,79 +1,359 @@
|
|
|
1
|
-
from
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Any, Dict, List
|
|
2
3
|
|
|
3
|
-
from
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
from trismik.exceptions import TrismikApiError
|
|
5
|
+
from trismik.types import (
|
|
6
|
+
TrismikClassicEvalResponse,
|
|
7
|
+
TrismikDataset,
|
|
7
8
|
TrismikItem,
|
|
8
|
-
|
|
9
|
+
TrismikMeResponse,
|
|
9
10
|
TrismikMultipleChoiceTextItem,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
TrismikSession,
|
|
11
|
+
TrismikOrganization,
|
|
12
|
+
TrismikProject,
|
|
13
|
+
TrismikReplayResponse,
|
|
14
14
|
TrismikResponse,
|
|
15
|
+
TrismikResult,
|
|
16
|
+
TrismikRun,
|
|
17
|
+
TrismikRunInfo,
|
|
18
|
+
TrismikRunResponse,
|
|
19
|
+
TrismikRunState,
|
|
20
|
+
TrismikRunSummary,
|
|
21
|
+
TrismikTextChoice,
|
|
22
|
+
TrismikUserInfo,
|
|
15
23
|
)
|
|
16
24
|
|
|
17
25
|
|
|
18
26
|
class TrismikResponseMapper:
|
|
27
|
+
"""
|
|
28
|
+
Maps JSON responses from the Trismik API to Python objects.
|
|
19
29
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
token=json["token"],
|
|
24
|
-
expires=parse_date(json["expires"]),
|
|
25
|
-
)
|
|
30
|
+
This class provides static methods to convert JSON responses from various
|
|
31
|
+
API endpoints into their corresponding Python object representations.
|
|
32
|
+
"""
|
|
26
33
|
|
|
27
34
|
@staticmethod
|
|
28
|
-
def
|
|
35
|
+
def to_datasets(json: Dict[str, Any]) -> List[TrismikDataset]:
|
|
36
|
+
"""
|
|
37
|
+
Convert JSON response to a list of TrismikDataset objects.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
json (Dict[str, Any]): JSON response containing dataset data.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
List[TrismikDataset]: List of
|
|
44
|
+
dataset objects with IDs and names.
|
|
45
|
+
"""
|
|
29
46
|
return [
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
)
|
|
47
|
+
TrismikDataset(
|
|
48
|
+
id=item["id"],
|
|
49
|
+
name=item["name"],
|
|
50
|
+
)
|
|
51
|
+
for item in json["data"]
|
|
34
52
|
]
|
|
35
53
|
|
|
36
54
|
@staticmethod
|
|
37
|
-
def
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
55
|
+
def to_run(json: Dict[str, Any]) -> TrismikRun:
|
|
56
|
+
"""
|
|
57
|
+
Convert JSON response to a TrismikRun object.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
json (Dict[str, Any]): JSON response containing run data.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
TrismikRun: Run object with ID, URL, and status.
|
|
64
|
+
"""
|
|
65
|
+
return TrismikRun(
|
|
66
|
+
id=json["id"],
|
|
67
|
+
url=json["url"],
|
|
68
|
+
status=json["status"],
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
@staticmethod
|
|
72
|
+
def to_run_info(json: Dict[str, Any]) -> TrismikRunInfo:
|
|
73
|
+
"""
|
|
74
|
+
Convert JSON response to a TrismikRunInfo object.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
json (Dict[str, Any]): JSON response containing run info.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
TrismikRunInfo: Run info object with ID.
|
|
81
|
+
"""
|
|
82
|
+
return TrismikRunInfo(id=json["id"])
|
|
83
|
+
|
|
84
|
+
@staticmethod
|
|
85
|
+
def to_run_state(json: Dict[str, Any]) -> TrismikRunState:
|
|
86
|
+
"""
|
|
87
|
+
Convert JSON response to a TrismikRunState object.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
json (Dict[str, Any]): JSON response containing run state.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
TrismikRunState: Run state object.
|
|
94
|
+
"""
|
|
95
|
+
return TrismikRunState(
|
|
96
|
+
responses=json.get("responses", []),
|
|
97
|
+
thetas=json.get("thetas", []),
|
|
98
|
+
std_error_history=json.get("std_error_history", []),
|
|
99
|
+
kl_info_history=json.get("kl_info_history", []),
|
|
100
|
+
effective_difficulties=json.get("effective_difficulties", []),
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
@staticmethod
|
|
104
|
+
def to_run_response(json: Dict[str, Any]) -> TrismikRunResponse:
|
|
105
|
+
"""
|
|
106
|
+
Convert JSON response to a TrismikRunResponse object.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
json (Dict[str, Any]): JSON response from run endpoints.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
TrismikRunResponse: Run response.
|
|
113
|
+
"""
|
|
114
|
+
return TrismikRunResponse(
|
|
115
|
+
run_info=TrismikResponseMapper.to_run_info(json["runInfo"]),
|
|
116
|
+
state=TrismikResponseMapper.to_run_state(json["state"]),
|
|
117
|
+
next_item=(
|
|
118
|
+
TrismikResponseMapper.to_item(json["nextItem"])
|
|
119
|
+
if json.get("nextItem")
|
|
120
|
+
else None
|
|
121
|
+
),
|
|
122
|
+
completed=json.get("completed", False),
|
|
42
123
|
)
|
|
43
124
|
|
|
44
125
|
@staticmethod
|
|
45
|
-
def
|
|
46
|
-
|
|
126
|
+
def to_run_summary(json: Dict[str, Any]) -> TrismikRunSummary:
|
|
127
|
+
"""
|
|
128
|
+
Convert JSON response to a TrismikRunSummary object.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
json (Dict[str, Any]): JSON response from run summary endpoint.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
TrismikRunSummary: Complete run summary.
|
|
135
|
+
"""
|
|
136
|
+
return TrismikRunSummary(
|
|
137
|
+
id=json["id"],
|
|
138
|
+
dataset_id=json["datasetId"],
|
|
139
|
+
state=TrismikResponseMapper.to_run_state(json["state"]),
|
|
140
|
+
dataset=[
|
|
141
|
+
TrismikResponseMapper.to_item(item)
|
|
142
|
+
for item in json.get("dataset", [])
|
|
143
|
+
],
|
|
144
|
+
responses=TrismikResponseMapper.to_responses(
|
|
145
|
+
json.get("responses", [])
|
|
146
|
+
),
|
|
147
|
+
metadata=json.get("metadata", {}),
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
@staticmethod
|
|
151
|
+
def to_item(json: Dict[str, Any]) -> TrismikItem:
|
|
152
|
+
"""
|
|
153
|
+
Convert JSON response to a TrismikItem object.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
json (Dict[str, Any]): JSON response containing item data.
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
TrismikItem: Item object with question and choices.
|
|
160
|
+
|
|
161
|
+
Raises:
|
|
162
|
+
TrismikApiError: If the item type is not recognized.
|
|
163
|
+
"""
|
|
164
|
+
if "question" in json and "choices" in json:
|
|
47
165
|
return TrismikMultipleChoiceTextItem(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
]
|
|
166
|
+
id=json["id"],
|
|
167
|
+
question=json["question"],
|
|
168
|
+
choices=[
|
|
169
|
+
TrismikTextChoice(
|
|
170
|
+
id=choice["id"],
|
|
171
|
+
text=choice["value"],
|
|
172
|
+
)
|
|
173
|
+
for choice in json["choices"]
|
|
174
|
+
],
|
|
56
175
|
)
|
|
57
176
|
else:
|
|
177
|
+
item_type = json.get("type", "unknown")
|
|
58
178
|
raise TrismikApiError(
|
|
59
|
-
|
|
179
|
+
f"API has returned unrecognized item type: {item_type}"
|
|
180
|
+
)
|
|
60
181
|
|
|
61
182
|
@staticmethod
|
|
62
|
-
def to_results(json: List[
|
|
183
|
+
def to_results(json: List[Dict[str, Any]]) -> List[TrismikResult]:
|
|
184
|
+
"""
|
|
185
|
+
Convert JSON response to a list of TrismikResult objects.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
json (List[Dict[str, Any]]): JSON response containing result data.
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
List[TrismikResult]: List of result objects with trait, name, and
|
|
192
|
+
value.
|
|
193
|
+
"""
|
|
63
194
|
return [
|
|
64
195
|
TrismikResult(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
)
|
|
196
|
+
trait=item["trait"],
|
|
197
|
+
name=item["name"],
|
|
198
|
+
value=item["value"],
|
|
199
|
+
)
|
|
200
|
+
for item in json
|
|
69
201
|
]
|
|
70
202
|
|
|
71
203
|
@staticmethod
|
|
72
|
-
def to_responses(json: List[
|
|
204
|
+
def to_responses(json: List[Dict[str, Any]]) -> List[TrismikResponse]:
|
|
205
|
+
"""
|
|
206
|
+
Convert JSON response to a list of TrismikResponse objects.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
json (List[Dict[str, Any]]): JSON response containing response data.
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
List[TrismikResponse]: List of response objects with dataset item
|
|
213
|
+
ID, value, and correctness.
|
|
214
|
+
"""
|
|
73
215
|
return [
|
|
74
216
|
TrismikResponse(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
)
|
|
217
|
+
dataset_item_id=response["datasetItemId"],
|
|
218
|
+
value=response["value"],
|
|
219
|
+
correct=response["correct"],
|
|
220
|
+
)
|
|
221
|
+
for response in json
|
|
79
222
|
]
|
|
223
|
+
|
|
224
|
+
@staticmethod
|
|
225
|
+
def to_replay_response(json: Dict[str, Any]) -> TrismikReplayResponse:
|
|
226
|
+
"""
|
|
227
|
+
Convert JSON response to a TrismikReplayResponse object.
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
json (Dict[str, Any]): JSON response from replay endpoint.
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
TrismikReplayResponse: Replay response object.
|
|
234
|
+
"""
|
|
235
|
+
# Parse datetime strings if they exist
|
|
236
|
+
completed_at = None
|
|
237
|
+
if "completedAt" in json and json["completedAt"]:
|
|
238
|
+
completed_at = datetime.fromisoformat(
|
|
239
|
+
json["completedAt"].replace("Z", "+00:00")
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
created_at = None
|
|
243
|
+
if "createdAt" in json and json["createdAt"]:
|
|
244
|
+
created_at = datetime.fromisoformat(
|
|
245
|
+
json["createdAt"].replace("Z", "+00:00")
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
return TrismikReplayResponse(
|
|
249
|
+
id=json["id"],
|
|
250
|
+
datasetId=json["datasetId"],
|
|
251
|
+
state=TrismikResponseMapper.to_run_state(json["state"]),
|
|
252
|
+
replay_of_run=json["replayOfRun"],
|
|
253
|
+
completedAt=completed_at,
|
|
254
|
+
createdAt=created_at,
|
|
255
|
+
metadata=json.get("metadata", {}),
|
|
256
|
+
dataset=[
|
|
257
|
+
TrismikResponseMapper.to_item(item)
|
|
258
|
+
for item in json.get("dataset", [])
|
|
259
|
+
],
|
|
260
|
+
responses=TrismikResponseMapper.to_responses(
|
|
261
|
+
json.get("responses", [])
|
|
262
|
+
),
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
@staticmethod
|
|
266
|
+
def to_me_response(json: Dict[str, Any]) -> TrismikMeResponse:
|
|
267
|
+
"""
|
|
268
|
+
Convert JSON response to a TrismikMeResponse object.
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
json (Dict[str, Any]): JSON response from /admin/api-keys/me
|
|
272
|
+
endpoint.
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
TrismikMeResponse: Me response object.
|
|
276
|
+
"""
|
|
277
|
+
user_data = json["user"]
|
|
278
|
+
organizations_data = json["organizations"]
|
|
279
|
+
|
|
280
|
+
user_info = TrismikUserInfo(
|
|
281
|
+
id=user_data["id"],
|
|
282
|
+
email=user_data["email"],
|
|
283
|
+
firstname=user_data["firstname"],
|
|
284
|
+
lastname=user_data["lastname"],
|
|
285
|
+
createdAt=user_data.get("createdAt"),
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
organizations = [
|
|
289
|
+
TrismikOrganization(
|
|
290
|
+
id=org_data["id"],
|
|
291
|
+
name=org_data["name"],
|
|
292
|
+
type=org_data["type"],
|
|
293
|
+
role=org_data["role"],
|
|
294
|
+
)
|
|
295
|
+
for org_data in organizations_data
|
|
296
|
+
]
|
|
297
|
+
|
|
298
|
+
return TrismikMeResponse(
|
|
299
|
+
user=user_info,
|
|
300
|
+
organizations=organizations,
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
@staticmethod
|
|
304
|
+
def to_classic_eval_response(
|
|
305
|
+
json: Dict[str, Any]
|
|
306
|
+
) -> TrismikClassicEvalResponse:
|
|
307
|
+
"""
|
|
308
|
+
Convert JSON response to a TrismikClassicEvalResponse object.
|
|
309
|
+
|
|
310
|
+
Args:
|
|
311
|
+
json (Dict[str, Any]): JSON response from classic evaluation
|
|
312
|
+
endpoint.
|
|
313
|
+
|
|
314
|
+
Returns:
|
|
315
|
+
TrismikClassicEvalResponse: Classic evaluation response object.
|
|
316
|
+
"""
|
|
317
|
+
user_data = json["user"]
|
|
318
|
+
user_info = TrismikUserInfo(
|
|
319
|
+
id=user_data["id"],
|
|
320
|
+
email=user_data["email"],
|
|
321
|
+
firstname=user_data["firstname"],
|
|
322
|
+
lastname=user_data["lastname"],
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
return TrismikClassicEvalResponse(
|
|
326
|
+
id=json["id"],
|
|
327
|
+
organizationId=json["organizationId"],
|
|
328
|
+
projectId=json["projectId"],
|
|
329
|
+
experimentId=json["experimentId"],
|
|
330
|
+
experimentName=json["experimentName"],
|
|
331
|
+
datasetId=json["datasetId"],
|
|
332
|
+
userId=json["userId"],
|
|
333
|
+
type=json["type"],
|
|
334
|
+
modelName=json["modelName"],
|
|
335
|
+
hyperparameters=json.get("hyperparameters", {}),
|
|
336
|
+
createdAt=json["createdAt"],
|
|
337
|
+
user=user_info,
|
|
338
|
+
responseCount=json["responseCount"],
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
@staticmethod
|
|
342
|
+
def to_project(json: Dict[str, Any]) -> TrismikProject:
|
|
343
|
+
"""
|
|
344
|
+
Convert JSON response to a TrismikProject object.
|
|
345
|
+
|
|
346
|
+
Args:
|
|
347
|
+
json (Dict[str, Any]): JSON response from project creation endpoint.
|
|
348
|
+
|
|
349
|
+
Returns:
|
|
350
|
+
TrismikProject: Project object.
|
|
351
|
+
"""
|
|
352
|
+
return TrismikProject(
|
|
353
|
+
id=json["id"],
|
|
354
|
+
name=json["name"],
|
|
355
|
+
description=json.get("description"),
|
|
356
|
+
organizationId=json["organizationId"],
|
|
357
|
+
createdAt=json["createdAt"],
|
|
358
|
+
updatedAt=json["updatedAt"],
|
|
359
|
+
)
|
trismik/_utils.py
CHANGED
|
@@ -1,44 +1,121 @@
|
|
|
1
1
|
import os
|
|
2
|
+
from typing import Optional, Union
|
|
2
3
|
|
|
3
4
|
import httpx
|
|
4
5
|
|
|
5
|
-
from .exceptions import TrismikError
|
|
6
|
+
from trismik.exceptions import TrismikError
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class TrismikUtils:
|
|
10
|
+
"""
|
|
11
|
+
Utility functions for the Trismik client.
|
|
12
|
+
|
|
13
|
+
This class provides helper methods for error handling and configuration
|
|
14
|
+
management.
|
|
15
|
+
"""
|
|
9
16
|
|
|
10
17
|
@staticmethod
|
|
11
18
|
def get_error_message(response: httpx.Response) -> str:
|
|
19
|
+
"""
|
|
20
|
+
Extract error message from an HTTP response.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
response (httpx.Response): The HTTP response containing the error.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
str: The error message from the response JSON or content.
|
|
27
|
+
"""
|
|
12
28
|
try:
|
|
13
|
-
|
|
29
|
+
json_data = response.json()
|
|
30
|
+
message = json_data.get("message", "Unknown error")
|
|
31
|
+
return str(message) # Ensure we return a string
|
|
14
32
|
except (httpx.RequestError, ValueError):
|
|
15
|
-
error_message = response.content.decode(
|
|
16
|
-
|
|
33
|
+
error_message: str = response.content.decode(
|
|
34
|
+
"utf-8", errors="ignore"
|
|
35
|
+
)
|
|
36
|
+
return error_message
|
|
17
37
|
|
|
18
38
|
@staticmethod
|
|
19
|
-
def required_option(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
39
|
+
def required_option(value: Optional[str], name: str, env: str) -> str:
|
|
40
|
+
"""
|
|
41
|
+
Get a required configuration option.
|
|
42
|
+
|
|
43
|
+
Get a required configuration option from either the provided value or
|
|
44
|
+
environment variable.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
value (Optional[str]): The provided value for the option.
|
|
48
|
+
name (str): The name of the option for error messages.
|
|
49
|
+
env (str): The environment variable name to check if value is None.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
str: The option value.
|
|
53
|
+
|
|
54
|
+
Raises:
|
|
55
|
+
TrismikError: If neither value nor environment variable is set.
|
|
56
|
+
"""
|
|
24
57
|
if value is None:
|
|
25
58
|
value = os.environ.get(env)
|
|
26
59
|
if value is None:
|
|
27
60
|
raise TrismikError(
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
61
|
+
f"The {name} client option must be set either by passing "
|
|
62
|
+
f"{env} to the client or by setting the {env} "
|
|
63
|
+
"environment variable"
|
|
31
64
|
)
|
|
32
65
|
return value
|
|
33
66
|
|
|
34
67
|
@staticmethod
|
|
35
68
|
def option(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
69
|
+
value: Optional[str],
|
|
70
|
+
default: str,
|
|
71
|
+
env: str,
|
|
39
72
|
) -> str:
|
|
73
|
+
"""
|
|
74
|
+
Get an optional configuration value.
|
|
75
|
+
|
|
76
|
+
Get an optional configuration value from either the provided value,
|
|
77
|
+
environment variable, or default value.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
value (Optional[str]): The provided value for the option.
|
|
81
|
+
default (str): The default value to use if neither value nor env var
|
|
82
|
+
is set.
|
|
83
|
+
env (str): The environment variable name to check if value is None.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
str: The option value, falling back to default if not set.
|
|
87
|
+
"""
|
|
40
88
|
if value is None:
|
|
41
89
|
value = os.environ.get(env)
|
|
42
90
|
if value is None:
|
|
43
91
|
return default
|
|
44
92
|
return value
|
|
93
|
+
|
|
94
|
+
@staticmethod
|
|
95
|
+
def metric_value_to_type(value: Union[str, float, int, bool]) -> str:
|
|
96
|
+
"""
|
|
97
|
+
Automatically determine valueType from Python value type.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
value (Union[str, float, int, bool]): The metric value to analyze.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
str: The corresponding valueType string for the API.
|
|
104
|
+
|
|
105
|
+
Raises:
|
|
106
|
+
TypeError: If the value type is not supported.
|
|
107
|
+
"""
|
|
108
|
+
if isinstance(value, bool):
|
|
109
|
+
# Handle bool first since bool is a subclass of int in Python
|
|
110
|
+
return "Boolean"
|
|
111
|
+
elif isinstance(value, str):
|
|
112
|
+
return "String"
|
|
113
|
+
elif isinstance(value, float):
|
|
114
|
+
return "Float"
|
|
115
|
+
elif isinstance(value, int):
|
|
116
|
+
return "Integer"
|
|
117
|
+
else:
|
|
118
|
+
raise TypeError(
|
|
119
|
+
f"Unsupported metric value type: {type(value).__name__}. "
|
|
120
|
+
f"Supported types: str, float, int, bool"
|
|
121
|
+
)
|