0

I have many py files need to run in one py file. But I would like to make some condition which is need to exit the program when it occur an error during the process in any py file. Anyone can help me to solve it? Thanks.

5250A have error --> exit program

5250A no error --> 5250B have error --> exit program

5250A no error --> 5250B no error --> 5250C have error --> exit program

and so on.....

UPDATED: 2021-03-12

main.py:

import _5250A_1
import _5250A_2
import _5250A_3
import _5250A

def main():
    try:
        _5250A_1.main()
        sleep(3)
        _5250A_2.main()
        sleep(3)
        _5250A_3.main()
        sleep(3)
        _5250.main()
    except Exception as details:
        print(f"Controller failed with error {details}")
        raise
    finally:
        print("Controller completed")

if __name__ == "__main__":  
    main()

_5250A

import os 
import glob
import pandas as pd
import openpyxl as xl;
import datetime

#Define some variable
activeUser = os.getlogin()
currDateTime = datetime.datetime.today() - datetime.timedelta(days = 31)
prevDateTime = datetime.datetime.today() - datetime.timedelta(days = 62)

#Merge 3 csv files into 1 csv file
os.chdir("C:\\Users\\" + activeUser + "\\Documents\\" + "Print Count (" + currDateTime.strftime ("%b %Y") + ")\\5250A")

allFiles = [i for i in glob.glob("*.{}".format("csv"))]
mergeCsv = pd.concat([pd.read_csv(f) for f in allFiles ])

#Export to csv file
mergeCsv.to_csv("5250A.csv", header = 1, index = False)


#Run Pandas and openpyxl to load csv file and convert to xlsx file format
csvFile = pd.read_csv ("C:\\Users\\" + activeUser + "\\Documents\\" + "Print Count (" + currDateTime.strftime ("%b %Y") + ")\\5250A" + "\\5250A.csv")
csvFile.to_excel ("C:\\Users\\" + activeUser + "\\Documents\\" + "Print Count (" + currDateTime.strftime ("%b %Y") + ")\\5250A" + "\\5250A.xlsx", sheet_name="5250A (Curr)", header = True, index = None)

wb1 = xl.load_workbook("C:\\Users\\" + activeUser + "\\Documents\\" + "Print Count (" + prevDateTime.strftime ("%b %Y") + ")\\5250A" + "\\5250A.xlsx") 
ws1 = wb1.worksheets[0] 
wb2 = xl.load_workbook("C:\\Users\\" + activeUser + "\\Documents\\" + "Print Count (" + currDateTime.strftime ("%b %Y") + ")\\5250A" + "\\5250A.xlsx") 
ws2 = wb2.create_sheet("5250A (Prev)")

mr = ws1.max_row 
mc = ws1.max_column 

for i in range (1, mr + 1): 
        for j in range (1, mc + 1): 
            ws2.cell(row = i, column = j).value = ws1.cell(row = i, column = j).value 

wb2.save("C:\\Users\\" + activeUser + "\\Documents\\" + "Print Count (" + currDateTime.strftime ("%b %Y") + ")\\5250A" + "\\5250A.xlsx") 

#Run openpyxl to subtract cell value between 2 worksheet and save to xlsx file
def get_row_values(worksheet):

    result = []
    for i in worksheet.rows:
        row_data = []
        for j in i:
            row_data.append(j.value)
        result.append(row_data)
    return result

if __name__ == "__main__":

    wb = xl.load_workbook("C:\\Users\\" + activeUser + "\\Documents\\" + "Print Count (" + currDateTime.strftime ("%b %Y") + ")\\5250A" + "\\5250A.xlsx")
    ws1 = wb.worksheets[0]
    ws2 = wb.worksheets[1]

    ws1_rows = get_row_values(ws1)
    ws2_rows = get_row_values(ws2)

    ws_new = wb.create_sheet('5250A (New)')

    ws_new.append(ws1_rows[0])
    for row in range(1, len(ws1_rows)):

        row_data = []
        for column, value in enumerate(ws1_rows[row]):
            if column == 0:
                row_data.append(value)
            else:
                if ws1_rows[row][0] == ws2_rows[row][0]:
                    row_data.append(value - ws2_rows[row][column])
        ws_new.append(row_data)
    wb.save("C:\\Users\\" + activeUser + "\\Documents\\" + "Print Count (" + currDateTime.strftime ("%b %Y") + ")\\5250A" + "\\5250A.xlsx")

#Remove all csv files
os.remove("C:\\Users\\" + activeUser + "\\Documents\\" + "Print Count (" + currDateTime.strftime ("%b %Y") + ")\\5250A" + "\\5250A.1.csv")
os.remove("C:\\Users\\" + activeUser + "\\Documents\\" + "Print Count (" + currDateTime.strftime ("%b %Y") + ")\\5250A" + "\\5250A.2.csv")
os.remove("C:\\Users\\" + activeUser + "\\Documents\\" + "Print Count (" + currDateTime.strftime ("%b %Y") + ")\\5250A" + "\\5250A.3.csv")
os.remove("C:\\Users\\" + activeUser + "\\Documents\\" + "Print Count (" + currDateTime.strftime ("%b %Y") + ")\\5250A" + "\\5250A.csv")
user11343272
  • 77
  • 1
  • 1
  • 9
  • What's the error? Try printing it with `except Exception as e:print(e)` – CopyrightC Mar 10 '21 at 14:24
  • Instead of using `os.system()` which is really old-fashioned, consider using module `subprocess`. That will let you run the files and check the return code after each one. If the return code is nonzero then you skip the remaining files. But really, you should not be using one python program to call others as if they were subroutines. If you have coded all your programs with a `main()` function (which is usual) you can just import all of the subsidiary modules and then call `_5250A.main()` etc. That will require renaming your subsidiary modules because their names can't begin with a digit. – BoarGules Mar 10 '21 at 14:29
  • You can treat them as modules instead, an import them is your main script. "import 'python 5250A'" – Malo Mar 10 '21 at 14:37
  • @BoarGules: Thanks for your reply. But can you give me a code example for my reference? – user11343272 Mar 11 '21 at 04:51

