rapidata 2.21.5__py3-none-any.whl → 2.23.0__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 rapidata might be problematic. Click here for more details.
- rapidata/__init__.py +5 -0
- rapidata/api_client/__init__.py +8 -4
- rapidata/api_client/api/__init__.py +1 -0
- rapidata/api_client/api/evaluation_workflow_api.py +372 -0
- rapidata/api_client/api/identity_api.py +268 -0
- rapidata/api_client/api/rapid_api.py +353 -1987
- rapidata/api_client/api/simple_workflow_api.py +6 -6
- rapidata/api_client/models/__init__.py +7 -4
- rapidata/api_client/models/add_campaign_model.py +25 -1
- rapidata/api_client/models/add_validation_rapid_model_truth.py +24 -10
- rapidata/api_client/models/compare_result.py +2 -0
- rapidata/api_client/models/create_order_model.py +43 -2
- rapidata/api_client/models/evaluation_workflow_model1.py +115 -0
- rapidata/api_client/models/filter.py +2 -2
- rapidata/api_client/models/get_validation_rapids_result.py +11 -4
- rapidata/api_client/models/get_validation_rapids_result_truth.py +24 -10
- rapidata/api_client/models/get_workflow_by_id_result_workflow.py +23 -9
- rapidata/api_client/models/get_workflow_results_result.py +118 -0
- rapidata/api_client/models/get_workflow_results_result_paged_result.py +105 -0
- rapidata/api_client/models/google_one_tap_login_model.py +87 -0
- rapidata/api_client/models/labeling_selection.py +22 -3
- rapidata/api_client/models/logic_operator.py +1 -0
- rapidata/api_client/models/rapid_response.py +3 -1
- rapidata/api_client/models/retrieval_mode.py +38 -0
- rapidata/api_client/models/root_filter.py +2 -2
- rapidata/api_client/models/skip_truth.py +94 -0
- rapidata/api_client/models/sticky_state.py +38 -0
- rapidata/api_client/models/update_validation_rapid_model.py +11 -4
- rapidata/api_client/models/update_validation_rapid_model_truth.py +24 -10
- rapidata/api_client/rest.py +1 -0
- rapidata/api_client_README.md +10 -11
- rapidata/rapidata_client/__init__.py +7 -0
- rapidata/rapidata_client/api/rapidata_exception.py +5 -3
- rapidata/rapidata_client/assets/_media_asset.py +8 -1
- rapidata/rapidata_client/assets/_multi_asset.py +6 -0
- rapidata/rapidata_client/assets/_text_asset.py +6 -0
- rapidata/rapidata_client/demographic/demographic_manager.py +2 -3
- rapidata/rapidata_client/logging/__init__.py +2 -0
- rapidata/rapidata_client/logging/logger.py +47 -0
- rapidata/rapidata_client/logging/output_manager.py +16 -0
- rapidata/rapidata_client/order/_rapidata_dataset.py +48 -33
- rapidata/rapidata_client/order/_rapidata_order_builder.py +41 -19
- rapidata/rapidata_client/order/rapidata_order.py +22 -13
- rapidata/rapidata_client/order/rapidata_order_manager.py +84 -34
- rapidata/rapidata_client/order/rapidata_results.py +2 -1
- rapidata/rapidata_client/rapidata_client.py +6 -1
- rapidata/rapidata_client/selection/__init__.py +1 -0
- rapidata/rapidata_client/selection/labeling_selection.py +8 -2
- rapidata/rapidata_client/selection/retrieval_modes.py +9 -0
- rapidata/rapidata_client/settings/alert_on_fast_response.py +2 -1
- rapidata/rapidata_client/settings/free_text_minimum_characters.py +2 -1
- rapidata/rapidata_client/validation/rapidata_validation_set.py +2 -2
- rapidata/rapidata_client/validation/rapids/rapids.py +3 -1
- rapidata/rapidata_client/validation/validation_set_manager.py +39 -36
- rapidata/service/credential_manager.py +22 -30
- rapidata/service/openapi_service.py +11 -0
- {rapidata-2.21.5.dist-info → rapidata-2.23.0.dist-info}/METADATA +2 -1
- {rapidata-2.21.5.dist-info → rapidata-2.23.0.dist-info}/RECORD +60 -48
- {rapidata-2.21.5.dist-info → rapidata-2.23.0.dist-info}/WHEEL +1 -1
- {rapidata-2.21.5.dist-info → rapidata-2.23.0.dist-info}/LICENSE +0 -0
|
@@ -15,7 +15,7 @@ from urllib3._collections import HTTPHeaderDict # type: ignore[import]
|
|
|
15
15
|
|
|
16
16
|
from rapidata.rapidata_client.validation.rapids.box import Box
|
|
17
17
|
|
|
18
|
-
from rapidata.
|
|
18
|
+
from rapidata.rapidata_client.logging import logger, managed_print
|
|
19
19
|
from tqdm import tqdm
|
|
20
20
|
|
|
21
21
|
|
|
@@ -29,6 +29,7 @@ class ValidationSetManager:
|
|
|
29
29
|
def __init__(self, openapi_service: OpenAPIService) -> None:
|
|
30
30
|
self.__openapi_service = openapi_service
|
|
31
31
|
self.rapid = RapidsManager()
|
|
32
|
+
logger.debug("ValidationSetManager initialized")
|
|
32
33
|
|
|
33
34
|
def create_classification_set(self,
|
|
34
35
|
name: str,
|
|
@@ -40,7 +41,6 @@ class ValidationSetManager:
|
|
|
40
41
|
contexts: list[str] | None = None,
|
|
41
42
|
explanations: list[str | None] | None = None,
|
|
42
43
|
dimensions: list[str] = [],
|
|
43
|
-
print_confirmation: bool = True,
|
|
44
44
|
) -> RapidataValidationSet:
|
|
45
45
|
"""Create a classification validation set.
|
|
46
46
|
|
|
@@ -60,7 +60,6 @@ class ValidationSetManager:
|
|
|
60
60
|
Will be match up with the datapoints using the list index.
|
|
61
61
|
explanations (list[str | None], optional): The explanations for each datapoint. Will be given to the annotators in case the answer is wrong. Defaults to None.
|
|
62
62
|
dimensions (list[str], optional): The dimensions to add to the validation set accross which users will be tracked. Defaults to [] which is the default dimension.
|
|
63
|
-
print_confirmation (bool, optional): Whether to print a confirmation message that validation set has been created. Defaults to True.
|
|
64
63
|
|
|
65
64
|
Example:
|
|
66
65
|
```python
|
|
@@ -83,6 +82,7 @@ class ValidationSetManager:
|
|
|
83
82
|
if(explanations and len(explanations) != len(datapoints)):
|
|
84
83
|
raise ValueError("The numeber of reasons and datapoints must be equal, the index must align, but can be padded with None")
|
|
85
84
|
|
|
85
|
+
logger.debug("Creating classification rapids")
|
|
86
86
|
rapids: list[Rapid] = []
|
|
87
87
|
for i in range(len(datapoints)):
|
|
88
88
|
rapids.append(
|
|
@@ -97,7 +97,8 @@ class ValidationSetManager:
|
|
|
97
97
|
)
|
|
98
98
|
)
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
logger.debug("Submitting classification rapids")
|
|
101
|
+
return self._submit(name=name, rapids=rapids, dimensions=dimensions)
|
|
101
102
|
|
|
102
103
|
def create_compare_set(self,
|
|
103
104
|
name: str,
|
|
@@ -108,7 +109,6 @@ class ValidationSetManager:
|
|
|
108
109
|
contexts: list[str] | None = None,
|
|
109
110
|
explanation: list[str | None] | None = None,
|
|
110
111
|
dimensions: list[str] = [],
|
|
111
|
-
print_confirmation: bool = True,
|
|
112
112
|
) -> RapidataValidationSet:
|
|
113
113
|
"""Create a comparison validation set.
|
|
114
114
|
|
|
@@ -128,7 +128,6 @@ class ValidationSetManager:
|
|
|
128
128
|
Will be match up with the datapoints using the list index.
|
|
129
129
|
explanation (list[str | None], optional): The explanations for each datapoint. Will be given to the annotators in case the answer is wrong. Defaults to None.
|
|
130
130
|
dimensions (list[str], optional): The dimensions to add to the validation set accross which users will be tracked. Defaults to [] which is the default dimension.
|
|
131
|
-
print_confirmation (bool, optional): Whether to print a confirmation message that validation set has been created. Defaults to True.
|
|
132
131
|
|
|
133
132
|
Example:
|
|
134
133
|
```python
|
|
@@ -150,7 +149,8 @@ class ValidationSetManager:
|
|
|
150
149
|
|
|
151
150
|
if(explanation and len(explanation) != len(datapoints)):
|
|
152
151
|
raise ValueError("The numeber of reasons and datapoints must be equal, the index must align, but can be padded with None")
|
|
153
|
-
|
|
152
|
+
|
|
153
|
+
logger.debug("Creating comparison rapids")
|
|
154
154
|
rapids: list[Rapid] = []
|
|
155
155
|
for i in range(len(datapoints)):
|
|
156
156
|
rapids.append(
|
|
@@ -163,8 +163,9 @@ class ValidationSetManager:
|
|
|
163
163
|
explanation=explanation[i] if explanation != None else None
|
|
164
164
|
)
|
|
165
165
|
)
|
|
166
|
-
|
|
167
|
-
|
|
166
|
+
|
|
167
|
+
logger.debug("Submitting comparison rapids")
|
|
168
|
+
return self._submit(name=name, rapids=rapids, dimensions=dimensions)
|
|
168
169
|
|
|
169
170
|
def create_select_words_set(self,
|
|
170
171
|
name: str,
|
|
@@ -176,7 +177,6 @@ class ValidationSetManager:
|
|
|
176
177
|
required_completeness: float = 1.0,
|
|
177
178
|
explanation: list[str | None] | None = None,
|
|
178
179
|
dimensions: list[str] = [],
|
|
179
|
-
print_confirmation: bool = True,
|
|
180
180
|
) -> RapidataValidationSet:
|
|
181
181
|
"""Create a select words validation set.
|
|
182
182
|
|
|
@@ -195,7 +195,6 @@ class ValidationSetManager:
|
|
|
195
195
|
required_completeness (float, optional): The required completeness for the labeler to get the rapid correct (miminum ratio of total correct words selected). Defaults to 1.0 (all correct words need to be selected).
|
|
196
196
|
explanation (list[str | None], optional): The explanations for each datapoint. Will be given to the annotators in case the answer is wrong. Defaults to None.
|
|
197
197
|
dimensions (list[str], optional): The dimensions to add to the validation set accross which users will be tracked. Defaults to [] which is the default dimension.
|
|
198
|
-
print_confirmation (bool, optional): Whether to print a confirmation message that validation set has been created. Defaults to True.
|
|
199
198
|
|
|
200
199
|
Example:
|
|
201
200
|
```python
|
|
@@ -214,7 +213,8 @@ class ValidationSetManager:
|
|
|
214
213
|
|
|
215
214
|
if(explanation and len(explanation) != len(datapoints)):
|
|
216
215
|
raise ValueError("The numeber of reasons and datapoints must be equal, the index must align, but can be padded with None")
|
|
217
|
-
|
|
216
|
+
|
|
217
|
+
logger.debug("Creating select words rapids")
|
|
218
218
|
rapids: list[Rapid] = []
|
|
219
219
|
for i in range(len(datapoints)):
|
|
220
220
|
rapids.append(
|
|
@@ -229,7 +229,8 @@ class ValidationSetManager:
|
|
|
229
229
|
)
|
|
230
230
|
)
|
|
231
231
|
|
|
232
|
-
|
|
232
|
+
logger.debug("Submitting select words rapids")
|
|
233
|
+
return self._submit(name=name, rapids=rapids, dimensions=dimensions)
|
|
233
234
|
|
|
234
235
|
def create_locate_set(self,
|
|
235
236
|
name: str,
|
|
@@ -239,7 +240,6 @@ class ValidationSetManager:
|
|
|
239
240
|
contexts: list[str] | None = None,
|
|
240
241
|
explanation: list[str | None] | None = None,
|
|
241
242
|
dimensions: list[str] = [],
|
|
242
|
-
print_confirmation: bool = True,
|
|
243
243
|
) -> RapidataValidationSet:
|
|
244
244
|
"""Create a locate validation set.
|
|
245
245
|
|
|
@@ -254,7 +254,6 @@ class ValidationSetManager:
|
|
|
254
254
|
contexts (list[str], optional): The contexts for each datapoint. Defaults to None.
|
|
255
255
|
explanation (list[str | None], optional): The explanations for each datapoint. Will be given to the annotators in case the answer is wrong. Defaults to None.
|
|
256
256
|
dimensions (list[str], optional): The dimensions to add to the validation set accross which users will be tracked. Defaults to [] which is the default dimension.
|
|
257
|
-
print_confirmation (bool, optional): Whether to print a confirmation message that validation set has been created. Defaults to True.
|
|
258
257
|
|
|
259
258
|
Example:
|
|
260
259
|
```python
|
|
@@ -275,7 +274,8 @@ class ValidationSetManager:
|
|
|
275
274
|
|
|
276
275
|
if(explanation and len(explanation) != len(datapoints)):
|
|
277
276
|
raise ValueError("The numeber of reasons and datapoints must be equal, the index must align, but can be padded with None")
|
|
278
|
-
|
|
277
|
+
|
|
278
|
+
logger.debug("Creating locate rapids")
|
|
279
279
|
rapids = []
|
|
280
280
|
rapids: list[Rapid] = []
|
|
281
281
|
for i in range(len(datapoints)):
|
|
@@ -290,7 +290,8 @@ class ValidationSetManager:
|
|
|
290
290
|
)
|
|
291
291
|
)
|
|
292
292
|
|
|
293
|
-
|
|
293
|
+
logger.debug("Submitting locate rapids")
|
|
294
|
+
return self._submit(name=name, rapids=rapids, dimensions=dimensions)
|
|
294
295
|
|
|
295
296
|
def create_draw_set(self,
|
|
296
297
|
name: str,
|
|
@@ -300,7 +301,6 @@ class ValidationSetManager:
|
|
|
300
301
|
contexts: list[str] | None = None,
|
|
301
302
|
explanation: list[str | None] | None = None,
|
|
302
303
|
dimensions: list[str] = [],
|
|
303
|
-
print_confirmation: bool = True,
|
|
304
304
|
) -> RapidataValidationSet:
|
|
305
305
|
"""Create a draw validation set.
|
|
306
306
|
|
|
@@ -315,7 +315,6 @@ class ValidationSetManager:
|
|
|
315
315
|
contexts (list[str], optional): The contexts for each datapoint. Defaults to None.
|
|
316
316
|
explanation (list[str | None], optional): The explanations for each datapoint. Will be given to the annotators in case the answer is wrong. Defaults to None.
|
|
317
317
|
dimensions (list[str], optional): The dimensions to add to the validation set accross which users will be tracked. Defaults to [] which is the default dimension.
|
|
318
|
-
print_confirmation (bool, optional): Whether to print a confirmation message that validation set has been created. Defaults to True.
|
|
319
318
|
|
|
320
319
|
Example:
|
|
321
320
|
```python
|
|
@@ -336,7 +335,8 @@ class ValidationSetManager:
|
|
|
336
335
|
|
|
337
336
|
if(explanation and len(explanation) != len(datapoints)):
|
|
338
337
|
raise ValueError("The numeber of reasons and datapoints must be equal, the index must align, but can be padded with None")
|
|
339
|
-
|
|
338
|
+
|
|
339
|
+
logger.debug("Creating draw rapids")
|
|
340
340
|
rapids: list[Rapid] = []
|
|
341
341
|
for i in range(len(datapoints)):
|
|
342
342
|
rapids.append(
|
|
@@ -350,7 +350,8 @@ class ValidationSetManager:
|
|
|
350
350
|
)
|
|
351
351
|
)
|
|
352
352
|
|
|
353
|
-
|
|
353
|
+
logger.debug("Submitting draw rapids")
|
|
354
|
+
return self._submit(name=name, rapids=rapids, dimensions=dimensions)
|
|
354
355
|
|
|
355
356
|
def create_timestamp_set(self,
|
|
356
357
|
name: str,
|
|
@@ -360,7 +361,6 @@ class ValidationSetManager:
|
|
|
360
361
|
contexts: list[str] | None = None,
|
|
361
362
|
explanation: list[str | None] | None = None,
|
|
362
363
|
dimensions: list[str] = [],
|
|
363
|
-
print_confirmation: bool = True,
|
|
364
364
|
) -> RapidataValidationSet:
|
|
365
365
|
"""Create a timestamp validation set.
|
|
366
366
|
|
|
@@ -376,7 +376,6 @@ class ValidationSetManager:
|
|
|
376
376
|
contexts (list[str], optional): The contexts for each datapoint. Defaults to None.
|
|
377
377
|
explanation (list[str | None], optional): The explanations for each datapoint. Will be given to the annotators in case the answer is wrong. Defaults to None.
|
|
378
378
|
dimensions (list[str], optional): The dimensions to add to the validation set accross which users will be tracked. Defaults to [] which is the default dimension.
|
|
379
|
-
print_confirmation (bool, optional): Whether to print a confirmation message that validation set has been created. Defaults to True.
|
|
380
379
|
|
|
381
380
|
Example:
|
|
382
381
|
```python
|
|
@@ -398,7 +397,7 @@ class ValidationSetManager:
|
|
|
398
397
|
if(explanation and len(explanation) != len(datapoints)):
|
|
399
398
|
raise ValueError("The numeber of reasons and datapoints must be equal, the index must align, but can be padded with None")
|
|
400
399
|
|
|
401
|
-
|
|
400
|
+
logger.debug("Creating timestamp rapids")
|
|
402
401
|
rapids: list[Rapid] = []
|
|
403
402
|
for i in range(len(datapoints)):
|
|
404
403
|
rapids.append(
|
|
@@ -411,13 +410,13 @@ class ValidationSetManager:
|
|
|
411
410
|
)
|
|
412
411
|
)
|
|
413
412
|
|
|
414
|
-
|
|
413
|
+
logger.debug("Submitting timestamp rapids")
|
|
414
|
+
return self._submit(name=name, rapids=rapids, dimensions=dimensions)
|
|
415
415
|
|
|
416
416
|
def create_mixed_set(self,
|
|
417
417
|
name: str,
|
|
418
418
|
rapids: list[Rapid],
|
|
419
419
|
dimensions: list[str] = [],
|
|
420
|
-
print_confirmation: bool = True
|
|
421
420
|
) -> RapidataValidationSet:
|
|
422
421
|
"""Create a validation set with a list of rapids.
|
|
423
422
|
|
|
@@ -425,10 +424,9 @@ class ValidationSetManager:
|
|
|
425
424
|
name (str): The name of the validation set. (will not be shown to the labeler)
|
|
426
425
|
rapids (list[Rapid]): The list of rapids to add to the validation set.
|
|
427
426
|
dimensions (list[str], optional): The dimensions to add to the validation set accross which users will be tracked. Defaults to [] which is the default dimension.
|
|
428
|
-
print_confirmation (bool, optional): Whether to print a confirmation message that validation set has been created. Defaults to True.
|
|
429
427
|
"""
|
|
430
428
|
|
|
431
|
-
return self._submit(name=name, rapids=rapids, dimensions=dimensions
|
|
429
|
+
return self._submit(name=name, rapids=rapids, dimensions=dimensions)
|
|
432
430
|
|
|
433
431
|
def get_validation_set_by_id(self, validation_set_id: str) -> RapidataValidationSet:
|
|
434
432
|
"""Get a validation set by ID.
|
|
@@ -444,32 +442,37 @@ class ValidationSetManager:
|
|
|
444
442
|
except Exception:
|
|
445
443
|
raise ValueError(f"ValidationSet with ID {validation_set_id} not found.")
|
|
446
444
|
|
|
447
|
-
return RapidataValidationSet(validation_set_id, validation_set.name, self.__openapi_service)
|
|
445
|
+
return RapidataValidationSet(validation_set_id, str(validation_set.name), self.__openapi_service)
|
|
448
446
|
|
|
449
|
-
def _submit(self, name: str, rapids: list[Rapid], dimensions: list[str] | None
|
|
447
|
+
def _submit(self, name: str, rapids: list[Rapid], dimensions: list[str] | None) -> RapidataValidationSet:
|
|
448
|
+
logger.debug("Creating validation set")
|
|
450
449
|
validation_set_id = (
|
|
451
450
|
self.__openapi_service.validation_api.validation_create_validation_set_post(
|
|
452
451
|
name=name
|
|
453
452
|
)
|
|
454
453
|
).validation_set_id
|
|
455
454
|
|
|
455
|
+
logger.debug(f"Validation set created with ID: {validation_set_id}")
|
|
456
|
+
|
|
456
457
|
if validation_set_id is None:
|
|
457
458
|
raise ValueError("Failed to create validation set")
|
|
458
459
|
|
|
460
|
+
logger.debug("Creating validation set instance")
|
|
461
|
+
|
|
459
462
|
validation_set = RapidataValidationSet(
|
|
460
463
|
name=name,
|
|
461
464
|
validation_set_id=validation_set_id,
|
|
462
465
|
openapi_service=self.__openapi_service
|
|
463
466
|
)
|
|
464
467
|
|
|
468
|
+
logger.debug("Adding rapids to validation set")
|
|
465
469
|
for rapid in tqdm(rapids, desc="Uploading validation tasks"):
|
|
466
470
|
validation_set.add_rapid(rapid)
|
|
467
471
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
sep="")
|
|
472
|
+
managed_print()
|
|
473
|
+
managed_print(f"Validation set '{name}' created with ID {validation_set_id}\n",
|
|
474
|
+
f"Now viewable under: https://app.{self.__openapi_service.environment}/validation-set/detail/{validation_set_id}",
|
|
475
|
+
sep="")
|
|
473
476
|
|
|
474
477
|
if dimensions:
|
|
475
478
|
validation_set.update_dimensions(dimensions)
|
|
@@ -500,6 +503,6 @@ class ValidationSetManager:
|
|
|
500
503
|
except Exception as e:
|
|
501
504
|
raise ValueError(f"Unknown error occured: {e}")
|
|
502
505
|
|
|
503
|
-
validation_sets = [self.get_validation_set_by_id(validation_set.id) for validation_set in validation_page_result.items]
|
|
506
|
+
validation_sets = [self.get_validation_set_by_id(str(validation_set.id)) for validation_set in validation_page_result.items]
|
|
504
507
|
return validation_sets
|
|
505
508
|
|
|
@@ -11,6 +11,7 @@ from typing import Dict, List, Optional, Tuple
|
|
|
11
11
|
import requests
|
|
12
12
|
from colorama import Fore
|
|
13
13
|
from pydantic import BaseModel
|
|
14
|
+
from rapidata.rapidata_client.logging import logger, managed_print
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
class ClientCredential(BaseModel):
|
|
@@ -21,27 +22,6 @@ class ClientCredential(BaseModel):
|
|
|
21
22
|
created_at: datetime
|
|
22
23
|
last_used: datetime
|
|
23
24
|
|
|
24
|
-
@classmethod
|
|
25
|
-
def from_dict(cls, data: Dict):
|
|
26
|
-
return cls(
|
|
27
|
-
display_name=data["display_name"],
|
|
28
|
-
client_id=data["client_id"],
|
|
29
|
-
client_secret=data["client_secret"],
|
|
30
|
-
endpoint=data["endpoint"],
|
|
31
|
-
created_at=datetime.fromisoformat(data["created_at"]),
|
|
32
|
-
last_used=datetime.fromisoformat(data["last_used"]),
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
def to_dict(self) -> Dict:
|
|
36
|
-
return {
|
|
37
|
-
"display_name": self.display_name,
|
|
38
|
-
"client_id": self.client_id,
|
|
39
|
-
"client_secret": self.client_secret,
|
|
40
|
-
"endpoint": self.endpoint,
|
|
41
|
-
"created_at": self.created_at.isoformat(),
|
|
42
|
-
"last_used": self.last_used.isoformat(),
|
|
43
|
-
}
|
|
44
|
-
|
|
45
25
|
def get_display_string(self):
|
|
46
26
|
return f"{self.display_name} - Client ID: {self.client_id} (Created: {self.created_at.strftime('%Y-%m-%d %H:%M:%S')})"
|
|
47
27
|
|
|
@@ -72,6 +52,7 @@ class CredentialManager:
|
|
|
72
52
|
|
|
73
53
|
def _read_credentials(self) -> Dict[str, List[ClientCredential]]:
|
|
74
54
|
"""Read all stored credentials from the config file."""
|
|
55
|
+
logger.debug(f"Reading credentials from {self.config_path}")
|
|
75
56
|
if not self.config_path.exists():
|
|
76
57
|
return {}
|
|
77
58
|
|
|
@@ -79,7 +60,7 @@ class CredentialManager:
|
|
|
79
60
|
with open(self.config_path, "r") as f:
|
|
80
61
|
data = json.load(f)
|
|
81
62
|
return {
|
|
82
|
-
env: [ClientCredential.
|
|
63
|
+
env: [ClientCredential.model_validate(cred) for cred in creds]
|
|
83
64
|
for env, creds in data.items()
|
|
84
65
|
}
|
|
85
66
|
except json.JSONDecodeError:
|
|
@@ -89,15 +70,18 @@ class CredentialManager:
|
|
|
89
70
|
self, credentials: Dict[str, List[ClientCredential]]
|
|
90
71
|
) -> None:
|
|
91
72
|
data = {
|
|
92
|
-
env: [cred.
|
|
73
|
+
env: [cred.model_dump(mode="json") for cred in creds]
|
|
93
74
|
for env, creds in credentials.items()
|
|
94
75
|
}
|
|
95
76
|
|
|
96
77
|
with open(self.config_path, "w") as f:
|
|
97
78
|
json.dump(data, f, indent=2)
|
|
98
79
|
|
|
80
|
+
logger.debug(f"Credentials written to {self.config_path} with data: {data}")
|
|
81
|
+
|
|
99
82
|
# Ensure file is only readable by the user
|
|
100
83
|
os.chmod(self.config_path, 0o600)
|
|
84
|
+
logger.debug(f"Set permissions for {self.config_path} to read/write for user only.")
|
|
101
85
|
|
|
102
86
|
def _store_credential(self, credential: ClientCredential) -> None:
|
|
103
87
|
credentials = self._read_credentials()
|
|
@@ -123,15 +107,19 @@ class CredentialManager:
|
|
|
123
107
|
def get_client_credentials(self) -> Optional[ClientCredential]:
|
|
124
108
|
"""Gets stored client credentials or create new ones via browser auth."""
|
|
125
109
|
credentials = self._read_credentials()
|
|
110
|
+
logger.debug(f"Stored credentials: {credentials}")
|
|
126
111
|
env_credentials = credentials.get(self.endpoint, [])
|
|
127
112
|
|
|
128
113
|
if env_credentials:
|
|
114
|
+
logger.debug(f"Found credentials for {self.endpoint}: {env_credentials}")
|
|
129
115
|
credential = self._select_credential(env_credentials)
|
|
116
|
+
logger.debug(f"Selected credential: {credential}")
|
|
130
117
|
if credential:
|
|
131
118
|
credential.last_used = datetime.now(timezone.utc)
|
|
132
119
|
self._write_credentials(credentials)
|
|
133
120
|
return credential
|
|
134
121
|
|
|
122
|
+
logger.debug(f"No credentials found for {self.endpoint}. Creating new ones.")
|
|
135
123
|
return self._create_new_credentials()
|
|
136
124
|
|
|
137
125
|
def reset_credentials(self) -> None:
|
|
@@ -140,22 +128,26 @@ class CredentialManager:
|
|
|
140
128
|
if self.endpoint in credentials:
|
|
141
129
|
del credentials[self.endpoint]
|
|
142
130
|
self._write_credentials(credentials)
|
|
131
|
+
logger.info(
|
|
132
|
+
f"Credentials for {self.endpoint} have been reset."
|
|
133
|
+
)
|
|
143
134
|
|
|
144
135
|
def _get_bridge_tokens(self) -> Optional[BridgeToken]:
|
|
145
136
|
"""Get bridge tokens from the identity endpoint."""
|
|
137
|
+
logger.debug("Getting bridge tokens")
|
|
146
138
|
try:
|
|
147
139
|
bridge_endpoint = (
|
|
148
140
|
f"{self.endpoint}/Identity/CreateBridgeToken?clientId=rapidata-cli"
|
|
149
141
|
)
|
|
150
142
|
response = requests.post(bridge_endpoint, verify=self.cert_path)
|
|
151
143
|
if not response.ok:
|
|
152
|
-
|
|
144
|
+
logger.error(f"Failed to get bridge tokens: {response.status_code}")
|
|
153
145
|
return None
|
|
154
146
|
|
|
155
147
|
data = response.json()
|
|
156
148
|
return BridgeToken(read_key=data["readKey"], write_key=data["writeKey"])
|
|
157
149
|
except requests.RequestException as e:
|
|
158
|
-
|
|
150
|
+
logger.error(f"Failed to get bridge tokens: {e}")
|
|
159
151
|
return None
|
|
160
152
|
|
|
161
153
|
def _poll_read_key(self, read_key: str) -> Optional[str]:
|
|
@@ -177,14 +169,14 @@ class CredentialManager:
|
|
|
177
169
|
continue
|
|
178
170
|
else:
|
|
179
171
|
# Error occurred
|
|
180
|
-
|
|
172
|
+
logger.error(f"Error polling read key: {response.status_code}")
|
|
181
173
|
return None
|
|
182
174
|
|
|
183
175
|
except requests.RequestException as e:
|
|
184
|
-
|
|
176
|
+
logger.error(f"Error polling read key: {e}")
|
|
185
177
|
return None
|
|
186
178
|
|
|
187
|
-
|
|
179
|
+
logger.error("Polling timed out")
|
|
188
180
|
return None
|
|
189
181
|
|
|
190
182
|
def _create_client(self, access_token: str) -> Optional[Tuple[str, str, str]]:
|
|
@@ -206,7 +198,7 @@ class CredentialManager:
|
|
|
206
198
|
data = response.json()
|
|
207
199
|
return data.get("clientId"), data.get("clientSecret"), display_name
|
|
208
200
|
except requests.RequestException as e:
|
|
209
|
-
|
|
201
|
+
logger.error(f"Failed to create client: {e}")
|
|
210
202
|
return None
|
|
211
203
|
|
|
212
204
|
def _create_new_credentials(self) -> Optional[ClientCredential]:
|
|
@@ -219,7 +211,7 @@ class CredentialManager:
|
|
|
219
211
|
|
|
220
212
|
if not could_open_browser:
|
|
221
213
|
encoded_url = urllib.parse.quote(auth_url, safe="%/:=&?~#+!$,;'@()*[]")
|
|
222
|
-
|
|
214
|
+
managed_print(
|
|
223
215
|
Fore.RED
|
|
224
216
|
+ f'Please open the following URL in your browser to log in: "{encoded_url}"'
|
|
225
217
|
+ Fore.RESET
|
|
@@ -11,6 +11,7 @@ from rapidata.api_client.api.workflow_api import WorkflowApi
|
|
|
11
11
|
from rapidata.api_client.configuration import Configuration
|
|
12
12
|
from rapidata.service.credential_manager import CredentialManager
|
|
13
13
|
from rapidata.rapidata_client.api.rapidata_exception import RapidataApiClient
|
|
14
|
+
from rapidata.rapidata_client.logging import logger
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
class OpenAPIService:
|
|
@@ -31,18 +32,25 @@ class OpenAPIService:
|
|
|
31
32
|
if environment == "rapidata.dev" and not cert_path:
|
|
32
33
|
cert_path = _get_local_certificate()
|
|
33
34
|
|
|
35
|
+
logger.debug(f"Using cert_path: {cert_path} environment: {environment} token: {token} client_id: {client_id} client_secret: {client_secret}")
|
|
36
|
+
logger.debug("Initializing OpenAPIService")
|
|
34
37
|
self.credential_manager = CredentialManager(
|
|
35
38
|
endpoint=auth_endpoint, cert_path=cert_path
|
|
36
39
|
)
|
|
40
|
+
logger.debug("CredentialManager initialized")
|
|
37
41
|
|
|
42
|
+
logger.debug("Initializing RapidataApiClient")
|
|
38
43
|
client_configuration = Configuration(host=endpoint, ssl_ca_cert=cert_path)
|
|
44
|
+
logger.debug(f"Client configuration: {client_configuration}")
|
|
39
45
|
self.api_client = RapidataApiClient(
|
|
40
46
|
configuration=client_configuration,
|
|
41
47
|
header_name="X-Client",
|
|
42
48
|
header_value=f"RapidataPythonSDK/{self._get_rapidata_package_version()}",
|
|
43
49
|
)
|
|
50
|
+
logger.debug("RapidataApiClient initialized")
|
|
44
51
|
|
|
45
52
|
if token:
|
|
53
|
+
logger.debug("Using token for authentication")
|
|
46
54
|
self.api_client.rest_client.setup_oauth_with_token(
|
|
47
55
|
token=token,
|
|
48
56
|
token_endpoint=f"{auth_endpoint}/connect/token",
|
|
@@ -50,9 +58,11 @@ class OpenAPIService:
|
|
|
50
58
|
client_secret=client_secret,
|
|
51
59
|
leeway=leeway,
|
|
52
60
|
)
|
|
61
|
+
logger.debug("Token authentication setup complete")
|
|
53
62
|
return
|
|
54
63
|
|
|
55
64
|
if not client_id or not client_secret:
|
|
65
|
+
logger.debug("Client ID and secret not provided, fetching from credential manager")
|
|
56
66
|
credentials = self.credential_manager.get_client_credentials()
|
|
57
67
|
if not credentials:
|
|
58
68
|
raise ValueError("Failed to fetch client credentials")
|
|
@@ -65,6 +75,7 @@ class OpenAPIService:
|
|
|
65
75
|
token_endpoint=f"{auth_endpoint}/connect/token",
|
|
66
76
|
scope=oauth_scope,
|
|
67
77
|
)
|
|
78
|
+
logger.debug("Client credentials authentication setup complete")
|
|
68
79
|
|
|
69
80
|
def reset_credentials(self):
|
|
70
81
|
self.credential_manager.reset_credentials()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: rapidata
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.23.0
|
|
4
4
|
Summary: Rapidata package containing the Rapidata Python Client to interact with the Rapidata Web API in an easy way.
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Author: Rapidata AG
|
|
@@ -27,6 +27,7 @@ Requires-Dist: tqdm (>=4.66.5,<5.0.0)
|
|
|
27
27
|
Description-Content-Type: text/markdown
|
|
28
28
|
|
|
29
29
|
# Rapidata Python Client
|
|
30
|
+
|
|
30
31
|
Python client to interface with the Rapidata API.
|
|
31
32
|
|
|
32
33
|
Docs: https://docs.rapidata.ai/
|