rapidata 2.37.0__py3-none-any.whl → 2.38.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 +3 -4
- rapidata/rapidata_client/__init__.py +1 -4
- rapidata/rapidata_client/api/{rapidata_exception.py → rapidata_api_client.py} +119 -2
- rapidata/rapidata_client/benchmark/leaderboard/rapidata_leaderboard.py +88 -46
- rapidata/rapidata_client/benchmark/participant/_participant.py +26 -9
- rapidata/rapidata_client/benchmark/rapidata_benchmark.py +274 -205
- rapidata/rapidata_client/benchmark/rapidata_benchmark_manager.py +98 -76
- rapidata/rapidata_client/config/__init__.py +3 -0
- rapidata/rapidata_client/config/logger.py +135 -0
- rapidata/rapidata_client/config/logging_config.py +58 -0
- rapidata/rapidata_client/config/managed_print.py +6 -0
- rapidata/rapidata_client/config/order_config.py +14 -0
- rapidata/rapidata_client/config/rapidata_config.py +14 -9
- rapidata/rapidata_client/config/tracer.py +130 -0
- rapidata/rapidata_client/config/upload_config.py +14 -0
- rapidata/rapidata_client/datapoints/_datapoint.py +1 -1
- rapidata/rapidata_client/datapoints/assets/_media_asset.py +1 -1
- rapidata/rapidata_client/datapoints/assets/_sessions.py +2 -2
- rapidata/rapidata_client/demographic/demographic_manager.py +16 -14
- rapidata/rapidata_client/filter/_base_filter.py +11 -5
- rapidata/rapidata_client/filter/age_filter.py +9 -3
- rapidata/rapidata_client/filter/and_filter.py +20 -5
- rapidata/rapidata_client/filter/campaign_filter.py +7 -1
- rapidata/rapidata_client/filter/country_filter.py +8 -2
- rapidata/rapidata_client/filter/custom_filter.py +9 -3
- rapidata/rapidata_client/filter/gender_filter.py +9 -3
- rapidata/rapidata_client/filter/language_filter.py +12 -5
- rapidata/rapidata_client/filter/new_user_filter.py +3 -4
- rapidata/rapidata_client/filter/not_filter.py +17 -5
- rapidata/rapidata_client/filter/or_filter.py +20 -5
- rapidata/rapidata_client/filter/response_count_filter.py +6 -0
- rapidata/rapidata_client/filter/user_score_filter.py +17 -5
- rapidata/rapidata_client/order/_rapidata_dataset.py +45 -17
- rapidata/rapidata_client/order/_rapidata_order_builder.py +19 -13
- rapidata/rapidata_client/order/rapidata_order.py +60 -48
- rapidata/rapidata_client/order/rapidata_order_manager.py +231 -197
- rapidata/rapidata_client/order/rapidata_results.py +71 -57
- rapidata/rapidata_client/rapidata_client.py +36 -23
- rapidata/rapidata_client/selection/_base_selection.py +6 -0
- rapidata/rapidata_client/selection/static_selection.py +5 -10
- rapidata/rapidata_client/settings/_rapidata_setting.py +8 -0
- rapidata/rapidata_client/settings/alert_on_fast_response.py +8 -5
- rapidata/rapidata_client/settings/free_text_minimum_characters.py +9 -4
- rapidata/rapidata_client/validation/rapidata_validation_set.py +20 -16
- rapidata/rapidata_client/validation/rapids/rapids.py +7 -1
- rapidata/rapidata_client/validation/validation_set_manager.py +285 -268
- rapidata/rapidata_client/workflow/_base_workflow.py +6 -1
- rapidata/rapidata_client/workflow/_classify_workflow.py +6 -0
- rapidata/rapidata_client/workflow/_compare_workflow.py +6 -0
- rapidata/rapidata_client/workflow/_draw_workflow.py +6 -0
- rapidata/rapidata_client/workflow/_evaluation_workflow.py +6 -0
- rapidata/rapidata_client/workflow/_free_text_workflow.py +6 -0
- rapidata/rapidata_client/workflow/_locate_workflow.py +6 -0
- rapidata/rapidata_client/workflow/_ranking_workflow.py +12 -0
- rapidata/rapidata_client/workflow/_select_words_workflow.py +6 -0
- rapidata/rapidata_client/workflow/_timestamp_workflow.py +6 -0
- rapidata/service/credential_manager.py +1 -1
- rapidata/service/openapi_service.py +2 -2
- {rapidata-2.37.0.dist-info → rapidata-2.38.0.dist-info}/METADATA +4 -1
- {rapidata-2.37.0.dist-info → rapidata-2.38.0.dist-info}/RECORD +62 -59
- rapidata/rapidata_client/logging/__init__.py +0 -2
- rapidata/rapidata_client/logging/logger.py +0 -122
- rapidata/rapidata_client/logging/output_manager.py +0 -20
- {rapidata-2.37.0.dist-info → rapidata-2.38.0.dist-info}/LICENSE +0 -0
- {rapidata-2.37.0.dist-info → rapidata-2.38.0.dist-info}/WHEEL +0 -0
|
@@ -1,29 +1,31 @@
|
|
|
1
1
|
from rapidata.service.openapi_service import OpenAPIService
|
|
2
2
|
from rapidata.rapidata_client.datapoints.assets import MediaAsset
|
|
3
|
-
from rapidata.api_client.models.create_demographic_rapid_model import
|
|
3
|
+
from rapidata.api_client.models.create_demographic_rapid_model import (
|
|
4
|
+
CreateDemographicRapidModel,
|
|
5
|
+
)
|
|
4
6
|
from rapidata.api_client.models.classify_payload import ClassifyPayload
|
|
5
|
-
from rapidata.rapidata_client.
|
|
7
|
+
from rapidata.rapidata_client.config import logger
|
|
8
|
+
|
|
6
9
|
|
|
7
10
|
class DemographicManager:
|
|
8
11
|
def __init__(self, openapi_service: OpenAPIService):
|
|
9
12
|
self._openapi_service = openapi_service
|
|
10
13
|
logger.debug("DemographicManager initialized")
|
|
11
|
-
|
|
12
|
-
def create_demographic_rapid(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
key: str):
|
|
17
|
-
|
|
14
|
+
|
|
15
|
+
def create_demographic_rapid(
|
|
16
|
+
self, instruction: str, answer_options: list[str], datapoint: str, key: str
|
|
17
|
+
):
|
|
18
|
+
|
|
18
19
|
media = MediaAsset(path=datapoint)
|
|
19
20
|
model = CreateDemographicRapidModel(
|
|
20
21
|
key=key,
|
|
21
22
|
payload=ClassifyPayload(
|
|
22
23
|
_t="ClassifyPayload",
|
|
23
24
|
possibleCategories=answer_options,
|
|
24
|
-
title=instruction
|
|
25
|
-
)
|
|
25
|
+
title=instruction,
|
|
26
|
+
),
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
self._openapi_service.rapid_api.rapid_demographic_post(
|
|
30
|
+
model=model, file=[media.to_file()]
|
|
26
31
|
)
|
|
27
|
-
|
|
28
|
-
self._openapi_service.rapid_api.rapid_demographic_post(model=model, file=[media.to_file()])
|
|
29
|
-
|
|
@@ -13,9 +13,9 @@ class RapidataFilter:
|
|
|
13
13
|
"""Enable the | operator to create OrFilter combinations."""
|
|
14
14
|
if not isinstance(other, RapidataFilter):
|
|
15
15
|
return NotImplemented
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
from rapidata.rapidata_client.filter.or_filter import OrFilter
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
# If self is already an OrFilter, extend its filters list
|
|
20
20
|
if isinstance(self, OrFilter):
|
|
21
21
|
if isinstance(other, OrFilter):
|
|
@@ -33,9 +33,9 @@ class RapidataFilter:
|
|
|
33
33
|
"""Enable the & operator to create AndFilter combinations."""
|
|
34
34
|
if not isinstance(other, RapidataFilter):
|
|
35
35
|
return NotImplemented
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
from rapidata.rapidata_client.filter.and_filter import AndFilter
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
# If self is already an AndFilter, extend its filters list
|
|
40
40
|
if isinstance(self, AndFilter):
|
|
41
41
|
if isinstance(other, AndFilter):
|
|
@@ -52,10 +52,16 @@ class RapidataFilter:
|
|
|
52
52
|
def __invert__(self):
|
|
53
53
|
"""Enable the ~ operator to create NotFilter negations."""
|
|
54
54
|
from rapidata.rapidata_client.filter.not_filter import NotFilter
|
|
55
|
-
|
|
55
|
+
|
|
56
56
|
# If self is already a NotFilter, return the original filter (double negation)
|
|
57
57
|
if isinstance(self, NotFilter):
|
|
58
58
|
return self.filter
|
|
59
59
|
# Create a new NotFilter
|
|
60
60
|
else:
|
|
61
61
|
return NotFilter(self)
|
|
62
|
+
|
|
63
|
+
def __str__(self) -> str:
|
|
64
|
+
return f"{self.__class__.__name__}()"
|
|
65
|
+
|
|
66
|
+
def __repr__(self) -> str:
|
|
67
|
+
return f"{self.__class__.__name__}()"
|
|
@@ -6,10 +6,10 @@ from rapidata.rapidata_client.filter.models.age_group import AgeGroup
|
|
|
6
6
|
|
|
7
7
|
class AgeFilter(RapidataFilter):
|
|
8
8
|
"""AgeFilter Class
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
Can be used to filter who to target based on age groups.
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
|
|
12
|
+
|
|
13
13
|
Args:
|
|
14
14
|
age_groups (list[AgeGroup]): List of age groups to filter by."""
|
|
15
15
|
|
|
@@ -21,3 +21,9 @@ class AgeFilter(RapidataFilter):
|
|
|
21
21
|
_t="AgeFilter",
|
|
22
22
|
ageGroups=[age_group._to_backend_model() for age_group in self.age_groups],
|
|
23
23
|
)
|
|
24
|
+
|
|
25
|
+
def __str__(self) -> str:
|
|
26
|
+
return f"AgeFilter(age_groups={self.age_groups})"
|
|
27
|
+
|
|
28
|
+
def __repr__(self) -> str:
|
|
29
|
+
return f"AgeFilter(age_groups={self.age_groups!r})"
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
from rapidata.rapidata_client.filter._base_filter import RapidataFilter
|
|
3
3
|
from rapidata.api_client.models.and_user_filter_model import AndUserFilterModel
|
|
4
|
-
from rapidata.api_client.models.and_user_filter_model_filters_inner import
|
|
4
|
+
from rapidata.api_client.models.and_user_filter_model_filters_inner import (
|
|
5
|
+
AndUserFilterModelFiltersInner,
|
|
6
|
+
)
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
class AndFilter(RapidataFilter):
|
|
@@ -10,21 +12,34 @@ class AndFilter(RapidataFilter):
|
|
|
10
12
|
|
|
11
13
|
Args:
|
|
12
14
|
filters (list[RapidataFilter]): A list of filters to be combined with AND.
|
|
13
|
-
|
|
15
|
+
|
|
14
16
|
Example:
|
|
15
17
|
```python
|
|
16
18
|
from rapidata import AndFilter, LanguageFilter, CountryFilter
|
|
17
19
|
|
|
18
|
-
AndFilter([LanguageFilter(["en"]), CountryFilter(["US"])])
|
|
20
|
+
AndFilter([LanguageFilter(["en"]), CountryFilter(["US"])])
|
|
19
21
|
```
|
|
20
22
|
|
|
21
23
|
This will match users who have their phone set to English AND are located in the United States.
|
|
22
24
|
"""
|
|
25
|
+
|
|
23
26
|
def __init__(self, filters: list[RapidataFilter]):
|
|
24
27
|
if not all(isinstance(filter, RapidataFilter) for filter in filters):
|
|
25
28
|
raise ValueError("Filters must be a RapidataFilter object")
|
|
26
|
-
|
|
29
|
+
|
|
27
30
|
self.filters = filters
|
|
28
31
|
|
|
29
32
|
def _to_model(self):
|
|
30
|
-
return AndUserFilterModel(
|
|
33
|
+
return AndUserFilterModel(
|
|
34
|
+
_t="AndFilter",
|
|
35
|
+
filters=[
|
|
36
|
+
AndUserFilterModelFiltersInner(filter._to_model())
|
|
37
|
+
for filter in self.filters
|
|
38
|
+
],
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def __str__(self) -> str:
|
|
42
|
+
return f"AndFilter(filters={self.filters})"
|
|
43
|
+
|
|
44
|
+
def __repr__(self) -> str:
|
|
45
|
+
return f"AndFilter(filters={self.filters!r})"
|
|
@@ -11,7 +11,7 @@ class CampaignFilter(RapidataFilter):
|
|
|
11
11
|
Can be used to filter who to target based on campaign IDs.
|
|
12
12
|
|
|
13
13
|
This filter can only be used when directly in contact with Rapidata.
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
Args:
|
|
16
16
|
campaign_ids (list[str]): List of campaign IDs to filter by.
|
|
17
17
|
"""
|
|
@@ -24,3 +24,9 @@ class CampaignFilter(RapidataFilter):
|
|
|
24
24
|
_t="CampaignFilter",
|
|
25
25
|
campaignIds=self.campaign_ids,
|
|
26
26
|
)
|
|
27
|
+
|
|
28
|
+
def __str__(self) -> str:
|
|
29
|
+
return f"CampaignFilter(campaign_ids={self.campaign_ids})"
|
|
30
|
+
|
|
31
|
+
def __repr__(self) -> str:
|
|
32
|
+
return f"CampaignFilter(campaign_ids={self.campaign_ids!r})"
|
|
@@ -7,7 +7,7 @@ class CountryFilter(RapidataFilter):
|
|
|
7
7
|
"""CountryFilter Class
|
|
8
8
|
|
|
9
9
|
Can be used to filter who to target based on country codes.
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
Args:
|
|
12
12
|
country_codes (list[str]): List of country codes (capitalized) to filter by.
|
|
13
13
|
"""
|
|
@@ -16,7 +16,7 @@ class CountryFilter(RapidataFilter):
|
|
|
16
16
|
# check that all characters in the country codes are uppercase
|
|
17
17
|
if not isinstance(country_codes, list):
|
|
18
18
|
raise ValueError("Country codes must be a list")
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
if not all([code.isupper() for code in country_codes]):
|
|
21
21
|
raise ValueError("Country codes must be uppercase")
|
|
22
22
|
|
|
@@ -24,3 +24,9 @@ class CountryFilter(RapidataFilter):
|
|
|
24
24
|
|
|
25
25
|
def _to_model(self):
|
|
26
26
|
return CountryUserFilterModel(_t="CountryFilter", countries=self.country_codes)
|
|
27
|
+
|
|
28
|
+
def __str__(self) -> str:
|
|
29
|
+
return f"CountryFilter(country_codes={self.country_codes})"
|
|
30
|
+
|
|
31
|
+
def __repr__(self) -> str:
|
|
32
|
+
return f"CountryFilter(country_codes={self.country_codes!r})"
|
|
@@ -8,10 +8,10 @@ class CustomFilter(RapidataFilter):
|
|
|
8
8
|
|
|
9
9
|
Can be used to filter who to target based on custom filters.
|
|
10
10
|
|
|
11
|
-
Ought to be used with contact to Rapidata.
|
|
12
|
-
|
|
11
|
+
Ought to be used with contact to Rapidata.
|
|
12
|
+
|
|
13
13
|
Warning: If identifier does not exist, order will not get any responses.
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
Args:
|
|
16
16
|
identifier (str): Identifier of the custom filter.
|
|
17
17
|
values (list[str]): List of values to filter by.
|
|
@@ -27,3 +27,9 @@ class CustomFilter(RapidataFilter):
|
|
|
27
27
|
identifier=self.identifier,
|
|
28
28
|
values=self.values,
|
|
29
29
|
)
|
|
30
|
+
|
|
31
|
+
def __str__(self) -> str:
|
|
32
|
+
return f"CustomFilter(identifier={self.identifier}, values={self.values})"
|
|
33
|
+
|
|
34
|
+
def __repr__(self) -> str:
|
|
35
|
+
return f"CustomFilter(identifier={self.identifier!r}, values={self.values!r})"
|
|
@@ -6,10 +6,10 @@ from rapidata.rapidata_client.filter.models.gender import Gender
|
|
|
6
6
|
|
|
7
7
|
class GenderFilter(RapidataFilter):
|
|
8
8
|
"""GenderFilter Class
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
Can be used to filter who to target based on their gender.
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
|
|
12
|
+
|
|
13
13
|
Args:
|
|
14
14
|
genders (list[Gender]): List of genders to filter by."""
|
|
15
15
|
|
|
@@ -21,3 +21,9 @@ class GenderFilter(RapidataFilter):
|
|
|
21
21
|
_t="GenderFilter",
|
|
22
22
|
genders=[gender._to_backend_model() for gender in self.genders],
|
|
23
23
|
)
|
|
24
|
+
|
|
25
|
+
def __str__(self) -> str:
|
|
26
|
+
return f"GenderFilter(genders={self.genders})"
|
|
27
|
+
|
|
28
|
+
def __repr__(self) -> str:
|
|
29
|
+
return f"GenderFilter(genders={self.genders!r})"
|
|
@@ -7,26 +7,27 @@ from rapidata.api_client.models.language_user_filter_model import (
|
|
|
7
7
|
|
|
8
8
|
class LanguageFilter(RapidataFilter):
|
|
9
9
|
"""LanguageFilter Class
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
Can be used to filter who to target based on language codes.
|
|
12
12
|
|
|
13
13
|
Args:
|
|
14
14
|
language_codes (list[str]): List of language codes to filter by.
|
|
15
|
-
|
|
16
|
-
Example:
|
|
15
|
+
|
|
16
|
+
Example:
|
|
17
17
|
```python
|
|
18
18
|
LanguageFilter(["en", "de"])
|
|
19
19
|
```
|
|
20
20
|
This will limit the order to be shown to only people who have their phone set to english or german
|
|
21
21
|
"""
|
|
22
|
+
|
|
22
23
|
def __init__(self, language_codes: list[str]):
|
|
23
24
|
if not isinstance(language_codes, list):
|
|
24
25
|
raise ValueError("Language codes must be a list")
|
|
25
|
-
|
|
26
|
+
|
|
26
27
|
# check that all characters in the language codes are lowercase
|
|
27
28
|
if not all([code.islower() for code in language_codes]):
|
|
28
29
|
raise ValueError("Language codes must be lowercase")
|
|
29
|
-
|
|
30
|
+
|
|
30
31
|
for code in language_codes:
|
|
31
32
|
if not len(code) == 2:
|
|
32
33
|
raise ValueError("Language codes must be two characters long")
|
|
@@ -35,3 +36,9 @@ class LanguageFilter(RapidataFilter):
|
|
|
35
36
|
|
|
36
37
|
def _to_model(self):
|
|
37
38
|
return LanguageUserFilterModel(_t="LanguageFilter", languages=self.languages)
|
|
39
|
+
|
|
40
|
+
def __str__(self):
|
|
41
|
+
return f"LanguageFilter({self.languages})"
|
|
42
|
+
|
|
43
|
+
def __repr__(self):
|
|
44
|
+
return f"LanguageFilter({self.languages})"
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
from rapidata.rapidata_client.filter._base_filter import RapidataFilter
|
|
2
2
|
from rapidata.api_client.models.new_user_filter_model import NewUserFilterModel
|
|
3
3
|
|
|
4
|
+
|
|
4
5
|
class NewUserFilter(RapidataFilter):
|
|
5
6
|
"""NewUserFilter Class
|
|
6
|
-
|
|
7
|
+
|
|
7
8
|
Can be used to filter new users.
|
|
8
9
|
"""
|
|
9
10
|
|
|
10
11
|
def _to_model(self):
|
|
11
|
-
return NewUserFilterModel(
|
|
12
|
-
_t="NewUserFilter"
|
|
13
|
-
)
|
|
12
|
+
return NewUserFilterModel(_t="NewUserFilter")
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
from rapidata.rapidata_client.filter._base_filter import RapidataFilter
|
|
3
3
|
from rapidata.api_client.models.not_user_filter_model import NotUserFilterModel
|
|
4
|
-
from rapidata.api_client.models.and_user_filter_model_filters_inner import
|
|
4
|
+
from rapidata.api_client.models.and_user_filter_model_filters_inner import (
|
|
5
|
+
AndUserFilterModelFiltersInner,
|
|
6
|
+
)
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
class NotFilter(RapidataFilter):
|
|
@@ -10,21 +12,31 @@ class NotFilter(RapidataFilter):
|
|
|
10
12
|
|
|
11
13
|
Args:
|
|
12
14
|
filter (RapidataFilter): The filter whose condition should be negated.
|
|
13
|
-
|
|
15
|
+
|
|
14
16
|
Example:
|
|
15
17
|
```python
|
|
16
18
|
from rapidata import NotFilter, LanguageFilter
|
|
17
19
|
|
|
18
|
-
NotFilter(LanguageFilter(["en"]))
|
|
20
|
+
NotFilter(LanguageFilter(["en"]))
|
|
19
21
|
```
|
|
20
22
|
|
|
21
23
|
This will limit the order to be shown to only people who have their phone set to a language other than English.
|
|
22
24
|
"""
|
|
25
|
+
|
|
23
26
|
def __init__(self, filter: RapidataFilter):
|
|
24
27
|
if not isinstance(filter, RapidataFilter):
|
|
25
28
|
raise ValueError("Filter must be a RapidataFilter object")
|
|
26
|
-
|
|
29
|
+
|
|
27
30
|
self.filter = filter
|
|
28
31
|
|
|
29
32
|
def _to_model(self):
|
|
30
|
-
return NotUserFilterModel(
|
|
33
|
+
return NotUserFilterModel(
|
|
34
|
+
_t="NotFilter",
|
|
35
|
+
filter=AndUserFilterModelFiltersInner(self.filter._to_model()),
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def __str__(self) -> str:
|
|
39
|
+
return f"NotFilter(filter={self.filter})"
|
|
40
|
+
|
|
41
|
+
def __repr__(self) -> str:
|
|
42
|
+
return f"NotFilter(filter={self.filter!r})"
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
from rapidata.rapidata_client.filter._base_filter import RapidataFilter
|
|
3
3
|
from rapidata.api_client.models.or_user_filter_model import OrUserFilterModel
|
|
4
|
-
from rapidata.api_client.models.and_user_filter_model_filters_inner import
|
|
4
|
+
from rapidata.api_client.models.and_user_filter_model_filters_inner import (
|
|
5
|
+
AndUserFilterModelFiltersInner,
|
|
6
|
+
)
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
class OrFilter(RapidataFilter):
|
|
@@ -10,21 +12,34 @@ class OrFilter(RapidataFilter):
|
|
|
10
12
|
|
|
11
13
|
Args:
|
|
12
14
|
filters (list[RapidataFilter]): A list of filters to be combined with OR.
|
|
13
|
-
|
|
15
|
+
|
|
14
16
|
Example:
|
|
15
17
|
```python
|
|
16
18
|
from rapidata import OrFilter, LanguageFilter, CountryFilter
|
|
17
19
|
|
|
18
|
-
OrFilter([LanguageFilter(["en"]), CountryFilter(["US"])])
|
|
20
|
+
OrFilter([LanguageFilter(["en"]), CountryFilter(["US"])])
|
|
19
21
|
```
|
|
20
22
|
|
|
21
23
|
This will match users who either have their phone set to English OR are located in the United States.
|
|
22
24
|
"""
|
|
25
|
+
|
|
23
26
|
def __init__(self, filters: list[RapidataFilter]):
|
|
24
27
|
if not all(isinstance(filter, RapidataFilter) for filter in filters):
|
|
25
28
|
raise ValueError("Filters must be a RapidataFilter object")
|
|
26
|
-
|
|
29
|
+
|
|
27
30
|
self.filters = filters
|
|
28
31
|
|
|
29
32
|
def _to_model(self):
|
|
30
|
-
return OrUserFilterModel(
|
|
33
|
+
return OrUserFilterModel(
|
|
34
|
+
_t="OrFilter",
|
|
35
|
+
filters=[
|
|
36
|
+
AndUserFilterModelFiltersInner(filter._to_model())
|
|
37
|
+
for filter in self.filters
|
|
38
|
+
],
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def __str__(self) -> str:
|
|
42
|
+
return f"OrFilter(filters={self.filters})"
|
|
43
|
+
|
|
44
|
+
def __repr__(self) -> str:
|
|
45
|
+
return f"OrFilter(filters={self.filters!r})"
|
|
@@ -49,3 +49,9 @@ class ResponseCountFilter(RapidataFilter):
|
|
|
49
49
|
dimension=self.dimension,
|
|
50
50
|
operator=self.operator,
|
|
51
51
|
)
|
|
52
|
+
|
|
53
|
+
def __str__(self) -> str:
|
|
54
|
+
return f"ResponseCountFilter(response_count={self.response_count}, dimension={self.dimension}, operator={self.operator})"
|
|
55
|
+
|
|
56
|
+
def __repr__(self) -> str:
|
|
57
|
+
return f"ResponseCountFilter(response_count={self.response_count!r}, dimension={self.dimension!r}, operator={self.operator!r})"
|
|
@@ -7,28 +7,34 @@ from rapidata.api_client.models.user_score_user_filter_model import (
|
|
|
7
7
|
|
|
8
8
|
class UserScoreFilter(RapidataFilter):
|
|
9
9
|
"""UserScoreFilter Class
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
Can be used to filter who to target based on their user score.
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
Args:
|
|
14
14
|
lower_bound (float): The lower bound of the user score.
|
|
15
15
|
upper_bound (float): The upper bound of the user score.
|
|
16
16
|
dimension (str): The dimension of the userScore to be considerd for the filter.
|
|
17
17
|
|
|
18
|
-
Example:
|
|
18
|
+
Example:
|
|
19
19
|
```python
|
|
20
20
|
UserScoreFilter(0.5, 0.9)
|
|
21
21
|
```
|
|
22
22
|
This will only show the order to users that have a UserScore of >=0.5 and <=0.9
|
|
23
23
|
"""
|
|
24
|
-
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
lower_bound: float = 0.0,
|
|
28
|
+
upper_bound: float = 1.0,
|
|
29
|
+
dimension: str | None = None,
|
|
30
|
+
):
|
|
25
31
|
if lower_bound < 0 or lower_bound > 1:
|
|
26
32
|
raise ValueError("The lower bound must be between 0 and 1.")
|
|
27
33
|
if upper_bound < 0 or upper_bound > 1:
|
|
28
34
|
raise ValueError("The upper bound must be between 0 and 1.")
|
|
29
35
|
if lower_bound >= upper_bound:
|
|
30
36
|
raise ValueError("The lower bound must be less than the upper bound.")
|
|
31
|
-
|
|
37
|
+
|
|
32
38
|
self.upper_bound = upper_bound
|
|
33
39
|
self.lower_bound = lower_bound
|
|
34
40
|
self.dimension = dimension
|
|
@@ -40,3 +46,9 @@ class UserScoreFilter(RapidataFilter):
|
|
|
40
46
|
lowerbound=self.lower_bound,
|
|
41
47
|
dimension=self.dimension,
|
|
42
48
|
)
|
|
49
|
+
|
|
50
|
+
def __str__(self) -> str:
|
|
51
|
+
return f"UserScoreFilter(lower_bound={self.lower_bound}, upper_bound={self.upper_bound}, dimension={self.dimension})"
|
|
52
|
+
|
|
53
|
+
def __repr__(self) -> str:
|
|
54
|
+
return f"UserScoreFilter(lower_bound={self.lower_bound!r}, upper_bound={self.upper_bound!r}, dimension={self.dimension!r})"
|
|
@@ -6,18 +6,17 @@ from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
|
6
6
|
from tqdm import tqdm
|
|
7
7
|
|
|
8
8
|
from typing import Generator
|
|
9
|
-
from rapidata.rapidata_client.
|
|
10
|
-
logger,
|
|
11
|
-
managed_print,
|
|
12
|
-
RapidataOutputManager,
|
|
13
|
-
)
|
|
9
|
+
from rapidata.rapidata_client.config import logger, managed_print
|
|
14
10
|
import time
|
|
15
11
|
import threading
|
|
16
|
-
from rapidata.rapidata_client.api.
|
|
12
|
+
from rapidata.rapidata_client.api.rapidata_api_client import (
|
|
17
13
|
suppress_rapidata_error_logging,
|
|
18
14
|
)
|
|
19
15
|
from rapidata.rapidata_client.config.rapidata_config import rapidata_config
|
|
20
16
|
|
|
17
|
+
# Add OpenTelemetry context imports for thread propagation
|
|
18
|
+
from opentelemetry import context as otel_context
|
|
19
|
+
|
|
21
20
|
|
|
22
21
|
def chunk_list(lst: list, chunk_size: int) -> Generator:
|
|
23
22
|
for i in range(0, len(lst), chunk_size):
|
|
@@ -62,22 +61,37 @@ class RapidataDataset:
|
|
|
62
61
|
)
|
|
63
62
|
return datapoint
|
|
64
63
|
|
|
64
|
+
def upload_with_context(
|
|
65
|
+
context: otel_context.Context, datapoint: Datapoint, index: int
|
|
66
|
+
) -> Datapoint:
|
|
67
|
+
"""Wrapper function that runs upload_text_datapoint with the provided context."""
|
|
68
|
+
token = otel_context.attach(context)
|
|
69
|
+
try:
|
|
70
|
+
return upload_text_datapoint(datapoint, index)
|
|
71
|
+
finally:
|
|
72
|
+
otel_context.detach(token)
|
|
73
|
+
|
|
65
74
|
successful_uploads: list[Datapoint] = []
|
|
66
75
|
failed_uploads: list[Datapoint] = []
|
|
67
76
|
|
|
77
|
+
# Capture the current OpenTelemetry context before creating threads
|
|
78
|
+
current_context = otel_context.get_current()
|
|
79
|
+
|
|
68
80
|
total_uploads = len(datapoints)
|
|
69
81
|
with ThreadPoolExecutor(
|
|
70
|
-
max_workers=rapidata_config.
|
|
82
|
+
max_workers=rapidata_config.upload.maxWorkers
|
|
71
83
|
) as executor:
|
|
72
84
|
future_to_datapoint = {
|
|
73
|
-
executor.submit(
|
|
85
|
+
executor.submit(
|
|
86
|
+
upload_with_context, current_context, datapoint, i
|
|
87
|
+
): datapoint
|
|
74
88
|
for i, datapoint in enumerate(datapoints)
|
|
75
89
|
}
|
|
76
90
|
|
|
77
91
|
with tqdm(
|
|
78
92
|
total=total_uploads,
|
|
79
93
|
desc="Uploading text datapoints",
|
|
80
|
-
disable=
|
|
94
|
+
disable=rapidata_config.logging.silent_mode,
|
|
81
95
|
) as pbar:
|
|
82
96
|
for future in as_completed(future_to_datapoint.keys()):
|
|
83
97
|
datapoint = future_to_datapoint[future]
|
|
@@ -119,7 +133,7 @@ class RapidataDataset:
|
|
|
119
133
|
urls = datapoint.get_urls()
|
|
120
134
|
|
|
121
135
|
last_exception = None
|
|
122
|
-
for attempt in range(rapidata_config.
|
|
136
|
+
for attempt in range(rapidata_config.upload.maxRetries):
|
|
123
137
|
try:
|
|
124
138
|
with suppress_rapidata_error_logging():
|
|
125
139
|
self.openapi_service.dataset_api.dataset_dataset_id_datapoints_post(
|
|
@@ -136,7 +150,7 @@ class RapidataDataset:
|
|
|
136
150
|
|
|
137
151
|
except Exception as e:
|
|
138
152
|
last_exception = e
|
|
139
|
-
if attempt < rapidata_config.
|
|
153
|
+
if attempt < rapidata_config.upload.maxRetries - 1:
|
|
140
154
|
# Exponential backoff: wait 1s, then 2s, then 4s
|
|
141
155
|
retry_delay = 2**attempt
|
|
142
156
|
time.sleep(retry_delay)
|
|
@@ -144,13 +158,13 @@ class RapidataDataset:
|
|
|
144
158
|
logger.debug(
|
|
145
159
|
"Retrying %s of %s...",
|
|
146
160
|
attempt + 1,
|
|
147
|
-
rapidata_config.
|
|
161
|
+
rapidata_config.upload.maxRetries,
|
|
148
162
|
)
|
|
149
163
|
|
|
150
164
|
# If we get here, all retries failed
|
|
151
165
|
local_failed.append(datapoint)
|
|
152
166
|
tqdm.write(
|
|
153
|
-
f"Upload failed for {datapoint} after {rapidata_config.
|
|
167
|
+
f"Upload failed for {datapoint} after {rapidata_config.upload.maxRetries} attempts. \nFinal error: \n{str(last_exception)}"
|
|
154
168
|
)
|
|
155
169
|
|
|
156
170
|
return local_successful, local_failed
|
|
@@ -183,7 +197,7 @@ class RapidataDataset:
|
|
|
183
197
|
with tqdm(
|
|
184
198
|
total=total_uploads,
|
|
185
199
|
desc="Uploading datapoints",
|
|
186
|
-
disable=
|
|
200
|
+
disable=rapidata_config.logging.silent_mode,
|
|
187
201
|
) as pbar:
|
|
188
202
|
prev_ready = 0
|
|
189
203
|
prev_failed = 0
|
|
@@ -291,17 +305,31 @@ class RapidataDataset:
|
|
|
291
305
|
successful_uploads: list[Datapoint] = []
|
|
292
306
|
failed_uploads: list[Datapoint] = []
|
|
293
307
|
|
|
308
|
+
def process_upload_with_context(
|
|
309
|
+
context: otel_context.Context, datapoint: Datapoint, index: int
|
|
310
|
+
) -> tuple[list[Datapoint], list[Datapoint]]:
|
|
311
|
+
"""Wrapper function that runs _process_single_upload with the provided context."""
|
|
312
|
+
token = otel_context.attach(context)
|
|
313
|
+
try:
|
|
314
|
+
return self._process_single_upload(datapoint, index)
|
|
315
|
+
finally:
|
|
316
|
+
otel_context.detach(token)
|
|
317
|
+
|
|
318
|
+
# Capture the current OpenTelemetry context before creating threads
|
|
319
|
+
current_context = otel_context.get_current()
|
|
320
|
+
|
|
294
321
|
try:
|
|
295
322
|
with ThreadPoolExecutor(
|
|
296
|
-
max_workers=rapidata_config.
|
|
323
|
+
max_workers=rapidata_config.upload.maxWorkers
|
|
297
324
|
) as executor:
|
|
298
325
|
# Process uploads in chunks to avoid overwhelming the system
|
|
299
326
|
for chunk_idx, chunk in enumerate(chunk_list(datapoints, chunk_size)):
|
|
300
327
|
futures = [
|
|
301
328
|
executor.submit(
|
|
302
|
-
|
|
329
|
+
process_upload_with_context,
|
|
330
|
+
current_context,
|
|
303
331
|
datapoint,
|
|
304
|
-
|
|
332
|
+
chunk_idx * chunk_size + i,
|
|
305
333
|
)
|
|
306
334
|
for i, datapoint in enumerate(chunk)
|
|
307
335
|
]
|