fiddler-client 3.8.3__tar.gz → 3.9.1__tar.gz
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.
- {fiddler-client-3.8.3/fiddler_client.egg-info → fiddler-client-3.9.1}/PKG-INFO +1 -1
- fiddler-client-3.9.1/fiddler/VERSION +1 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/entities/webhook.py +2 -2
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/webhook.py +3 -1
- fiddler-client-3.9.1/fiddler/tests/test_utils.py +431 -0
- fiddler-client-3.9.1/fiddler/utils/column_generator.py +68 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/utils/model_generator.py +1 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1/fiddler_client.egg-info}/PKG-INFO +1 -1
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler_client.egg-info/SOURCES.txt +1 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler_client.egg-info/requires.txt +2 -2
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/setup.py +2 -2
- fiddler-client-3.8.3/fiddler/VERSION +0 -1
- fiddler-client-3.8.3/fiddler/tests/test_utils.py +0 -99
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/LICENSE.txt +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/MANIFEST.in +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/PUBLIC.md +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/README.md +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/__init__.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/configs.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/connection.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/constants/__init__.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/constants/alert_rule.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/constants/baseline.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/constants/common.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/constants/dataset.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/constants/events.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/constants/job.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/constants/model.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/constants/model_deployment.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/constants/xai.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/decorators.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/entities/__init__.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/entities/alert_record.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/entities/alert_rule.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/entities/base.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/entities/baseline.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/entities/custom_expression.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/entities/dataset.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/entities/events.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/entities/file.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/entities/job.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/entities/model.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/entities/model_artifact.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/entities/model_deployment.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/entities/organization.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/entities/project.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/entities/surrogate.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/entities/user.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/entities/xai.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/exceptions.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/libs/__init__.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/libs/aws.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/libs/http_client.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/libs/json_encoder.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/libs/semver.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/packtools/__init__.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/packtools/gem.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/packtools/keras_ig_helpers.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/packtools/project_attributions_helpers.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/packtools/template_model.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/__init__.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/alert_record.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/alert_rule.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/base.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/baseline.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/custom_expression.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/custom_features.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/dataset.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/events.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/file.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/filter_query.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/job.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/model.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/model_deployment.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/model_schema.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/model_spec.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/model_task_params.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/organization.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/project.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/response.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/server_info.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/user.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/xai.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/schemas/xai_params.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/__init__.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/apis/__init__.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/apis/test_alert_record.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/apis/test_alert_rule.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/apis/test_baseline.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/apis/test_custom_metric.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/apis/test_dataset.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/apis/test_events.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/apis/test_files.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/apis/test_generate_model.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/apis/test_job.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/apis/test_mixin.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/apis/test_model.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/apis/test_model_artifact.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/apis/test_model_deployment.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/apis/test_model_surrogate.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/apis/test_project.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/apis/test_segment.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/apis/test_webhook.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/apis/test_xai.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/conftest.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/constants.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/test_connection.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/test_json_encoder.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/test_logger.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/test_sagemaker_auth.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/tests/utils.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/utils/__init__.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/utils/decorators.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/utils/helpers.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/utils/logger.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/utils/validations.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/utils/version.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/version.py +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler_client.egg-info/dependency_links.txt +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler_client.egg-info/top_level.txt +0 -0
- {fiddler-client-3.8.3 → fiddler-client-3.9.1}/setup.cfg +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.9.1
|
|
@@ -20,7 +20,7 @@ class Webhook(BaseEntity):
|
|
|
20
20
|
"""
|
|
21
21
|
self.name = name
|
|
22
22
|
self.url = url
|
|
23
|
-
# provider is 'SLACK'
|
|
23
|
+
# provider is 'SLACK', 'MS_TEAMS' as of May 2025.
|
|
24
24
|
self.provider = provider
|
|
25
25
|
|
|
26
26
|
self.id: UUID | None = None
|
|
@@ -113,7 +113,7 @@ class Webhook(BaseEntity):
|
|
|
113
113
|
|
|
114
114
|
:params name: name of webhook
|
|
115
115
|
:params url: webhook url
|
|
116
|
-
:params provider: Either 'SLACK' or '
|
|
116
|
+
:params provider: Either 'SLACK' or 'MS_TEAMS'
|
|
117
117
|
|
|
118
118
|
:returns: Created `Webhook` object.
|
|
119
119
|
"""
|
|
@@ -9,8 +9,10 @@ from fiddler.schemas.base import BaseModel
|
|
|
9
9
|
|
|
10
10
|
@enum.unique
|
|
11
11
|
class WebhookProvider(str, enum.Enum):
|
|
12
|
-
# provider is 'SLACK' or '
|
|
12
|
+
# provider is 'SLACK' or 'MS_TEAMS' as of May 2025.
|
|
13
|
+
# keeping OTHER in enum for existing webhooks for backwards compatibility
|
|
13
14
|
SLACK = 'SLACK'
|
|
15
|
+
MS_TEAMS = 'MS_TEAMS'
|
|
14
16
|
OTHER = 'OTHER'
|
|
15
17
|
|
|
16
18
|
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import tempfile
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import numpy as np
|
|
5
|
+
import pandas as pd
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
from fiddler.constants.model import DataType
|
|
9
|
+
from fiddler.schemas.server_info import Version
|
|
10
|
+
from fiddler.utils.helpers import group_by, try_series_retype
|
|
11
|
+
from fiddler.utils.column_generator import create_columns_from_df
|
|
12
|
+
from fiddler.utils.validations import validate_artifact_dir
|
|
13
|
+
from fiddler.utils.version import match_semver
|
|
14
|
+
|
|
15
|
+
MODEL_DATA = [{'Unnamed: 0': 43660,
|
|
16
|
+
'CreditScore': 681,
|
|
17
|
+
'Geography': 'France',
|
|
18
|
+
'Gender': 'Female',
|
|
19
|
+
'Age': 45,
|
|
20
|
+
'Tenure': 4,
|
|
21
|
+
'Balance': 150461.78248572032,
|
|
22
|
+
'NumOfProducts': 1,
|
|
23
|
+
'HasCrCard': True,
|
|
24
|
+
'IsActiveMember': True,
|
|
25
|
+
'EstimatedSalary': 121476.50483532489,
|
|
26
|
+
'Churned': 'Not Churned',
|
|
27
|
+
'probability_churned': 0.2070909278091097},
|
|
28
|
+
{'Unnamed: 0': 87278,
|
|
29
|
+
'CreditScore': 604,
|
|
30
|
+
'Geography': 'Spain',
|
|
31
|
+
'Gender': 'Male',
|
|
32
|
+
'Age': 25,
|
|
33
|
+
'Tenure': 8,
|
|
34
|
+
'Balance': 870.563948633173,
|
|
35
|
+
'NumOfProducts': 2,
|
|
36
|
+
'HasCrCard': False,
|
|
37
|
+
'IsActiveMember': True,
|
|
38
|
+
'EstimatedSalary': 39030.86584360056,
|
|
39
|
+
'Churned': 'Not Churned',
|
|
40
|
+
'probability_churned': 0.0619905773329336},
|
|
41
|
+
{'Unnamed: 0': 14317,
|
|
42
|
+
'CreditScore': 648,
|
|
43
|
+
'Geography': 'France',
|
|
44
|
+
'Gender': 'Female',
|
|
45
|
+
'Age': 50,
|
|
46
|
+
'Tenure': 6,
|
|
47
|
+
'Balance': 127661.4013780268,
|
|
48
|
+
'NumOfProducts': 1,
|
|
49
|
+
'HasCrCard': True,
|
|
50
|
+
'IsActiveMember': True,
|
|
51
|
+
'EstimatedSalary': -8216.031548157727,
|
|
52
|
+
'Churned': 'Churned',
|
|
53
|
+
'probability_churned': 0.1026814066436183},
|
|
54
|
+
{'Unnamed: 0': 81932,
|
|
55
|
+
'CreditScore': 670,
|
|
56
|
+
'Geography': 'France',
|
|
57
|
+
'Gender': 'Male',
|
|
58
|
+
'Age': 49,
|
|
59
|
+
'Tenure': 7,
|
|
60
|
+
'Balance': 95199.48061342211,
|
|
61
|
+
'NumOfProducts': 3,
|
|
62
|
+
'HasCrCard': False,
|
|
63
|
+
'IsActiveMember': True,
|
|
64
|
+
'EstimatedSalary': 47114.97249302002,
|
|
65
|
+
'Churned': 'Not Churned',
|
|
66
|
+
'probability_churned': 0.2134035806234498},
|
|
67
|
+
{'Unnamed: 0': 95321,
|
|
68
|
+
'CreditScore': 616,
|
|
69
|
+
'Geography': 'Germany',
|
|
70
|
+
'Gender': 'Female',
|
|
71
|
+
'Age': 35,
|
|
72
|
+
'Tenure': 1,
|
|
73
|
+
'Balance': 88151.28675933508,
|
|
74
|
+
'NumOfProducts': 1,
|
|
75
|
+
'HasCrCard': True,
|
|
76
|
+
'IsActiveMember': False,
|
|
77
|
+
'EstimatedSalary': 107882.06957422369,
|
|
78
|
+
'Churned': 'Churned',
|
|
79
|
+
'probability_churned': 0.8824657828379177},
|
|
80
|
+
{'Unnamed: 0': 5405,
|
|
81
|
+
'CreditScore': 536,
|
|
82
|
+
'Geography': 'France',
|
|
83
|
+
'Gender': 'Female',
|
|
84
|
+
'Age': 41,
|
|
85
|
+
'Tenure': 4,
|
|
86
|
+
'Balance': 167680.40434914205,
|
|
87
|
+
'NumOfProducts': 1,
|
|
88
|
+
'HasCrCard': True,
|
|
89
|
+
'IsActiveMember': True,
|
|
90
|
+
'EstimatedSalary': 133588.33926550962,
|
|
91
|
+
'Churned': 'Not Churned',
|
|
92
|
+
'probability_churned': 0.1189636863349831},
|
|
93
|
+
{'Unnamed: 0': 33188,
|
|
94
|
+
'CreditScore': 666,
|
|
95
|
+
'Geography': 'Spain',
|
|
96
|
+
'Gender': 'Male',
|
|
97
|
+
'Age': 34,
|
|
98
|
+
'Tenure': 2,
|
|
99
|
+
'Balance': 120370.38776657668,
|
|
100
|
+
'NumOfProducts': 2,
|
|
101
|
+
'HasCrCard': False,
|
|
102
|
+
'IsActiveMember': True,
|
|
103
|
+
'EstimatedSalary': 60070.356958972116,
|
|
104
|
+
'Churned': 'Not Churned',
|
|
105
|
+
'probability_churned': 0.1244325159224678},
|
|
106
|
+
{'Unnamed: 0': 63421,
|
|
107
|
+
'CreditScore': 613,
|
|
108
|
+
'Geography': 'France',
|
|
109
|
+
'Gender': 'Male',
|
|
110
|
+
'Age': 35,
|
|
111
|
+
'Tenure': 2,
|
|
112
|
+
'Balance': 1632.9882268964022,
|
|
113
|
+
'NumOfProducts': 2,
|
|
114
|
+
'HasCrCard': True,
|
|
115
|
+
'IsActiveMember': True,
|
|
116
|
+
'EstimatedSalary': 77206.59807746019,
|
|
117
|
+
'Churned': 'Not Churned',
|
|
118
|
+
'probability_churned': 0.1037151191218035},
|
|
119
|
+
{'Unnamed: 0': 72897,
|
|
120
|
+
'CreditScore': 591,
|
|
121
|
+
'Geography': 'Germany',
|
|
122
|
+
'Gender': 'Male',
|
|
123
|
+
'Age': 85,
|
|
124
|
+
'Tenure': 4,
|
|
125
|
+
'Balance': 115817.11190439922,
|
|
126
|
+
'NumOfProducts': 1,
|
|
127
|
+
'HasCrCard': False,
|
|
128
|
+
'IsActiveMember': False,
|
|
129
|
+
'EstimatedSalary': 23310.677701467852,
|
|
130
|
+
'Churned': 'Not Churned',
|
|
131
|
+
'probability_churned': 0.2658220429852892},
|
|
132
|
+
{'Unnamed: 0': 9507,
|
|
133
|
+
'CreditScore': 488,
|
|
134
|
+
'Geography': 'Spain',
|
|
135
|
+
'Gender': 'Female',
|
|
136
|
+
'Age': 40,
|
|
137
|
+
'Tenure': 8,
|
|
138
|
+
'Balance': 101678.5269411524,
|
|
139
|
+
'NumOfProducts': 1,
|
|
140
|
+
'HasCrCard': True,
|
|
141
|
+
'IsActiveMember': False,
|
|
142
|
+
'EstimatedSalary': 9013.186551877934,
|
|
143
|
+
'Churned': 'Not Churned',
|
|
144
|
+
'probability_churned': 0.1167422545893403}
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
def test_match_semvar_version() -> None:
|
|
148
|
+
assert match_semver(None, '>=22.9.0') is False
|
|
149
|
+
assert match_semver(Version.parse('22.9.0'), '>=22.10.0') is False
|
|
150
|
+
assert match_semver(Version.parse('22.10.0'), '>=22.10.0') is True
|
|
151
|
+
assert match_semver(Version.parse('22.10.0'), '>22.10.0') is False
|
|
152
|
+
assert match_semver(Version.parse('22.11.0'), '>=22.10.0') is True
|
|
153
|
+
assert match_semver(Version.parse('22.11.0'), '>22.10.0') is True
|
|
154
|
+
assert match_semver(Version.parse('22.10.0'), '<=22.10.0') is True
|
|
155
|
+
assert match_semver(Version.parse('22.10.0'), '<22.10.0') is False
|
|
156
|
+
assert match_semver(Version.parse('22.9.0'), '<22.10.0') is True
|
|
157
|
+
assert match_semver(Version.parse('22.11.0-RC1'), '>=22.11.0') is True
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def test_validate_artifact_dir(tmp_path) -> None:
|
|
161
|
+
artifact_dir = os.path.join(Path(__file__).resolve().parent, 'artifact_test_dir')
|
|
162
|
+
assert validate_artifact_dir(Path(artifact_dir)) is None
|
|
163
|
+
# Test for artifact_dir not valid directory
|
|
164
|
+
with pytest.raises(ValueError):
|
|
165
|
+
validate_artifact_dir(Path('test'))
|
|
166
|
+
# Test for package.py file not found
|
|
167
|
+
mock_dir = tmp_path / 'test'
|
|
168
|
+
mock_dir.mkdir()
|
|
169
|
+
with pytest.raises(ValueError):
|
|
170
|
+
validate_artifact_dir(Path(mock_dir))
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def test_group_by_helper() -> None:
|
|
174
|
+
df = pd.DataFrame(
|
|
175
|
+
[
|
|
176
|
+
{'col1': 1, 'col2': 'foo'},
|
|
177
|
+
{'col1': 2, 'col2': 'bar'},
|
|
178
|
+
{'col1': 3, 'col2': 'baz'},
|
|
179
|
+
{'col1': 3, 'col2': 'foo'},
|
|
180
|
+
]
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
# with output_path
|
|
184
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
185
|
+
file_path = Path(temp_dir) / 'data.csv'
|
|
186
|
+
|
|
187
|
+
assert file_path.exists() is False
|
|
188
|
+
group_by(df=df, group_by_col='col2', output_path=file_path)
|
|
189
|
+
assert file_path.exists() is True
|
|
190
|
+
|
|
191
|
+
# without output path
|
|
192
|
+
grouped_df = group_by(df=df, group_by_col='col2')
|
|
193
|
+
assert grouped_df.equals(
|
|
194
|
+
pd.DataFrame(
|
|
195
|
+
[
|
|
196
|
+
{'col2': 'foo', 'col1': [1, 3]},
|
|
197
|
+
{'col2': 'bar', 'col1': [2]},
|
|
198
|
+
{'col2': 'baz', 'col1': [3]},
|
|
199
|
+
]
|
|
200
|
+
)
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def test_try_series_retype() -> None:
|
|
205
|
+
series = pd.Series([1, 2, 3], dtype='float')
|
|
206
|
+
series = try_series_retype(series, 'int')
|
|
207
|
+
assert series.dtype == 'int'
|
|
208
|
+
|
|
209
|
+
series = pd.Series([1, 2, None])
|
|
210
|
+
series = try_series_retype(series, 'int')
|
|
211
|
+
assert series.dtype == 'float'
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def test_try_series_retype_str_or_unkown() -> None:
|
|
215
|
+
series = pd.Series(['HIGH', 'MEDIUM', '', None], dtype='str')
|
|
216
|
+
series = try_series_retype(series, 'str')
|
|
217
|
+
assert series.dtype == 'object'
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def test_try_series_retype_timestamp() -> None:
|
|
221
|
+
series = pd.Series(
|
|
222
|
+
['2023-11-12 09:15:32.23', '2023-12-11 09:15:32.45'], dtype='str'
|
|
223
|
+
)
|
|
224
|
+
series = try_series_retype(series, 'timestamp')
|
|
225
|
+
assert series.dtype == 'datetime64[ns]'
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def test_try_series_retype_timestamp_error() -> None:
|
|
229
|
+
series = pd.Series(['2023-11-12 09:15:32.23', None], dtype='str')
|
|
230
|
+
|
|
231
|
+
with pytest.raises(TypeError):
|
|
232
|
+
try_series_retype(series, 'timestamp')
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def test_create_columns_from_df() -> None:
|
|
236
|
+
# test with an empty dataframe
|
|
237
|
+
df = pd.DataFrame()
|
|
238
|
+
with pytest.raises(ValueError):
|
|
239
|
+
create_columns_from_df(df)
|
|
240
|
+
|
|
241
|
+
# test with a dataframe from dictionary
|
|
242
|
+
df = pd.DataFrame(MODEL_DATA)
|
|
243
|
+
|
|
244
|
+
df['Gender'] = df['Gender'].astype('category')
|
|
245
|
+
df['Churned'] = df['Churned'].astype('category')
|
|
246
|
+
|
|
247
|
+
model_schema = create_columns_from_df(df)
|
|
248
|
+
columns = model_schema.columns
|
|
249
|
+
assert len(columns) == 13
|
|
250
|
+
assert columns[0].name == 'Unnamed: 0'
|
|
251
|
+
assert columns[0].data_type == DataType.INTEGER
|
|
252
|
+
|
|
253
|
+
assert columns[1].name == 'CreditScore'
|
|
254
|
+
assert columns[1].data_type == DataType.INTEGER
|
|
255
|
+
|
|
256
|
+
assert columns[2].name == 'Geography'
|
|
257
|
+
assert columns[2].data_type == DataType.STRING
|
|
258
|
+
|
|
259
|
+
assert columns[3].name == 'Gender'
|
|
260
|
+
assert columns[3].data_type == DataType.CATEGORY
|
|
261
|
+
|
|
262
|
+
assert columns[4].name == 'Age'
|
|
263
|
+
assert columns[4].data_type == DataType.INTEGER
|
|
264
|
+
|
|
265
|
+
assert columns[5].name == 'Tenure'
|
|
266
|
+
assert columns[5].data_type == DataType.INTEGER
|
|
267
|
+
|
|
268
|
+
assert columns[6].name == 'Balance'
|
|
269
|
+
assert columns[6].data_type == DataType.FLOAT
|
|
270
|
+
|
|
271
|
+
assert columns[7].name == 'NumOfProducts'
|
|
272
|
+
assert columns[7].data_type == DataType.INTEGER
|
|
273
|
+
|
|
274
|
+
assert columns[8].name == 'HasCrCard'
|
|
275
|
+
assert columns[8].data_type == DataType.BOOLEAN
|
|
276
|
+
|
|
277
|
+
assert columns[9].name == 'IsActiveMember'
|
|
278
|
+
assert columns[9].data_type == DataType.BOOLEAN
|
|
279
|
+
|
|
280
|
+
assert columns[10].name == 'EstimatedSalary'
|
|
281
|
+
assert columns[10].data_type == DataType.FLOAT
|
|
282
|
+
|
|
283
|
+
assert columns[11].name == 'Churned'
|
|
284
|
+
assert columns[11].data_type == DataType.CATEGORY
|
|
285
|
+
|
|
286
|
+
assert columns[12].name == 'probability_churned'
|
|
287
|
+
assert columns[12].data_type == DataType.FLOAT
|
|
288
|
+
|
|
289
|
+
def test_numeric_type_casting():
|
|
290
|
+
# Create a DataFrame with various integer types
|
|
291
|
+
df = pd.DataFrame({
|
|
292
|
+
'int8_col': pd.Series([1, 2, 3], dtype='int8'),
|
|
293
|
+
'int16_col': pd.Series([1000, 2000, 3000], dtype='int16'),
|
|
294
|
+
'int32_col': pd.Series([100000, 200000, 300000], dtype='int32'),
|
|
295
|
+
'int64_col': pd.Series([10000000000, 20000000000, 30000000000], dtype='int64'),
|
|
296
|
+
'uint8_col': pd.Series([1, 2, 3], dtype='uint8'),
|
|
297
|
+
'uint16_col': pd.Series([1000, 2000, 3000], dtype='uint16'),
|
|
298
|
+
'uint32_col': pd.Series([100000, 200000, 300000], dtype='uint32'),
|
|
299
|
+
'uint64_col': pd.Series([10000000000, 20000000000, 30000000000], dtype='uint64'),
|
|
300
|
+
|
|
301
|
+
# Float types
|
|
302
|
+
'float16_col': pd.Series([1.0, 2.0, 3.0], dtype='float16'),
|
|
303
|
+
'float32_col': pd.Series([1.234, 2.345, 3.456], dtype='float32'),
|
|
304
|
+
'float64_col': pd.Series([1.23456789, 2.34567890, 3.45678901], dtype='float64'),
|
|
305
|
+
|
|
306
|
+
# Control columns
|
|
307
|
+
'string_col': pd.Series(['1', '2', '3'], dtype='string'),
|
|
308
|
+
'bool_col': pd.Series([True, False, True], dtype='bool')
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
# Generate columns from DataFrame
|
|
312
|
+
columns = create_columns_from_df(df).columns
|
|
313
|
+
|
|
314
|
+
# Create a mapping of column names to their expected data types
|
|
315
|
+
expected_types = {
|
|
316
|
+
'int8_col': DataType.INTEGER,
|
|
317
|
+
'int16_col': DataType.INTEGER,
|
|
318
|
+
'int32_col': DataType.INTEGER,
|
|
319
|
+
'int64_col': DataType.INTEGER,
|
|
320
|
+
'uint8_col': DataType.INTEGER,
|
|
321
|
+
'uint16_col': DataType.INTEGER,
|
|
322
|
+
'uint32_col': DataType.INTEGER,
|
|
323
|
+
'uint64_col': DataType.INTEGER,
|
|
324
|
+
|
|
325
|
+
# Float columns
|
|
326
|
+
'float16_col': DataType.FLOAT,
|
|
327
|
+
'float32_col': DataType.FLOAT,
|
|
328
|
+
'float64_col': DataType.FLOAT,
|
|
329
|
+
|
|
330
|
+
# control columns
|
|
331
|
+
'string_col': DataType.STRING,
|
|
332
|
+
'bool_col': DataType.BOOLEAN
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
# Verify each column's data type
|
|
336
|
+
for column in columns:
|
|
337
|
+
assert column.data_type == expected_types[column.name], \
|
|
338
|
+
f"Column {column.name} should be {expected_types[column.name]}, but got {column.data_type}"
|
|
339
|
+
|
|
340
|
+
# Verify min and max values for numeric columns
|
|
341
|
+
for col_name in df.select_dtypes(include=['int', 'float']).columns:
|
|
342
|
+
col = next(c for c in columns if c.name == col_name)
|
|
343
|
+
assert col.min == df[col_name].min(), \
|
|
344
|
+
f"Min value mismatch for {col_name}: expected {df[col_name].min()}, got {col.min}"
|
|
345
|
+
assert col.max == df[col_name].max(), \
|
|
346
|
+
f"Max value mismatch for {col_name}: expected {df[col_name].max()}, got {col.max}"
|
|
347
|
+
|
|
348
|
+
def test_integer_edge_cases():
|
|
349
|
+
# Test with empty DataFrame
|
|
350
|
+
empty_df = pd.DataFrame({
|
|
351
|
+
'int_col': pd.Series([], dtype='int64')
|
|
352
|
+
})
|
|
353
|
+
columns = create_columns_from_df(empty_df).columns
|
|
354
|
+
assert len(columns) == 1
|
|
355
|
+
assert columns[0].data_type == DataType.INTEGER
|
|
356
|
+
|
|
357
|
+
# Test with NaN values
|
|
358
|
+
df_with_nan = pd.DataFrame({
|
|
359
|
+
'int_col': pd.Series([1, 2, np.nan], dtype='float64') # NaN forces float dtype
|
|
360
|
+
})
|
|
361
|
+
columns = create_columns_from_df(df_with_nan).columns
|
|
362
|
+
assert len(columns) == 1
|
|
363
|
+
assert columns[0].data_type == DataType.FLOAT # Should be float due to NaN
|
|
364
|
+
|
|
365
|
+
# Test with mixed types
|
|
366
|
+
df_mixed = pd.DataFrame({
|
|
367
|
+
'mixed_col': pd.Series([1, '2', 3], dtype='object')
|
|
368
|
+
})
|
|
369
|
+
columns = create_columns_from_df(df_mixed).columns
|
|
370
|
+
assert len(columns) == 1
|
|
371
|
+
assert columns[0].data_type == DataType.STRING # Should be string due to mixed types
|
|
372
|
+
|
|
373
|
+
def test_float_edge_cases():
|
|
374
|
+
# Test with NaN values
|
|
375
|
+
df_nan = pd.DataFrame({
|
|
376
|
+
'float_nan': pd.Series([1.0, np.nan, 3.0], dtype='float64')
|
|
377
|
+
})
|
|
378
|
+
columns = create_columns_from_df(df_nan).columns
|
|
379
|
+
assert len(columns) == 1
|
|
380
|
+
assert columns[0].data_type == DataType.FLOAT
|
|
381
|
+
assert columns[0].min == 1.0
|
|
382
|
+
assert columns[0].max == 3.0
|
|
383
|
+
|
|
384
|
+
# Test with infinity
|
|
385
|
+
df_inf = pd.DataFrame({
|
|
386
|
+
'float_inf': pd.Series([1.0, np.inf, -np.inf], dtype='float64')
|
|
387
|
+
})
|
|
388
|
+
columns = create_columns_from_df(df_inf).columns
|
|
389
|
+
assert len(columns) == 1
|
|
390
|
+
assert columns[0].data_type == DataType.FLOAT
|
|
391
|
+
assert columns[0].min == -np.inf
|
|
392
|
+
assert columns[0].max == np.inf
|
|
393
|
+
|
|
394
|
+
# Test with very small numbers
|
|
395
|
+
df_small = pd.DataFrame({
|
|
396
|
+
'float_small': pd.Series([1e-10, 1e-20, 1e-30], dtype='float64')
|
|
397
|
+
})
|
|
398
|
+
columns = create_columns_from_df(df_small).columns
|
|
399
|
+
assert len(columns) == 1
|
|
400
|
+
assert columns[0].data_type == DataType.FLOAT
|
|
401
|
+
assert columns[0].min == 1e-30
|
|
402
|
+
assert columns[0].max == 1e-10
|
|
403
|
+
|
|
404
|
+
# Test with very large numbers
|
|
405
|
+
df_large = pd.DataFrame({
|
|
406
|
+
'float_large': pd.Series([1e10, 1e20, 1e30], dtype='float64')
|
|
407
|
+
})
|
|
408
|
+
columns = create_columns_from_df(df_large).columns
|
|
409
|
+
assert len(columns) == 1
|
|
410
|
+
assert columns[0].data_type == DataType.FLOAT
|
|
411
|
+
assert columns[0].min == 1e10
|
|
412
|
+
assert columns[0].max == 1e30
|
|
413
|
+
|
|
414
|
+
def test_mixed_numeric_types():
|
|
415
|
+
# Test with mixed integer and float values
|
|
416
|
+
df_mixed = pd.DataFrame({
|
|
417
|
+
'mixed_numeric': pd.Series([1, 2.0, 3], dtype='float64')
|
|
418
|
+
})
|
|
419
|
+
columns = create_columns_from_df(df_mixed).columns
|
|
420
|
+
assert len(columns) == 1
|
|
421
|
+
assert columns[0].data_type == DataType.FLOAT
|
|
422
|
+
assert columns[0].min == 1.0
|
|
423
|
+
assert columns[0].max == 3.0
|
|
424
|
+
|
|
425
|
+
# Test with mixed numeric and string values
|
|
426
|
+
df_mixed_str = pd.DataFrame({
|
|
427
|
+
'mixed_str': pd.Series([1, '2.0', 3], dtype='object')
|
|
428
|
+
})
|
|
429
|
+
columns = create_columns_from_df(df_mixed_str).columns
|
|
430
|
+
assert len(columns) == 1
|
|
431
|
+
assert columns[0].data_type == DataType.STRING # Should be string due to mixed types
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from fiddler.schemas.model_schema import Column, ModelSchema
|
|
4
|
+
from fiddler.constants.model import DataType
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def create_columns_from_df(df: pd.DataFrame) -> ModelSchema:
|
|
8
|
+
"""
|
|
9
|
+
Helper function to create Columns from a pandas DataFrame column dtypes.
|
|
10
|
+
timedelta, period, interval & object dtypes are converted to string.
|
|
11
|
+
Sparse dtypes are not handled.
|
|
12
|
+
Args:
|
|
13
|
+
df: Input pandas DataFrame
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
ModelSchema
|
|
17
|
+
"""
|
|
18
|
+
columns: List[Column] = []
|
|
19
|
+
|
|
20
|
+
# Check if the DataFrame is empty - a dataframe with columns but no rows is valid
|
|
21
|
+
if len(df.columns) == 0:
|
|
22
|
+
raise ValueError("Cannot create columns from an empty DataFrame")
|
|
23
|
+
|
|
24
|
+
for col_name, dtype in df.dtypes.items():
|
|
25
|
+
# Map pandas dtypes to Fiddler DataTypes
|
|
26
|
+
if pd.api.types.is_float_dtype(dtype):
|
|
27
|
+
data_type = DataType.FLOAT
|
|
28
|
+
col_min, col_max = float(df[col_name].min()), float(df[col_name].max())
|
|
29
|
+
col = Column(
|
|
30
|
+
name=col_name,
|
|
31
|
+
data_type=data_type,
|
|
32
|
+
min=col_min,
|
|
33
|
+
max=col_max
|
|
34
|
+
)
|
|
35
|
+
elif pd.api.types.is_integer_dtype(dtype):
|
|
36
|
+
data_type = DataType.INTEGER
|
|
37
|
+
col = Column(
|
|
38
|
+
name=col_name,
|
|
39
|
+
data_type=data_type,
|
|
40
|
+
min=df[col_name].min(),
|
|
41
|
+
max=df[col_name].max()
|
|
42
|
+
)
|
|
43
|
+
elif pd.api.types.is_bool_dtype(dtype):
|
|
44
|
+
col = Column(
|
|
45
|
+
name=col_name,
|
|
46
|
+
data_type=DataType.BOOLEAN
|
|
47
|
+
)
|
|
48
|
+
elif pd.api.types.is_datetime64_any_dtype(dtype):
|
|
49
|
+
col = Column(
|
|
50
|
+
name=col_name,
|
|
51
|
+
data_type=DataType.TIMESTAMP
|
|
52
|
+
)
|
|
53
|
+
elif pd.api.types.is_categorical_dtype(dtype):
|
|
54
|
+
col = Column(
|
|
55
|
+
name=col_name,
|
|
56
|
+
data_type=DataType.CATEGORY,
|
|
57
|
+
categories=df[col_name].cat.categories.tolist()
|
|
58
|
+
)
|
|
59
|
+
else:
|
|
60
|
+
# Default to string for other types
|
|
61
|
+
col = Column(
|
|
62
|
+
name=col_name,
|
|
63
|
+
data_type=DataType.STRING
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
columns.append(col)
|
|
67
|
+
|
|
68
|
+
return ModelSchema(columns=columns)
|
|
@@ -103,6 +103,7 @@ fiddler/tests/apis/test_segment.py
|
|
|
103
103
|
fiddler/tests/apis/test_webhook.py
|
|
104
104
|
fiddler/tests/apis/test_xai.py
|
|
105
105
|
fiddler/utils/__init__.py
|
|
106
|
+
fiddler/utils/column_generator.py
|
|
106
107
|
fiddler/utils/decorators.py
|
|
107
108
|
fiddler/utils/helpers.py
|
|
108
109
|
fiddler/utils/logger.py
|
|
@@ -29,10 +29,10 @@ setuptools.setup(
|
|
|
29
29
|
'requests-toolbelt',
|
|
30
30
|
'pandas>=1.2.5',
|
|
31
31
|
'pydantic>=1.10.17',
|
|
32
|
-
'deprecated==1.2.
|
|
32
|
+
'deprecated==1.2.18',
|
|
33
33
|
'tqdm',
|
|
34
34
|
'simplejson>=3.17.0',
|
|
35
|
-
'pyarrow>=
|
|
35
|
+
'pyarrow>=15.0.0',
|
|
36
36
|
'pyyaml',
|
|
37
37
|
'typing-extensions>=4.6.0,<5',
|
|
38
38
|
],
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
3.8.3
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import tempfile
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
|
|
5
|
-
import pandas as pd
|
|
6
|
-
import pytest
|
|
7
|
-
|
|
8
|
-
from fiddler.schemas.server_info import Version
|
|
9
|
-
from fiddler.utils.helpers import group_by, try_series_retype
|
|
10
|
-
from fiddler.utils.validations import validate_artifact_dir
|
|
11
|
-
from fiddler.utils.version import match_semver
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def test_match_semvar_version() -> None:
|
|
15
|
-
assert match_semver(None, '>=22.9.0') is False
|
|
16
|
-
assert match_semver(Version.parse('22.9.0'), '>=22.10.0') is False
|
|
17
|
-
assert match_semver(Version.parse('22.10.0'), '>=22.10.0') is True
|
|
18
|
-
assert match_semver(Version.parse('22.10.0'), '>22.10.0') is False
|
|
19
|
-
assert match_semver(Version.parse('22.11.0'), '>=22.10.0') is True
|
|
20
|
-
assert match_semver(Version.parse('22.11.0'), '>22.10.0') is True
|
|
21
|
-
assert match_semver(Version.parse('22.10.0'), '<=22.10.0') is True
|
|
22
|
-
assert match_semver(Version.parse('22.10.0'), '<22.10.0') is False
|
|
23
|
-
assert match_semver(Version.parse('22.9.0'), '<22.10.0') is True
|
|
24
|
-
assert match_semver(Version.parse('22.11.0-RC1'), '>=22.11.0') is True
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def test_validate_artifact_dir(tmp_path) -> None:
|
|
28
|
-
artifact_dir = os.path.join(Path(__file__).resolve().parent, 'artifact_test_dir')
|
|
29
|
-
assert validate_artifact_dir(Path(artifact_dir)) is None
|
|
30
|
-
# Test for artifact_dir not valid directory
|
|
31
|
-
with pytest.raises(ValueError):
|
|
32
|
-
validate_artifact_dir(Path('test'))
|
|
33
|
-
# Test for package.py file not found
|
|
34
|
-
mock_dir = tmp_path / 'test'
|
|
35
|
-
mock_dir.mkdir()
|
|
36
|
-
with pytest.raises(ValueError):
|
|
37
|
-
validate_artifact_dir(Path(mock_dir))
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def test_group_by_helper() -> None:
|
|
41
|
-
df = pd.DataFrame(
|
|
42
|
-
[
|
|
43
|
-
{'col1': 1, 'col2': 'foo'},
|
|
44
|
-
{'col1': 2, 'col2': 'bar'},
|
|
45
|
-
{'col1': 3, 'col2': 'baz'},
|
|
46
|
-
{'col1': 3, 'col2': 'foo'},
|
|
47
|
-
]
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
# with output_path
|
|
51
|
-
with tempfile.TemporaryDirectory() as temp_dir:
|
|
52
|
-
file_path = Path(temp_dir) / 'data.csv'
|
|
53
|
-
|
|
54
|
-
assert file_path.exists() is False
|
|
55
|
-
group_by(df=df, group_by_col='col2', output_path=file_path)
|
|
56
|
-
assert file_path.exists() is True
|
|
57
|
-
|
|
58
|
-
# without output path
|
|
59
|
-
grouped_df = group_by(df=df, group_by_col='col2')
|
|
60
|
-
assert grouped_df.equals(
|
|
61
|
-
pd.DataFrame(
|
|
62
|
-
[
|
|
63
|
-
{'col2': 'foo', 'col1': [1, 3]},
|
|
64
|
-
{'col2': 'bar', 'col1': [2]},
|
|
65
|
-
{'col2': 'baz', 'col1': [3]},
|
|
66
|
-
]
|
|
67
|
-
)
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def test_try_series_retype() -> None:
|
|
72
|
-
series = pd.Series([1, 2, 3], dtype='float')
|
|
73
|
-
series = try_series_retype(series, 'int')
|
|
74
|
-
assert series.dtype == 'int'
|
|
75
|
-
|
|
76
|
-
series = pd.Series([1, 2, None])
|
|
77
|
-
series = try_series_retype(series, 'int')
|
|
78
|
-
assert series.dtype == 'float'
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def test_try_series_retype_str_or_unkown() -> None:
|
|
82
|
-
series = pd.Series(['HIGH', 'MEDIUM', '', None], dtype='str')
|
|
83
|
-
series = try_series_retype(series, 'str')
|
|
84
|
-
assert series.dtype == 'object'
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
def test_try_series_retype_timestamp() -> None:
|
|
88
|
-
series = pd.Series(
|
|
89
|
-
['2023-11-12 09:15:32.23', '2023-12-11 09:15:32.45'], dtype='str'
|
|
90
|
-
)
|
|
91
|
-
series = try_series_retype(series, 'timestamp')
|
|
92
|
-
assert series.dtype == 'datetime64[ns]'
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
def test_try_series_retype_timestamp_error() -> None:
|
|
96
|
-
series = pd.Series(['2023-11-12 09:15:32.23', None], dtype='str')
|
|
97
|
-
|
|
98
|
-
with pytest.raises(TypeError):
|
|
99
|
-
try_series_retype(series, 'timestamp')
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fiddler-client-3.8.3 → fiddler-client-3.9.1}/fiddler/packtools/project_attributions_helpers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|