# All dataframe calculations import pandas as pd MAX_DECIMAL_POINTS=10 # Generate empty dataframe with final report structure def createEmptyDf() -> pd.DataFrame: return pd.DataFrame({ 'year_month': pd.Series([], dtype='str'), 'month_cost': pd.Series([], dtype='float'), 'environment': pd.Series([], dtype='str'), 'resources': pd.Series([], dtype='str'), 'daily_cost': pd.Series([], dtype='float'), 'cost': pd.Series([], dtype='float'), 'date': pd.Series([], dtype='str'), 'product': pd.Series([], dtype='str'), 'daily_product_cost': pd.Series([], dtype='float'), 'daily_environment_cost': pd.Series([], dtype='float'), }) # From given untagged service dataframe generate dataframe with structure of final output # all summary fields set to 0 def generateAccountCost(in_df: pd.DataFrame, account: str, env: str) -> pd.DataFrame: out_df = createEmptyDf() in_dict = in_df.to_dict() for service, row in in_dict.items(): service = service.replace('($)','').lower() resources = 'untagged_' + service.replace(' ','_').lower() next_frame = pd.DataFrame.from_dict({ 'year_month': pd.Series([date.rsplit('-', 1)[0] for date in row.keys()], dtype='str'), 'month_cost': 0, 'environment': env, 'resources': resources, 'daily_cost': 0, 'cost': pd.Series([round(x, MAX_DECIMAL_POINTS) for x in row.values()], dtype='float'), 'date': pd.Series(row.keys(), dtype='str'), 'product': account, 'daily_product_cost': 0, 'daily_environment_cost': 0, },) out_df = pd.concat([out_df, next_frame], ignore_index=True) return out_df # From given tagged dataframe generate dataframe with structure of final output # all summary fields set to 0 def generateAmortizedCosts(in_df: pd.DataFrame) -> pd.DataFrame: out_df = createEmptyDf() in_dict = in_df.to_dict() for tag, row in in_dict.items(): tag = tag.replace('($)','').lower() # one broken tag fix tag = tag.replace('-','_') # extend names for cmn env and apl and dlp products splited_tag = tag.split('_', maxsplit=2) env = splited_tag[1] if env == 'cmn': env = 'common' product = splited_tag[0] if product == 'dlp': product = 'delphi' if product == 'apl': product = 'apollo' if product == 'ph': product = 'prodhub' if product == 'wtlst': product = 'whitelist' next_frame = pd.DataFrame.from_dict({ 'year_month': pd.Series([date.rsplit('-', 1)[0] for date in row.keys()], dtype='str'), 'month_cost': 0, 'environment': env, 'resources': splited_tag[2], 'daily_cost': 0, 'cost': pd.Series([round(x, MAX_DECIMAL_POINTS) for x in row.values()], dtype='float'), 'date': pd.Series(row.keys(), dtype='str'), 'product': product, 'daily_product_cost': 0, 'daily_environment_cost': 0, },) out_df = pd.concat([out_df, next_frame], ignore_index=True) return out_df # Sort dataframe by date, product, environment def sortBillingDf(in_df: pd.DataFrame)-> pd.DataFrame: out_df = in_df.sort_values(by=['date','product','environment']) return out_df # Generate dataframe with summaries for monthly cost, # daily cost, daily platform cost and daily platform environment cost def generateSummaries(in_df: pd.DataFrame) -> pd.DataFrame: out_df = createEmptyDf() # Calculate sums for month, day, day_platform and day_platform_env for month in list(pd.unique(in_df['year_month'])): month_df = in_df.loc[in_df['year_month'] == month].copy(deep=False) month_cost = month_df['cost'].sum() month_df['month_cost']=month_cost for date in list(pd.unique(month_df['date'])): daily_df = month_df.loc[month_df['date'] == date].copy(deep=False) daily_cost = daily_df['cost'].sum() daily_df['daily_cost']=daily_cost for product in list(pd.unique(daily_df['product'].values)): daily_product_df = daily_df.loc[daily_df['product'] == product].copy(deep=False) daily_product_cost = daily_product_df['cost'].sum() daily_product_df['daily_product_cost'] = daily_product_cost for env in list(pd.unique(daily_product_df['environment'].values)): daily_product_env_df = daily_product_df.loc[daily_df['environment'] == env].copy(deep=False) daily_product_env_cost = daily_product_env_df['cost'].sum() daily_product_env_df['daily_environment_cost'] = daily_product_env_cost out_df = pd.concat([out_df, daily_product_env_df], ignore_index=True) return out_df