dscin-ppy 0.0.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.
@@ -0,0 +1,12 @@
1
+ Metadata-Version: 2.1
2
+ Name: dscin_ppy
3
+ Version: 0.0.1
4
+ Summary: Collection of utility functions
5
+ Home-page: UNKNOWN
6
+ Author: Andrea Chiappo
7
+ Author-email: chiappo.andrea@gmail.com
8
+ License: UNKNOWN
9
+ Platform: UNKNOWN
10
+
11
+ UNKNOWN
12
+
File without changes
@@ -0,0 +1,12 @@
1
+ from functions import *
2
+ from db_utils import *
3
+ from etl_job import *
4
+ from aws_utils import *
5
+
6
+ import os
7
+ bucket = os.getenv("S3_TRANSDICT_BUCKET")
8
+ key = os.getenv("S3_TRANSDICT_KEY")
9
+
10
+ download_object_from_s3(
11
+ bucket, key, "src/translation_dictionaries.py"
12
+ )
@@ -0,0 +1,86 @@
1
+ import boto3
2
+
3
+
4
+ def build_s3_url(bucket, key):
5
+ return f's3a://{bucket}/{key}'
6
+
7
+
8
+ def read_object_from_s3(bucket, key):
9
+ s3_client = boto3.client("s3")
10
+ try:
11
+ # Get the file inside the S3 Bucket
12
+ s3_response = s3_client.get_object(Bucket=bucket, Key=key)
13
+ return s3_response["Body"].read()
14
+ except s3_client.exceptions.NoSuchBucket as e:
15
+ print("The S3 bucket does not exist.")
16
+ print(e)
17
+ except s3_client.exceptions.NoSuchKey as e:
18
+ print("The S3 objects does not exist in the S3 bucket.")
19
+ print(e)
20
+
21
+
22
+ def open_object_from_s3(bucket, key):
23
+ s3_client = boto3.client("s3")
24
+ try:
25
+ # Get the file inside the S3 Bucket
26
+ s3_response = s3_client.get_object(Bucket=bucket, Key=key)
27
+ return s3_response["Body"]
28
+ except s3_client.exceptions.NoSuchBucket as e:
29
+ print("The S3 bucket does not exist.")
30
+ print(e)
31
+ except s3_client.exceptions.NoSuchKey as e:
32
+ print("The S3 objects does not exist in the S3 bucket.")
33
+ print(e)
34
+
35
+
36
+ def write_dataframe_to_s3(dataframe, s3_url, file_type):
37
+ if file_type == "parquet":
38
+ dataframe.to_parquet(s3_url, engine='pyarrow', index=False)
39
+ elif file_type == "csv":
40
+ dataframe.to_csv(s3_url, index=False)
41
+ elif file_type == "xlsx":
42
+ dataframe.to_excel(s3_url, index=False)
43
+ else:
44
+ raise Exception("Format not supported")
45
+
46
+
47
+ def get_value_from_parameter_store(key, decrypt=False):
48
+ ssm_client = boto3.client("ssm")
49
+ value = ssm_client.get_parameter(Name=key, WithDecryption=decrypt)
50
+ return value["Parameter"]["Value"]
51
+
52
+
53
+ def save_to_s3(df, s3_bucket, s3_key, file_format):
54
+ s3_url = build_s3_url(s3_bucket, s3_key)
55
+ write_dataframe_to_s3(df, s3_url, file_format)
56
+
57
+
58
+ def copy_s3_object(copy_source, target_bucket, target_key):
59
+ s3_resource = boto3.resource("s3")
60
+ s3_bucket = s3_resource.Bucket(target_bucket)
61
+ s3_bucket.copy(copy_source, target_key)
62
+
63
+
64
+ def list_s3_objects(s3_bucket, s3_key_prefix):
65
+ s3_client = boto3.client("s3")
66
+ objects = s3_client.list_objects_v2(Bucket=s3_bucket, Prefix=s3_key_prefix)
67
+ # Extract the keys of the objects
68
+ objects_list = [
69
+ obj['Key'] for obj in objects.get('Contents', []) if obj
70
+ ]
71
+ return objects_list
72
+
73
+
74
+ def upload_object_to_s3(obj, s3_bucket, s3_key):
75
+ s3_client = boto3.client("s3")
76
+ s3_client.upload_fileobj(obj, s3_bucket, s3_key)
77
+
78
+
79
+ def remove_object_from_s3(bucket, key):
80
+ s3_client = boto3.client('s3')
81
+ s3_client.delete_object(Bucket=bucket, Key=key)
82
+
83
+
84
+ def download_object_from_s3(bucket, key, filename):
85
+ s3_client = boto3.client('s3')
86
+ s3_client.download_file(Bucket=bucket, Key=key, Filename=filename)
@@ -0,0 +1,10 @@
1
+ # INPUT PARAMS
2
+ ENV_PARAM = "env"
3
+ EXPORT_DATA_PARAM = "export_data"
4
+ LAST_X_DAYS_PARAM = "last_x_days"
5
+ SEASON_YEAR = "season_year"
6
+ HANA_SEASON = "hana_season"
7
+ FILE_NAME_PARAM = "file_name"
8
+ PREV_SEASONS_PARAM = "prev_seasons"
9
+ SEND_EMAIL ="send_email"
10
+ MODEL_NAME_EXT = "model_name_ext"
@@ -0,0 +1,234 @@
1
+ # This module contains functions to save and load data
2
+ import os
3
+ import csv
4
+ import time
5
+ import pickle
6
+ import datetime
7
+ import pandas as pd
8
+
9
+ import logging
10
+ log = logging.getLogger(__name__)
11
+
12
+
13
+ def remove_special_charachers(text, special=" ", replace=None):
14
+ if replace is None:
15
+ text = text.replace(special, "")
16
+ else:
17
+ text = text.replace(special, replace)
18
+ return text
19
+
20
+ def construct_path(*path):
21
+ path = os.path.join(*path)
22
+ path = (
23
+ os.path.join(os.path.dirname(__file__), path)
24
+ if not os.path.isabs(path)
25
+ else path
26
+ )
27
+ return path
28
+
29
+ def write_pickle(obj, *path):
30
+ """
31
+ Filepath in .pkl
32
+ """
33
+ path = construct_path(*path)
34
+ os.makedirs(os.path.dirname(path), exist_ok=True)
35
+ with open(path, "wb") as f:
36
+ pickle.dump(obj, f, pickle.HIGHEST_PROTOCOL)
37
+
38
+ def read_pickle(*path):
39
+ path = construct_path(*path)
40
+ with open(path, "rb") as f:
41
+ return pickle.load(f)
42
+
43
+ def append_csv(dataframe, path):
44
+ os.path.isfile(path)
45
+ path = construct_path(path)
46
+ if not os.path.exists(os.path.dirname(path)):
47
+ os.makedirs(os.path.dirname(path))
48
+ if os.path.isfile(path):
49
+ dataframe.to_csv(path, index=False, mode="a", header=False, sep=";")
50
+ else:
51
+ dataframe.to_csv(path, index=False, mode="a", header=True, sep=";")
52
+
53
+ def write_csv(dataframe: pd.DataFrame, *path, **kwargs):
54
+ """
55
+ Writes a DataFrame to disk as csv file, maintaining project standards.
56
+
57
+ Args:
58
+ DataFrame (pandas.DataFrame): the DataFrame to save
59
+ path: file location
60
+ """
61
+ path = construct_path(*path)
62
+ os.makedirs(os.path.dirname(path), exist_ok=True)
63
+ dataframe.to_csv(path, index=False, **kwargs)
64
+
65
+ def read_from_table(connection, table_name, cols_list=None, sum_list=None,
66
+ filter_condition=None, date_cols=None, extract_csv=False,
67
+ path="table_extraction.csv"):
68
+ """
69
+ Function that extracts defined table
70
+ If {extract_csv} is True, Extracted file saved as csv to the defined {path}
71
+
72
+ Args:
73
+ - connection: pyhdb.connect(host, port, user, password)
74
+ - table_name: table name in the database
75
+ - col_list: list of columns to query
76
+ - sum_list: list of columns to sum from the aggregation
77
+ - filter_condition: string containing the filtering instruction
78
+ - date_cols: list of column date in the data
79
+ - extract_csv: Boolean to control whether to save extraction to csv
80
+ - path: path string where to save the extracted data to csv
81
+
82
+ Returns:
83
+ - df (pd.DataFrame) extracted data
84
+
85
+ """
86
+ try:
87
+ if cols_list is not None:
88
+ if sum_list is not None:
89
+ group_list = set(cols_list) - set(sum_list)
90
+ group_str = '","'.join(group_list)
91
+ group_str = '"' + group_str + '"'
92
+ cols_list = set(cols_list) - set(sum_list)
93
+ cols_string = '","'.join(cols_list)
94
+ cols_string = '"' + cols_string + '"'
95
+
96
+ if sum_list is not None:
97
+ sum_list = ['sum("' + s + '")' for s in sum_list]
98
+ sum_list = ",".join(sum_list)
99
+ cols_string = cols_string + "," + sum_list
100
+ else:
101
+ cols_string = "*"
102
+
103
+ if filter_condition is not None and sum_list is None:
104
+ extract_query = "SELECT {} FROM {} WHERE {}".format(
105
+ cols_string, table_name, filter_condition
106
+ )
107
+ elif filter_condition is not None and sum_list is not None:
108
+ extract_query = "SELECT {} FROM {} WHERE {} GROUP BY {}".format(
109
+ cols_string, table_name, filter_condition, group_str
110
+ )
111
+ elif filter_condition is None and sum_list is not None:
112
+ extract_query = "SELECT {} FROM {} GROUP BY {}".format(
113
+ cols_string, table_name, group_str
114
+ )
115
+ else:
116
+ extract_query = "SELECT {} FROM {}".format(
117
+ cols_string, table_name
118
+ )
119
+
120
+ log.info(extract_query)
121
+ no_of_zerorecord_check:int = 1
122
+ while no_of_zerorecord_check != 0:
123
+ log.info(
124
+ str("no_of_zerorecord_check :" + str(no_of_zerorecord_check))
125
+ )
126
+ log.info(
127
+ str("Extraction start at :" + str(datetime.datetime.now()))
128
+ )
129
+ _data = pd.DataFrame()
130
+ data_list = []
131
+
132
+ if date_cols is None:
133
+ for chunk in pd.read_sql_query(extract_query, connection, chunksize=25000):
134
+ log.info(
135
+ str(
136
+ "Extracting Data from the table " +
137
+ table_name +
138
+ "as chunksize of 25000"
139
+ )
140
+ )
141
+ if extract_csv:
142
+ append_csv(chunk, path)
143
+ else:
144
+ data_list.append(chunk)
145
+ del chunk
146
+ else:
147
+ for chunk in pd.read_sql_query(extract_query, connection, chunksize=25000, parse_dates=date_cols):
148
+ log.info(
149
+ str(
150
+ "Extracting Data from the table " +
151
+ table_name +
152
+ "as chunksize of 25000"
153
+ )
154
+ )
155
+ if extract_csv:
156
+ append_csv(chunk, path)
157
+ else:
158
+ data_list.append(chunk)
159
+ del chunk
160
+
161
+ if extract_csv is False:
162
+ _data = pd.concat(data_list, ignore_index=True)
163
+
164
+ numOfRows = len(_data.index)
165
+
166
+ if numOfRows == 0:
167
+ # job sleeps for 1 minutes
168
+ log.info("Connection has been broken, wait for 10 secs")
169
+ time.sleep(10)
170
+ else:
171
+ break
172
+
173
+ no_of_zerorecord_check = no_of_zerorecord_check - 1
174
+
175
+ log.info(
176
+ str("Extraction end at :" + str(datetime.datetime.now()))
177
+ )
178
+
179
+ return _data
180
+
181
+ except Exception as e:
182
+ raise e
183
+
184
+ def read_csv(file_path, sep=",", decimal=".", header=0, index_col=""):
185
+ try:
186
+ if os.path.isfile(file_path):
187
+ if index_col != "":
188
+ _data = pd.read_csv(
189
+ file_path,
190
+ sep=sep,
191
+ decimal=decimal,
192
+ header=header,
193
+ quoting=csv.QUOTE_NONE,
194
+ index_col=index_col,
195
+ dtype="str"
196
+ )
197
+ else:
198
+ _data = pd.read_csv(
199
+ file_path,
200
+ sep=sep,
201
+ decimal=decimal,
202
+ header=header,
203
+ quoting=csv.QUOTE_NONE,
204
+ dtype="str"
205
+ )
206
+ return _data
207
+ else:
208
+ raise Exception
209
+ except Exception:
210
+ raise
211
+
212
+ def read_excel(file_path, sheet_name=0, skiprows=None):
213
+ try:
214
+ if os.path.isfile(file_path):
215
+ _data = pd.read_excel(
216
+ file_path, sheet_name=sheet_name, skiprows=skiprows
217
+ )
218
+ return _data
219
+ else:
220
+ raise Exception
221
+ except Exception:
222
+ raise
223
+
224
+ def write_excel(dataframe: pd.DataFrame, *path, **kwargs):
225
+ """
226
+ Writes a DataFrame to disk as excel file, maintaining project standards.
227
+
228
+ Args:
229
+ DataFrame (pandas.DataFrame): the DataFrame to save
230
+ path: file location
231
+ """
232
+ path = construct_path(*path)
233
+ os.makedirs(os.path.dirname(path), exist_ok=True)
234
+ dataframe.to_excel(path, index=False, **kwargs)
@@ -0,0 +1,14 @@
1
+ from hdbcli import dbapi
2
+
3
+ from config import db_config
4
+
5
+ def get_connection():
6
+ conn = dbapi.connect(
7
+ address=db_config.sap_hana_url,
8
+ port=db_config.sap_hana_port,
9
+ user=db_config.sap_hana_username,
10
+ password=db_config.sap_hana_password,
11
+ )
12
+ _ = conn.cursor()
13
+
14
+ return conn
@@ -0,0 +1,2 @@
1
+ class ValidationError(Exception):
2
+ pass
@@ -0,0 +1,14 @@
1
+ import job_parameters
2
+
3
+ class EtlJob:
4
+
5
+ def __init__(self):
6
+ self.params = job_parameters.gather_parameters()
7
+
8
+ def get_parameter(self, parameter, required: bool, default=None):
9
+ parameter_input_value = self.params.get(parameter.parameter_name)
10
+ parameter.validate(parameter_input_value, default, required)
11
+ return parameter.get_value_or_else(parameter_input_value, default)
12
+
13
+ def run(self):
14
+ pass
@@ -0,0 +1,55 @@
1
+ from config.env_config import env_config
2
+ from aws_utils import copy_s3_object
3
+
4
+ import logging
5
+ log = logging.getLogger(__name__)
6
+
7
+
8
+ def copy_report_to_email_bucket(env_param, file_name, s3_key, datatype='cid'):
9
+ s3_bucket = env_config[env_param]["feature-store-bucket"]
10
+ s3_exp_bucket = env_config[env_param]["exposed-bucket"]
11
+ s3_email_root_key = env_config[env_param]["exposed-send-to-email-path"]
12
+ if datatype == 'cid':
13
+ report_prefix = env_config[env_param]["exposed-cid-report-prefix"]
14
+ elif datatype == 'cod':
15
+ report_prefix = env_config[env_param]["exposed-cod-report-prefix"]
16
+ elif datatype == 'd2s':
17
+ report_prefix = env_config[env_param]["exposed-demand-to-supply-prefix"]
18
+ else:
19
+ raise ValueError(f"unkwon data type {datatype}")
20
+
21
+ copy_source = {"Bucket": s3_bucket, "Key": s3_key}
22
+ exp_file_name = f"{report_prefix}_{file_name}"
23
+ s3_exp_key = f"{s3_email_root_key}/{exp_file_name}"
24
+
25
+ log.info(f"Started file upload {exp_file_name} to email bucket.")
26
+ copy_s3_object(copy_source, s3_exp_bucket, s3_exp_key)
27
+ log.info(f"Finished file upload {exp_file_name} to email bucket.")
28
+
29
+
30
+ def copy_report_to_tableau_bucket(env_param, file_name, s3_key):
31
+ s3_bucket = env_config[env_param]["feature-store-bucket"]
32
+ s3_exp_bucket = env_config[env_param]["exposed-bucket"]
33
+ s3_tableau_root_key = env_config[env_param]["exposed-send-to-tableau-path"]
34
+
35
+ copy_source = {"Bucket": s3_bucket, "Key": s3_key}
36
+ s3_exp_key = f"{s3_tableau_root_key}/{file_name}"
37
+
38
+ log.info(f"Started file upload {file_name} to tableau bucket.")
39
+ copy_s3_object(copy_source, s3_exp_bucket, s3_exp_key)
40
+ log.info(f"Finished file upload {file_name} to tableau bucket.")
41
+
42
+
43
+ def copy_report_to_email_bucket_marketplace(env_param, file_name, s3_key):
44
+ s3_bucket = env_config[env_param]["feature-store-bucket"]
45
+ s3_exp_bucket = env_config[env_param]["exposed-bucket"]
46
+ s3_email_root_key = env_config[env_param]["exposed-send-to-email-path"]
47
+ report_prefix = env_config[env_param]["exposed-cod-report-prefix_compact"]
48
+
49
+ copy_source = {"Bucket": s3_bucket, "Key": s3_key}
50
+ exp_file_name = f"{report_prefix}_{file_name}"
51
+ s3_exp_key = f"{s3_email_root_key}/{exp_file_name}"
52
+
53
+ log.info(f"Started file upload {exp_file_name} to email bucket.")
54
+ copy_s3_object(copy_source, s3_exp_bucket, s3_exp_key)
55
+ log.info(f"Finished file upload {exp_file_name} to email bucket.")
@@ -0,0 +1,206 @@
1
+
2
+ import numpy as np
3
+ import pandas as pd
4
+
5
+ from time import time
6
+ from functools import wraps
7
+ from datetime import datetime
8
+
9
+
10
+ def timing(f):
11
+ @wraps(f)
12
+ def wrap(*args, **kw):
13
+ ts = time()
14
+ result = f(*args, **kw)
15
+ te = time()
16
+ print('func:%r args:[%r, %r] took: %2.4f sec' % \
17
+ (f.__name__, args, kw, te-ts))
18
+ return result
19
+ return wrap
20
+
21
+
22
+ def fillna_using_dtype(df):
23
+ column_types = df.dtypes.copy()
24
+
25
+ for k,v in df.dtypes.items():
26
+ if v == object:
27
+ column_types[k] = "#"
28
+ elif v == float or v == int:
29
+ column_types[k] = 0
30
+ elif v == datetime:
31
+ column_types[k] = pd.NaT
32
+ else:
33
+ column_types[k] = "#"
34
+
35
+ df.fillna(column_types, inplace=True)
36
+
37
+ return df
38
+
39
+
40
+ def replace_comma_with_semicolon(x):
41
+ if isinstance(x, str):
42
+ return x.replace(',', ';')
43
+ else:
44
+ return x
45
+
46
+
47
+ def extract_datetime_columns_from_dictionary(translation_dictionary):
48
+ """
49
+ Function to extract from {translation_dictionary} the columns with
50
+ datetime type and return a list of the corresponding technical names
51
+
52
+ Args:
53
+ - translation_dictionary: (dict)
54
+ translation dictionary, consisting of key-value pairs
55
+ {technical column name: [human column name (str), column data type]}
56
+
57
+ Returns:
58
+ - date_cols: (list[str])
59
+ list of all technical column names with data type datetime
60
+
61
+ Notes:
62
+ - An error is returned if {translation_dictionary} is empty
63
+ """
64
+
65
+ assert len(translation_dictionary) > 0, "translation_dictionary is empty"
66
+
67
+ date_cols = [
68
+ key for key, val in translation_dictionary.items() if val[1] == datetime
69
+ ]
70
+
71
+ return date_cols
72
+
73
+
74
+ def extract_dtype_columns_from_dictionary(translation_dictionary, data_type):
75
+ """
76
+ Function to extract from {translation_dictionary} the columns with
77
+ {data_type} type and return a list of the corresponding technical names
78
+
79
+ Args:
80
+ - translation_dictionary: (dict)
81
+ translation dictionary, consisting of key-value pairs
82
+ {technical column name: [human column name (str), column data type]}
83
+ - data_type: (str)
84
+ data type of the desired columns (for example: str, float, int,...)
85
+
86
+ Returns:
87
+ - data_type_cols: (list[str])
88
+ list of all technical column names with data type {data_type}
89
+
90
+ Notes:
91
+ - An error is returned if {translation_dictionary} is empty
92
+ """
93
+
94
+ assert len(translation_dictionary) > 0, "translation_dictionary is empty"
95
+
96
+ ### Create a list of the d_non_technical_column_names that match data_type
97
+ data_type_cols = [
98
+ key for key, val in translation_dictionary.items() if val[1] == data_type
99
+ ]
100
+
101
+ return data_type_cols
102
+
103
+
104
+ def extract_column_translations_from_dictionary(translation_dictionary):
105
+ """
106
+ Function to extract from {translation_dictionary} the technical names of
107
+ columns and their corresponding human-readable name and return a dictionary
108
+
109
+ Args:
110
+ - translation_dictionary: (dict)
111
+ translation dictionary, consisting of key-value pairs
112
+ {technical column name: [human column name (str), column data type]}
113
+
114
+ Returns:
115
+ - column_translation_dictionary: (dict{str: str}])
116
+ dictionary mapping columns' technical and human-readable names
117
+
118
+ Notes:
119
+ - An error is returned if {translation_dictionary} is empty
120
+ """
121
+
122
+ assert len(translation_dictionary) > 0, "translation_dictionary is empty"
123
+
124
+ # Create a dictionary of technical_column_name: non_technical_column_name
125
+ column_translation_dictionary = {
126
+ key: val[0] for key, val in translation_dictionary.items()
127
+ }
128
+
129
+ return column_translation_dictionary
130
+
131
+
132
+ def convert_column_dtype_to_str(df, translation_dictionary):
133
+ """
134
+ Function to convert to string the columns of {df} using the
135
+ {translation_dictionary} as a lookup reference for data types
136
+
137
+ Args:
138
+ - df: (pd.DataFrame)
139
+ Pandas.DataFrame whose columns to convert to str
140
+ - translation_dictionary: (dict)
141
+ reference dictionary for looking up the columns with str data type
142
+
143
+ Returns:
144
+ - df (pd.DataFrame):
145
+ staring Pandas.DataFrame with columns converted to str data type
146
+
147
+ Notes:
148
+ - An error is returned if {translation_dictionary} is empty
149
+ """
150
+
151
+ assert len(translation_dictionary) != 0, "translation_dictionary is empty"
152
+
153
+ ### Extract the str columns from translation_dictionary and store in list
154
+ str_cols = extract_dtype_columns_from_dictionary(translation_dictionary, str)
155
+ str_cols = [col for col in str_cols if col in df.columns.tolist()]
156
+
157
+ if len(str_cols) != len(set(str_cols)):
158
+ raise ValueError("Duplicate column names found in str_cols.")
159
+
160
+ ### Convert type
161
+ df[str_cols] = df[str_cols].astype(str)
162
+
163
+ return df
164
+
165
+
166
+ def convert_column_dtype_to_numeric(df, translation_dictionary, data_type):
167
+ """
168
+ Function to convert to numeric {data_type} the columns of {df} using
169
+ the {translation_dictionary} as a lookup reference for data types
170
+
171
+ Args:
172
+ - df: (pd.DataFrame)
173
+ Pandas.DataFrame whose columns to convert to {data_type}
174
+ - translation_dictionary: (dict)
175
+ reference dictionary for looking up the columns with {data_type} data type
176
+ - data_type: (str)
177
+ numeric data type object to which convert the columns of {df}
178
+
179
+ Returns:
180
+ - df (pd.DataFrame):
181
+ staring Pandas.DataFrame with columns converted to {data_type} data type
182
+
183
+ Notes:
184
+ - Empty values are replaced with 0's
185
+ - {data_type} needs to be of type float or int
186
+ - An error is returned if {translation_dictionary} is empty
187
+ """
188
+
189
+ assert data_type == float or data_type == int, "data_type must be either int or float!"
190
+ assert len(translation_dictionary) > 0, "translation_dictionary is empty"
191
+
192
+ ### Extract the int columns from translation_dictionary and store in list
193
+ num_cols = extract_dtype_columns_from_dictionary(translation_dictionary, data_type)
194
+ num_cols = [col for col in num_cols if col in df.columns.tolist()]
195
+
196
+ ### Replace empty values in num_cols with 0
197
+ df[num_cols] = df[num_cols].replace(r"^\s*$", np.nan, regex=True)
198
+ df[num_cols] = df[num_cols].fillna(0)
199
+
200
+ ### Convert type
201
+ if data_type == float:
202
+ df[num_cols] = df[num_cols].astype(float)
203
+ elif data_type == int:
204
+ df[num_cols] = df[num_cols].astype(float).astype(int)
205
+
206
+ return df
@@ -0,0 +1,278 @@
1
+
2
+ import argparse
3
+
4
+ import constants
5
+ from errors import ValidationError
6
+
7
+
8
+ class Parameter:
9
+
10
+ def get_value_or_else(self, value, default):
11
+ return value or default
12
+
13
+ def validate(self, value, default, required):
14
+ pass
15
+
16
+ def cast_value(self, value):
17
+ pass
18
+
19
+
20
+ class EnvParameter(Parameter):
21
+
22
+ def __init__(self) -> None:
23
+ self.parameter_name = constants.ENV_PARAM
24
+
25
+ def validate(self, value, default, required):
26
+ if not value:
27
+ value = default
28
+ if not value and required:
29
+ raise ValidationError(
30
+ f"Parameter is required: {self.parameter_name}"
31
+ )
32
+ if value not in ['dev', 'stage', 'prod']:
33
+ raise ValidationError(
34
+ f"{self.parameter_name} available values: 'dev', 'stage', 'prod'"
35
+ )
36
+
37
+ def get_value_or_else(self, value, default):
38
+ value = super().get_value_or_else(value, default)
39
+ return self.cast_value(value)
40
+
41
+ def cast_value(self, value):
42
+ return str(value)
43
+
44
+
45
+ class ExportDataParameter(Parameter):
46
+
47
+ def __init__(self) -> None:
48
+ self.parameter_name = constants.EXPORT_DATA_PARAM
49
+
50
+ def validate(self, value, default, required):
51
+ if not value:
52
+ value = default
53
+ if not value and required:
54
+ raise ValidationError(
55
+ f"Parameter is required: {self.parameter_name}"
56
+ )
57
+ if value not in ['True', 'False']:
58
+ raise ValidationError(
59
+ f"{self.parameter_name} available values: True/False"
60
+ )
61
+
62
+ def get_value_or_else(self, value, default):
63
+ value = super().get_value_or_else(value, default)
64
+ return self.cast_value(value)
65
+
66
+ # TODO: cast u boolean?
67
+ def cast_value(self, value):
68
+ return str(value)
69
+
70
+
71
+ class LastXDaysParameter(Parameter):
72
+ def __init__(self) -> None:
73
+ self.parameter_name = constants.LAST_X_DAYS_PARAM
74
+
75
+ def validate(self, value, default, required):
76
+ if not value:
77
+ value = default
78
+ if not value and required:
79
+ raise ValidationError(
80
+ f"Parameter is required: {self.parameter_name}"
81
+ )
82
+ if not value.isnumeric():
83
+ raise ValidationError(
84
+ f"Value of {self.parameter_name} must be a number."
85
+ )
86
+
87
+ def get_value_or_else(self, value, default):
88
+ value = super().get_value_or_else(value, default)
89
+ return self.cast_value(value)
90
+
91
+ def cast_value(self, value):
92
+ return str(value)
93
+
94
+
95
+ class SeasonYearParameter(Parameter):
96
+ def __init__(self) -> None:
97
+ self.parameter_name = constants.SEASON_YEAR
98
+
99
+ def validate(self, value, default, required):
100
+ if not value:
101
+ value = default
102
+ if not value and required:
103
+ raise ValidationError(
104
+ f"Parameter is required: {self.parameter_name}"
105
+ )
106
+ if not value.isnumeric():
107
+ raise ValidationError(
108
+ f"Value of {self.parameter_name} must be a number"
109
+ )
110
+
111
+ def get_value_or_else(self, value, default):
112
+ value = super().get_value_or_else(value, default)
113
+ return self.cast_value(value)
114
+
115
+ def cast_value(self, value):
116
+ return int(value)
117
+
118
+
119
+ class HanaSeasonParameter(Parameter):
120
+ def __init__(self) -> None:
121
+ self.parameter_name = constants.HANA_SEASON
122
+ def validate(self, value, default, required):
123
+ if not value:
124
+ value = default
125
+ if not value and required:
126
+ raise ValidationError(
127
+ f"Parameter is required: {self.parameter_name}"
128
+ )
129
+ if value not in ['WI', 'FA', 'SP', 'SU']:
130
+ raise ValidationError(
131
+ f"{self.parameter_name} available values: 'WI','SP','SU','FA'"
132
+ )
133
+
134
+ def get_value_or_else(self, value, default):
135
+ value = super().get_value_or_else(value, default)
136
+ return self.cast_value(value)
137
+
138
+ def cast_value(self, value):
139
+ return str(value)
140
+
141
+
142
+ class FileNameParameter(Parameter):
143
+ def __init__(self) -> None:
144
+ self.parameter_name = constants.FILE_NAME_PARAM
145
+
146
+ def validate(self, value, default, required):
147
+ if not value:
148
+ value = default
149
+ if not value and required:
150
+ raise ValidationError(
151
+ f"Parameter is required: {self.parameter_name}"
152
+ )
153
+ if not isinstance(value, str):
154
+ raise ValidationError(
155
+ f"{self.parameter_name} should be the name of the file in string format"
156
+ )
157
+
158
+ def get_value_or_else(self, value, default):
159
+ value = super().get_value_or_else(value, default)
160
+ return self.cast_value(value)
161
+
162
+ def cast_value(self, value):
163
+ return str(value)
164
+
165
+
166
+ class PreviousSeasonParameter(Parameter):
167
+ def __init__(self) -> None:
168
+ self.parameter_name = constants.PREV_SEASONS_PARAM
169
+
170
+ def validate(self, value, default, required):
171
+ if not value:
172
+ value = default
173
+ if not value and required:
174
+ raise ValidationError(
175
+ f"Parameter is required: {self.parameter_name}"
176
+ )
177
+
178
+ def get_value_or_else(self, value, default):
179
+ value = super().get_value_or_else(value, default)
180
+ return self.cast_value(value)
181
+
182
+ def cast_value(self, value):
183
+ return int(value)
184
+
185
+
186
+ class SendEmailParameter(Parameter):
187
+ def __init__(self) -> None:
188
+ self.parameter_name = constants.SEND_EMAIL
189
+
190
+ def validate(self, value, default, required):
191
+ if value is None:
192
+ value = default
193
+ if not value and required:
194
+ raise ValidationError(
195
+ f"Parameter is required: {self.parameter_name}"
196
+ )
197
+
198
+ def get_value_or_else(self, value, default):
199
+ if value is None:
200
+ value = super().get_value_or_else(value, default)
201
+ return self.cast_value(value)
202
+
203
+ def cast_value(self, value):
204
+ return value
205
+
206
+
207
+ class ModelNameExt(Parameter):
208
+ def __init__(self) -> None:
209
+ self.parameter_name = constants.MODEL_NAME_EXT
210
+
211
+ def validate(self, value, default, required):
212
+ if not value:
213
+ value = default
214
+ if not value and required:
215
+ raise ValidationError(
216
+ f"Parameter is required: {self.parameter_name}"
217
+ )
218
+
219
+ def get_value_or_else(self, value, default):
220
+ value = super().get_value_or_else(value, default)
221
+ return self.cast_value(value)
222
+
223
+ def cast_value(self, value):
224
+ return value
225
+
226
+
227
+ def gather_parameters():
228
+ parser = argparse.ArgumentParser()
229
+ parser.add_argument(
230
+ f"--{constants.ENV_PARAM}",
231
+ help="environment in which job is running",
232
+ )
233
+
234
+ parser.add_argument(
235
+ f"--{constants.EXPORT_DATA_PARAM}",
236
+ help="save data parameter",
237
+ )
238
+
239
+ parser.add_argument(
240
+ f"--{constants.LAST_X_DAYS_PARAM}",
241
+ help="parameter to determine the number of days considered in the query",
242
+ )
243
+
244
+ parser.add_argument(
245
+ f"--{constants.SEASON_YEAR}",
246
+ help="parameter to determine the current season year",
247
+ )
248
+
249
+ parser.add_argument(
250
+ f"--{constants.HANA_SEASON}",
251
+ help="parameter to determine the current Hana season",
252
+ )
253
+
254
+ parser.add_argument(
255
+ f"--{constants.FILE_NAME_PARAM}",
256
+ help="file name parameter",
257
+ )
258
+
259
+ parser.add_argument(
260
+ f"--{constants.PREV_SEASONS_PARAM}",
261
+ help="number of previous seasons to consider",
262
+ )
263
+
264
+ parser.add_argument(
265
+ f"--{constants.SEND_EMAIL}",
266
+ action="store_false",
267
+ help="DO NOT send out email with link to download file",
268
+ )
269
+
270
+ parser.add_argument(
271
+ f"--{constants.MODEL_NAME_EXT}",
272
+ help="suffix to append to model name",
273
+ )
274
+
275
+ args = parser.parse_args()
276
+ params_dictionary = vars(args)
277
+
278
+ return params_dictionary
@@ -0,0 +1,12 @@
1
+ Metadata-Version: 2.1
2
+ Name: dscin-ppy
3
+ Version: 0.0.1
4
+ Summary: Collection of utility functions
5
+ Home-page: UNKNOWN
6
+ Author: Andrea Chiappo
7
+ Author-email: chiappo.andrea@gmail.com
8
+ License: UNKNOWN
9
+ Platform: UNKNOWN
10
+
11
+ UNKNOWN
12
+
@@ -0,0 +1,17 @@
1
+ README.md
2
+ setup.py
3
+ dscin_ppy/__init__.py
4
+ dscin_ppy/aws_utils.py
5
+ dscin_ppy/constants.py
6
+ dscin_ppy/data_extracts.py
7
+ dscin_ppy/db_utils.py
8
+ dscin_ppy/errors.py
9
+ dscin_ppy/etl_job.py
10
+ dscin_ppy/exposing_reports.py
11
+ dscin_ppy/functions.py
12
+ dscin_ppy/job_parameters.py
13
+ dscin_ppy.egg-info/PKG-INFO
14
+ dscin_ppy.egg-info/SOURCES.txt
15
+ dscin_ppy.egg-info/dependency_links.txt
16
+ dscin_ppy.egg-info/requires.txt
17
+ dscin_ppy.egg-info/top_level.txt
@@ -0,0 +1,4 @@
1
+ boto3==1.35.15
2
+ pandas==2.0.1
3
+ numpy==1.23.5
4
+ hdbcli==2.17.22
@@ -0,0 +1 @@
1
+ dscin_ppy
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,16 @@
1
+ from setuptools import find_packages, setup
2
+
3
+ setup(
4
+ name="dscin_ppy",
5
+ version="0.0.1",
6
+ author="Andrea Chiappo",
7
+ author_email="chiappo.andrea@gmail.com",
8
+ description="Collection of utility functions",
9
+ packages=find_packages(include=["dscin_ppy"]),
10
+ install_requires=[
11
+ "boto3==1.35.15",
12
+ "pandas==2.0.1",
13
+ "numpy==1.23.5",
14
+ "hdbcli==2.17.22"
15
+ ]
16
+ )