1 Answers1

1

Comment expanded to answer at OP's request.

For this suggestion to work you will need to rename your files 5250A.py to _5250A.py etc. That is to make the name a legal Python identifier, which can not begin with a number. It doesn't have to be _, it can be anything you like.

Next, check that each of your programs _5250A.py etc follow the common Python boilerplate of having all the module-level code in a function called main() and at the very bottom of your code the following lines:

if __name__ == "__main__":
    main()

If you don't understand why you need to do this, stop here and go and find out, for example here. It is explained in countless tutorials, and should have been one of the first things you learnt about structuring programs. The reason you put the module-level code in a function called main() is because you want to be able to run that code from a call outside the module.

Once you have done that, put import statements in your controller program to incorporate the code of modules _5250A etc. in that program:

import _5250A
import _5250B
import _5250C
import _5250D

... etc

Then, instead of using os.system() to call an external program, you can call your main() functions directly from the controller program.

def main():
    try:
        _5250A.main()
        _5250B.main()
        _5250C.main()
        _5250D.main()
    # the rest of the calls to other modules go here
    except Exception as details:
        print(f"Controller failed with error {details}")
        raise
    finally:
        print("Controller completed")

if __name__ == "__main__":
    main()

Done this way, any exception that your subsidiary programs raise will be properly reported with a stack trace that gives the name of the module, and the function and line where it failed. Calling os.system() will at best give you the numbers 0, 1 or 2 with no indication of where or why something went wrong.

In response to your issue that one of the programs to be modified already has a test if __name__ == "__main__":

Your program _5250A contains:

if __name__ == "__main__":
    wb = xl.load_workbook("C:\\Users\\" + activeUser + "\\Documents\\" + "Print Count (" + currDateTime.strftime ("%b %Y") + ")\\5250A" + "\\5250A.xlsx")
    # lots of other code, up to
    wb.save(...)

Change this to:

def main():
    wb = xl.load_workbook("C:\\Users\\" + activeUser + "\\Documents\\" + "Print Count (" + currDateTime.strftime ("%b %Y") + ")\\5250A" + "\\5250A.xlsx")
    # lots of other code, up to
    wb.save(...)

if __name__ == "__main__":
    main()

Now the program also contains,

  • before the test if __name__ == "__main__":, a block of code at module level that begins #Define some variable and continues until def get_row_values(worksheet):
  • after the test if __name__ == "__main__":, a block of code at module level that obviously does cleanup.

It will do no harm if you move both of those blocks of module-level code into the function main(), so that it now looks like this:

def main():

    #Define some variable
    activeUser = os.getlogin()
    # and everything up to and including to the line before the `def` statement
    wb2.save(...) 

    # Then the code that was inside the if-test:

    wb = xl.load_workbook(...)
    # lots of other code, up to
    wb.save(...)


    # and finally the code that was after the if-test:

    #Remove all csv files
    os.remove(...)
    # 3 more `os.remove()` calls

How do I know that it will do no harm? Well, clearly I can't possibly know that with certainty without running the code, which I can't do because I don't have your files. But it is possible to make a confident prediction.

It is apparent that, despite the if __name__ == "__main__": test, the original module 5250A.py was not intended to be imported. Otherwise it would not be unconditionally doing file creation before that point, and file cleanup after that point. So the three blocks of code are essentially all at module level and so should have all been inside the if __name__ == "__main__": block, and so can all be safely moved into main(), as long as you take care to preserve the sequence of execution.

This is of course easy to test. Just check if your modified program _5250A.py produces the same output as the original 5250A.py when run from the command line.

It is likely that moving code around like this will initially produce a blizzard of syntax or runtime errors. That does not mean it is impossible to restructure the program; only that, in the process, it is very easy to make cut'n'paste mistakes and even easier to introduce indentation errors. I would not back myself to get this right the first time, and I recommend you don't expect immediate success either.

I realize that making invasive changes to code that you may not (or may no longer) fully understand is tricky, and something to avoid if possible, and os.system() looked like an easy way to solve your problem. But there is no way for os.system() to pass a Python exception in the invoked process back to the calling program. So it is, as you have discovered, not a full solution.

BoarGules
  • 16,440
  • 2
  • 27
  • 44
  • Thanks. But I have occur a problem which is one of py file have defined if __name__ = "__main__", and the result is can't to run for this part. – user11343272 Mar 11 '21 at 23:30
  • In that case, you *move* the code that is inside the existing `if __name__ == "__main__":` test into a function called `main()`. As the answer says, the reason you put the module-level code in a function called `main()` is because you want to be able to run that code from a call outside the module. So I already provided you with advice about what to do in this case. – BoarGules Mar 12 '21 at 06:57