How to call a loop under main fuction python

Viewed 242

I am working on a script which i have to modify in order loop through the multiple resources within a functions.

Below are the items which we need to loop through to get the data from and, this is coming from Config_local

BASE_URL = "https://synergy.hpe.example.com/rest/"

RES_EXT = [ 'resource-alerts?count=500&start=1',
            'resource-alerts?count=500&start=501' 
            'resource-alerts?count=500&start=1001,
            'resource-alerts?count=500&start=1501'
            ]

While i am looping through above list under def main(): section and taking get_resource_alerts_response() under loop the data coming out of the loop getting over-written and thus returning only last loop data only.

Main Script:

import os
import shutil
import smtplib
from email.message import EmailMessage
import pandas as pd
pd.set_option('expand_frame_repr', True)
import requests
from Config_local import (
    BASE_URL,
    DST_DIR,
    OUTFILE,
    PASSWORD,
    SRC_DIR,
    TIMESTAMP_DST,
    USERNAME,
    SUBJECT,
    FROM,
    TO,
    EMAIL_TEMPLATE,
    SMTP_SERVER,
    RES_EXT,
)

class FileMoveFailure(Exception):
    pass

class SynergyRequestFailure(Exception):
    pass

class SessionIdRetrievalFailure(SynergyRequestFailure):
    pass

class ResourceAlertsRetrievalFailure(SynergyRequestFailure):
    pass

def move_csv_files():
    for csv_file in os.listdir(SRC_DIR):
        if csv_file.endswith(".csv") and os.path.isfile(os.path.join(SRC_DIR, csv_file)):
            try:
                shutil.move(
                    os.path.join(f"{SRC_DIR}/{csv_file}"),
                    f"{DST_DIR}/{csv_file}-{TIMESTAMP_DST}.log"
                )
            except OSError as os_error:
                raise FileMoveFailure(
                    f'Moving file {csv_file} has failed: {os_error}'
                )

def get_session_id(session):
    try:
        response = session.post(
            url=f"{BASE_URL}/login-sessions",
            headers={
                "accept": "application/json",
                "content-type": "application/json",
                "x-api-version": "120",
            },
            json={
                "userName": USERNAME,
                "password": PASSWORD
            },
            verify=False
        )
    except requests.exceptions.RequestException as req_exception:
        # you should also get this logged somewhere, or at least
        # printed depending on your use case
        raise SessionIdRetrievalFailure(
            f"Could not get session id: {req_exception}"
        )

    json_response = response.json()
    if not json_response.get("sessionID"):
        # always assume the worse and do sanity checks & validations
        # on fetched data
        raise KeyError("Could not fetch session id")
    return json_response["sessionID"]

#def get_all_text(session, session_id):
#    all_text = ''
#    for res in RES_EXT:
#        url= f"{BASE_URL}{res}"
#        newresult = get_resource_alerts_response(session, session_id, url)
#        all_text += newresult
#        print(f"{all_text}")
#        return str(all_text)
#

def get_resource_alerts_response(session, session_id, res):
    try:
        return  session.get(
            url=f"{BASE_URL}{res}",
            headers={
                "accept": "application/json",
                "content-type": "text/csv",
                "x-api-version": "2",
                "auth": session_id,
            },
            verify=False,
            stream=True
        )
    except requests.exceptions.RequestException as req_exception:
        # you should also get this logged somewhere, or at least
        # printed depending on your use case
        raise ResourceAlertsRetrievalFailure(
            f"Could not fetch resource alerts: {req_exception}"
        )

def resource_alerts_to_df(resource_alerts_response):
    with open(OUTFILE, 'wb') as f:
        for chunk in resource_alerts_response.iter_content(chunk_size=1024*36):
            f.write(chunk)
    return pd.read_csv(OUTFILE)

def send_email(df):
    server = smtplib.SMTP(SMTP_SERVER)
    msg = EmailMessage()
    msg['Subject'], msg['From'], msg['To'] = SUBJECT, FROM, TO
    msg.set_content("Text version of your html template")
    msg.add_alternative(
        EMAIL_TEMPLATE.format(df.to_html(index=False)),
        subtype='html'
    )
    server.send_message(msg)

def main():
    move_csv_files()
    session = requests.Session()
    session_id = get_session_id(session)
    for res in RES_EXT:
        resource_alerts_response = get_resource_alerts_response(session,
        session_id, res)
        print(resource_alerts_response)
    df = resource_alerts_to_df(resource_alerts_response)
    print(df)
    send_email(df)
if __name__ == '__main__':
    main()

any help or hint will be much appreciated.

2 Answers

Only the last response is being used because this value is overwritten in resource_alerts_response on each iteration of the loop. You may consider acting on the data on each iteration or storing it for use later i.e. after the loop. I've included these options with modifications to the main() function below.

Option 1

Send an email for each resource alert response

def main():
    move_csv_files()
    session = requests.Session()
    session_id = get_session_id(session)
    for res in RES_EXT:
        resource_alerts_response = get_resource_alerts_response(session,
        session_id, res)
        print(resource_alerts_response)

        # Indent lines below so that the operations below are executed in each loop iteration
        df = resource_alerts_to_df(resource_alerts_response)
        print(df)
        send_email(df)

Option 2

Merge all resource alert responses and send one email

def main():
    move_csv_files()
    session = requests.Session()
    session_id = get_session_id(session)
    df_resource_alerts_responses = None
    for res in RES_EXT:
        resource_alerts_response = get_resource_alerts_response(session,
        session_id, res)
        print(resource_alerts_response)
        df = resource_alerts_to_df(resource_alerts_response)
        if df_resource_alerts_responses is None:
            df_resource_alerts_responses = df
        else:
            df_resource_alerts_responses = df_resource_alerts_responses.append(df, ignore_index=True)
    print(df_resource_alerts_responses)
    if  df_resource_alerts_responses is not None:
        send_email(df_resource_alerts_responses)

This is a copy of the code which I recall we had over SO but not what you want now, However, as the whole code body is okay and the idea of for loop is also looks good, you Just need to tweek it to meet the requirement.

1- You need to create and empty DataFrame assignment Synergy_Data = pd.DataFrame()

2- then you can append the data you received from for loop ie resource_alerts_response which becomes df = resource_alerts_to_df(resource_alerts_response)

3- lastly, you can append this df to the empty Synergy_Data and then call that under your if __name__ == '__main__' to send an e-mail. Also don't forget to declare Synergy_Data as a global variable.

Synergy_Data = pd.DataFrame()

def main():
    global Synergy_Data
    move_csv_files()
    session = requests.Session()
    session_id = get_session_id(session)
    for res in RES_EXT:
        resource_alerts_response = get_resource_alerts_response(session,
        session_id, res)
        df = resource_alerts_to_df(resource_alerts_response)
        Synergy_Data = Synergy_Data.append(df)
if __name__ == '__main__':
    main()
    send_email(Synergy_Data)

Hope this will be helpful.

Related