ipulse-shared-core-ftredge 2.33__py3-none-any.whl → 2.36__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.
- ipulse_shared_core_ftredge/__init__.py +3 -2
- ipulse_shared_core_ftredge/utils_templates_and_schemas.py +83 -76
- {ipulse_shared_core_ftredge-2.33.dist-info → ipulse_shared_core_ftredge-2.36.dist-info}/METADATA +1 -1
- {ipulse_shared_core_ftredge-2.33.dist-info → ipulse_shared_core_ftredge-2.36.dist-info}/RECORD +7 -7
- {ipulse_shared_core_ftredge-2.33.dist-info → ipulse_shared_core_ftredge-2.36.dist-info}/LICENCE +0 -0
- {ipulse_shared_core_ftredge-2.33.dist-info → ipulse_shared_core_ftredge-2.36.dist-info}/WHEEL +0 -0
- {ipulse_shared_core_ftredge-2.33.dist-info → ipulse_shared_core_ftredge-2.36.dist-info}/top_level.txt +0 -0
|
@@ -4,8 +4,9 @@ from .utils_gcp import (setup_gcp_logger_and_error_report,
|
|
|
4
4
|
read_csv_from_gcs, read_json_from_gcs,
|
|
5
5
|
write_csv_to_gcs, write_json_to_gcs)
|
|
6
6
|
from .utils_templates_and_schemas import (create_bigquery_schema_from_json,
|
|
7
|
-
update_check_with_schema_template
|
|
8
|
-
|
|
7
|
+
update_check_with_schema_template,
|
|
8
|
+
create_data_check_notice)
|
|
9
|
+
from .enums import (NoticeSeverity, Unit, Frequency,
|
|
9
10
|
Module, SubModule, BaseDataCategory,
|
|
10
11
|
FinCoreCategory, FincCoreSubCategory,
|
|
11
12
|
FinCoreRecordsCategory, ExchangeOrPublisher,
|
|
@@ -5,7 +5,15 @@
|
|
|
5
5
|
|
|
6
6
|
import datetime
|
|
7
7
|
from google.cloud import bigquery
|
|
8
|
-
from . import NoticeSeverity
|
|
8
|
+
from ipulse_shared_core_ftredge.enums.enums_common_utils import NoticeSeverity
|
|
9
|
+
|
|
10
|
+
def create_data_check_notice(severity, field_name, message):
|
|
11
|
+
return {
|
|
12
|
+
"severity_code": severity.value,
|
|
13
|
+
"severity_name": severity.name,
|
|
14
|
+
"subject": field_name,
|
|
15
|
+
"message": message
|
|
16
|
+
}
|
|
9
17
|
|
|
10
18
|
def create_bigquery_schema_from_json(json_schema):
|
|
11
19
|
schema = []
|
|
@@ -17,124 +25,123 @@ def create_bigquery_schema_from_json(json_schema):
|
|
|
17
25
|
return schema
|
|
18
26
|
|
|
19
27
|
|
|
20
|
-
def update_check_with_schema_template(updates, schema,
|
|
21
|
-
|
|
28
|
+
def update_check_with_schema_template(updates, schema, dt_ts_to_str=True, check_max_length=True):
|
|
29
|
+
|
|
22
30
|
"""Ensure Update dict corresponds to the config schema, ensuring proper formats and lengths."""
|
|
23
31
|
valid_updates = {}
|
|
24
|
-
|
|
32
|
+
notices=[] ### THIS IS TO AVOID LOGGING A WARNING RANDOMLY , INSTEAD GROUPPING FOR A GIVEN RUN
|
|
33
|
+
|
|
25
34
|
# Process updates to conform to the schema
|
|
26
35
|
for field in schema:
|
|
27
36
|
field_name = field["name"]
|
|
28
37
|
field_type = field["type"]
|
|
29
38
|
mode = field["mode"]
|
|
30
|
-
|
|
39
|
+
|
|
31
40
|
if field_name in updates:
|
|
32
41
|
value = updates[field_name]
|
|
33
|
-
|
|
42
|
+
|
|
34
43
|
# Handle date and timestamp formatting
|
|
35
44
|
if dt_ts_to_str:
|
|
36
45
|
if field_type == "DATE":
|
|
37
|
-
value = handle_date_fields(field_name, value
|
|
46
|
+
value, notice = handle_date_fields(field_name, value)
|
|
38
47
|
elif field_type == "TIMESTAMP":
|
|
39
|
-
value = handle_timestamp_fields(field_name, value
|
|
40
|
-
|
|
48
|
+
value,notice = handle_timestamp_fields(field_name, value)
|
|
49
|
+
if notice:
|
|
50
|
+
notices.append(notice)
|
|
41
51
|
# Check and handle max length restriction
|
|
42
52
|
if check_max_length and "max_length" in field:
|
|
43
|
-
value = check_and_truncate_length(field_name, value, field["max_length"]
|
|
44
|
-
|
|
53
|
+
value,notice = check_and_truncate_length(field_name, value, field["max_length"])
|
|
54
|
+
if notice:
|
|
55
|
+
notices.append(notice)
|
|
45
56
|
# Validate and convert types
|
|
46
|
-
if field_type
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
elif field_type == "INT64":
|
|
51
|
-
if not isinstance(value, int):
|
|
52
|
-
logger.warning(f"Field {field_name} expected to be an int but got {type(value).__name__}.")
|
|
53
|
-
try:
|
|
54
|
-
value = int(value)
|
|
55
|
-
except ValueError:
|
|
56
|
-
logger.warning(f"Cannot convert value {value} of field {field_name} to int.")
|
|
57
|
-
continue
|
|
58
|
-
elif field_type == "FLOAT64":
|
|
59
|
-
if not isinstance(value, float):
|
|
60
|
-
logger.warning(f"Field {field_name} expected to be a float but got {type(value).__name__}.")
|
|
61
|
-
try:
|
|
62
|
-
value = float(value)
|
|
63
|
-
except ValueError:
|
|
64
|
-
logger.warning(f"Cannot convert value {value} of field {field_name} to float.")
|
|
65
|
-
continue
|
|
66
|
-
elif field_type == "BOOL":
|
|
67
|
-
if not isinstance(value, bool):
|
|
68
|
-
logger.warning(f"Field {field_name} expected to be a bool but got {type(value).__name__}.")
|
|
69
|
-
value = bool(value)
|
|
57
|
+
if field_type in ["STRING", "INT64", "FLOAT64", "BOOL"]:
|
|
58
|
+
value, notice = handle_type_conversion(field_type, field_name, value )
|
|
59
|
+
if notice:
|
|
60
|
+
notices.append(notice)
|
|
70
61
|
|
|
71
62
|
# Only add to the dictionary if value is not None or the field is required
|
|
72
63
|
if value is not None or mode == "REQUIRED":
|
|
73
64
|
valid_updates[field_name] = value
|
|
74
65
|
|
|
75
66
|
elif mode == "REQUIRED":
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def check_updates_formatting(updates, schema, logger, dt_ts_to_str, check_max_length):
|
|
82
|
-
"""Processes updates to ensure they match the schema, handling dates, timestamps, and lengths."""
|
|
83
|
-
for field in schema:
|
|
84
|
-
field_name = field["name"]
|
|
85
|
-
field_type = field["type"]
|
|
86
|
-
|
|
87
|
-
if field_name in updates:
|
|
88
|
-
value = updates[field_name]
|
|
67
|
+
notice=create_data_check_notice(NoticeSeverity.WARNING_ACTION_REQUIRED,
|
|
68
|
+
field_name,
|
|
69
|
+
f"Required field '{field_name}' is missing in the updates.")
|
|
89
70
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
elif field_type == "TIMESTAMP":
|
|
94
|
-
updates[field_name] = handle_timestamp_fields(field_name, value, logger)
|
|
95
|
-
|
|
96
|
-
if check_max_length and "max_length" in field:
|
|
97
|
-
updates[field_name] = check_and_truncate_length(field_name, value, field["max_length"], logger)
|
|
98
|
-
|
|
99
|
-
return updates
|
|
71
|
+
notices.append(notice)
|
|
72
|
+
|
|
73
|
+
return valid_updates, notices
|
|
100
74
|
|
|
101
75
|
|
|
102
|
-
def handle_date_fields(field_name, value
|
|
103
|
-
"""Handles date fields, ensuring they are in the correct format.
|
|
76
|
+
def handle_date_fields(field_name, value):
|
|
77
|
+
"""Handles date fields, ensuring they are in the correct format.
|
|
78
|
+
Return is a tuple of the formatted date and a notice."""
|
|
104
79
|
if isinstance(value, datetime.date):
|
|
105
|
-
return value.strftime("%Y-%m-%d")
|
|
80
|
+
return value.strftime("%Y-%m-%d"), None
|
|
106
81
|
elif isinstance(value, str):
|
|
107
82
|
try:
|
|
108
83
|
datetime.datetime.strptime(value, "%Y-%m-%d")
|
|
109
84
|
return value
|
|
110
85
|
except ValueError:
|
|
111
|
-
|
|
112
|
-
|
|
86
|
+
return None, create_data_check_notice(NoticeSeverity.WARNING_ACTION_REQUIRED,
|
|
87
|
+
field_name,
|
|
88
|
+
f"Expected a DATE or YYYY-MM-DD str format but got {value} of type {type(value).__name__}.")
|
|
113
89
|
else:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
90
|
+
return None, create_data_check_notice(NoticeSeverity.WARNING_ACTION_REQUIRED,
|
|
91
|
+
field_name,
|
|
92
|
+
f"Expected a DATE or YYYY-MM-DD str format but got {value} of type {type(value).__name__}.")
|
|
93
|
+
|
|
117
94
|
|
|
118
|
-
def handle_timestamp_fields(field_name, value
|
|
95
|
+
def handle_timestamp_fields(field_name, value):
|
|
119
96
|
"""Handles timestamp fields, ensuring they are in the correct format."""
|
|
120
97
|
if isinstance(value, datetime.datetime):
|
|
121
|
-
return value.isoformat()
|
|
98
|
+
return value.isoformat(), None
|
|
122
99
|
elif isinstance(value, str):
|
|
123
100
|
try:
|
|
124
101
|
datetime.datetime.fromisoformat(value)
|
|
125
102
|
return value
|
|
126
103
|
except ValueError:
|
|
127
|
-
|
|
128
|
-
|
|
104
|
+
return None, create_data_check_notice(NoticeSeverity.WARNING_ACTION_REQUIRED,
|
|
105
|
+
field_name,
|
|
106
|
+
f"Expected ISO format TIMESTAMP but got {value} of type {type(value).__name__}.")
|
|
129
107
|
else:
|
|
130
|
-
|
|
131
|
-
|
|
108
|
+
return None, create_data_check_notice(NoticeSeverity.WARNING_ACTION_REQUIRED,
|
|
109
|
+
field_name,
|
|
110
|
+
f"Expected ISO format TIMESTAMP but got {value} of type {type(value).__name__}.")
|
|
132
111
|
|
|
133
|
-
|
|
112
|
+
|
|
113
|
+
def check_and_truncate_length(field_name, value, max_length):
|
|
134
114
|
"""Checks and truncates the length of string fields if they exceed the max length."""
|
|
135
115
|
if isinstance(value, str) and len(value) > max_length:
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
116
|
+
return value[:max_length], create_data_check_notice(NoticeSeverity.WARNING_ACTION_RECOMMENDED,
|
|
117
|
+
field_name,
|
|
118
|
+
f"Field exceeds max length: {len(value)}/{max_length}. Truncating.")
|
|
119
|
+
|
|
120
|
+
return value, None
|
|
121
|
+
|
|
139
122
|
|
|
140
123
|
|
|
124
|
+
def handle_type_conversion(field_type, field_name, value):
|
|
125
|
+
if field_type == "STRING" and not isinstance(value, str):
|
|
126
|
+
return str(value), create_data_check_notice(NoticeSeverity.WARNING_ACTION_REQUIRED,
|
|
127
|
+
field_name,
|
|
128
|
+
f"Expected STRING but got {value} of type {type(value).__name__}.")
|
|
129
|
+
|
|
130
|
+
if field_type == "INT64" and not isinstance(value, int):
|
|
131
|
+
try:
|
|
132
|
+
return int(value), None
|
|
133
|
+
except ValueError:
|
|
134
|
+
return None, create_data_check_notice(NoticeSeverity.WARNING_ACTION_REQUIRED,
|
|
135
|
+
field_name,
|
|
136
|
+
f"Expected INTEGER, but got {value} of type {type(value).__name__}.")
|
|
137
|
+
if field_type == "FLOAT64" and not isinstance(value, float):
|
|
138
|
+
try:
|
|
139
|
+
return float(value), None
|
|
140
|
+
except ValueError:
|
|
141
|
+
return None, create_data_check_notice(NoticeSeverity.WARNING_ACTION_REQUIRED,
|
|
142
|
+
field_name,
|
|
143
|
+
f"Expected FLOAT, but got {value} of type {type(value).__name__}.")
|
|
144
|
+
if field_type == "BOOL" and not isinstance(value, bool):
|
|
145
|
+
return bool(value), None
|
|
146
|
+
|
|
147
|
+
return value, None
|
{ipulse_shared_core_ftredge-2.33.dist-info → ipulse_shared_core_ftredge-2.36.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ipulse_shared_core_ftredge
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.36
|
|
4
4
|
Summary: Shared Core models and Logger util for the Pulse platform project. Using AI for financial advisory and investment management.
|
|
5
5
|
Home-page: https://github.com/TheFutureEdge/ipulse_shared_core
|
|
6
6
|
Author: Russlan Ramdowar
|
{ipulse_shared_core_ftredge-2.33.dist-info → ipulse_shared_core_ftredge-2.36.dist-info}/RECORD
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
ipulse_shared_core_ftredge/__init__.py,sha256=
|
|
1
|
+
ipulse_shared_core_ftredge/__init__.py,sha256=snLFrVzGmYy6TmXM6-D7Yq4dkcJDRP3g9DeuJQDFPMc,895
|
|
2
2
|
ipulse_shared_core_ftredge/utils_gcp.py,sha256=E8TvZ05fTjNr-VQXxSZNCiqT9PwPhtqeKOifIGhb2sg,6289
|
|
3
|
-
ipulse_shared_core_ftredge/utils_templates_and_schemas.py,sha256=
|
|
3
|
+
ipulse_shared_core_ftredge/utils_templates_and_schemas.py,sha256=UxRZnTOmV0VfjtrA-0YrTcKgJOMpa6kFiuLSdSUD_XA,6513
|
|
4
4
|
ipulse_shared_core_ftredge/enums/__init__.py,sha256=PjxJiUConI2TuaG_Ushe2BaFVjBDw1rbq1E9Vt9nXvE,801
|
|
5
5
|
ipulse_shared_core_ftredge/enums/enums_common_utils.py,sha256=ukChcm8R2QwlK4NAfM291mWryCAZvfg7bMpdScQQfok,4360
|
|
6
6
|
ipulse_shared_core_ftredge/enums/enums_data_eng.py,sha256=A8_uiGGacd-_AZP09Zft-DX3rF8aVqqFzFak8s4MsfY,1801
|
|
@@ -17,8 +17,8 @@ ipulse_shared_core_ftredge/models/user_profile_update.py,sha256=oKK0XsQDKkgDvjFP
|
|
|
17
17
|
ipulse_shared_core_ftredge/models/user_status.py,sha256=8TyRd8tBK9_xb0MPKbI5pn9-lX7ovKbeiuWYYPtIOiw,3202
|
|
18
18
|
ipulse_shared_core_ftredge/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
19
|
ipulse_shared_core_ftredge/tests/test.py,sha256=0lS8HP5Quo_BqNoscU40qOH9aJRaa1Pfam5VUBmdld8,682
|
|
20
|
-
ipulse_shared_core_ftredge-2.
|
|
21
|
-
ipulse_shared_core_ftredge-2.
|
|
22
|
-
ipulse_shared_core_ftredge-2.
|
|
23
|
-
ipulse_shared_core_ftredge-2.
|
|
24
|
-
ipulse_shared_core_ftredge-2.
|
|
20
|
+
ipulse_shared_core_ftredge-2.36.dist-info/LICENCE,sha256=YBtYAXNqCCOo9Mr2hfkbSPAM9CeAr2j1VZBSwQTrNwE,1060
|
|
21
|
+
ipulse_shared_core_ftredge-2.36.dist-info/METADATA,sha256=vYm8146CUjDdbz9XOZGikiH2wfd29iIthI6zq608ShI,561
|
|
22
|
+
ipulse_shared_core_ftredge-2.36.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
23
|
+
ipulse_shared_core_ftredge-2.36.dist-info/top_level.txt,sha256=8sgYrptpexkA_6_HyGvho26cVFH9kmtGvaK8tHbsGHk,27
|
|
24
|
+
ipulse_shared_core_ftredge-2.36.dist-info/RECORD,,
|
{ipulse_shared_core_ftredge-2.33.dist-info → ipulse_shared_core_ftredge-2.36.dist-info}/LICENCE
RENAMED
|
File without changes
|
{ipulse_shared_core_ftredge-2.33.dist-info → ipulse_shared_core_ftredge-2.36.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|