Help troubleshooting a program that suddenly exits when it has worked fine for years

help :slight_smile: with Python 3.4.3 budgeting script that has been working flawlessly for over 2 years on both windows and linux. One of the subroutines is kicking out to the OS and I can’t figure out why. Basically the “Payday” subroutine prompts for the amount … then steps through over 100 budget accounts adding a previously budgeted amount to the current balance and increments the counter to the next account. This has worked flawlessly for years and all of a sudden it bumps out to the OS in the middle of the routine … and even weirder it dumps out on a laptop and two different desktops as different points in the count … 34 on one 83 on another and works on the third … I couldn’t find it and it happened again a month later doing the same thing … same amount … but DIFFERENT counts through the list and the desktop that exited last month worked fine but the one that works last month didn’t this time… I don’t even know where to put an error trap in the routine as it doesn’t look like it actually gets through the entire list of commands. Sorry for the long post but I wanted to save some question and answer

Without the code and a traceback, there’s not much we can do to help.

3 Likes

Have you tried running the script with a debugger? Throw in several breakpoints near where it seems to fail, and then step through to get a sense of where things go wrong. This might also help identify any error messages like @MRAB was saying

First, that version of Python is fairly old. We may not always be able to update Python, but using an old Python can cause problems if you are using newer modules. Limiting which modules one can use limits what one can do.

Some modules are not compatible with an old version of Python, and in fact, some need Python 3.8 or higher. Check each module requirements on https://pypi.org.

Second, run the program through the debugger and trap the error and show us the line that causes the error and the exact error, like this:

import sys
try: 
    # Do your command(s) here. 
except Exception as e:
    print(f"ERROR Will Robinson! {e}")
    sys.exit()

Use multiple try..except blocks to break up your logic into multiple blocks that make sense. You should not have 200 lines inside the try...except block. Just have up to 20 lines IMO.

Questions

  1. What is the line that is causing the problem? Are you reading from a database? Reading from an Excel file?

Possibilities

Bad/Corrupt Excel file

Once in a while I get a corrupt Excel file and the program reads really weird results, although this seemed to be a problem with the older Perl module I was using. I have not had problems with Python yet but I have only used it since March 2024.

Bad data in database

Sometimes I read data from a database and the field/column that is read will have invisible characters because our less-than-stellar software (that I did not write) allows all kinds of control characters and does not clean those out. And that’s why you need an input routine or read routine that all your programs use that removes odd invisible characters.

I recently found a field with a unique SKU (inventory item number) that had a CRLF in the middle of the SKU! This SKU was used to link 2 completely different databases together in Power BI.

Memory issues

It’s also possible you are running out of memory especially if the program is running on a cloud service. Our cloud service plan has only 1GB of memory for the virtual machine. We have to work within budgetary constraints. That is not enough for when we start using big data. Our minimum machine requirements are 32GB of RAM since we do read some large Excel files of 100MB or a bit more. (The customer doesn’t know how to give us the data in any other way so we have to work with that.)

My point being I have already hit limits of memory with Perl reading spreadsheets (which we don’t use anymore) and with Power BI visuals. I have had no problems with memory and Python.

1 Like

what is a traceback?

See 8. Errors and Exceptions — Python 3.12.5 documentation

Presumably it’s the thing that you saw here:

To help you we’d need to see what was dumped out as well as the corresponding code (both as formatted text).

1 Like

When a Python program stops because of an error, it prints a series of messages saying what the error was and where it occurred. That’s called a “traceback”.

2 Likes

As I said before the program is old. I wrote it originally in 2014 never expecting to need more than 100 budget items for my home budget. In 2021, I went over 100 and encountered errors relating to displaying information and counting steps which were easily corrected and have had no issues since Oct 2021 until last month. I am not using any new modules, only what was available when I started writing the program in 2014.

Are the modules the part at the beginning after import?? As I said each part of the program was tested and ran for years without errors until last month. No new modules have been added but I will attempt to check requirements on that site.

didn’t know how to read Excel file … created a text file using this program … each line is read in and filled into arrays before the main menu is displayed and can be reviewed from the main menu with no problems. The entire file is updated each time any change is made to any value in the arrays

this is unlikely as the data file is rewritten after any change and backed up directly as a text readable file on each of the three computers on a normal exit from the program and a separate batch file is used to copy the data file from one computer to the other afterwards if the other computer is on. This problem appears only during one menu selection and only partway through indexing a counter and not in the same index number … I don’t know how to put a trap in the middle of the loop that would catch something that spits me out to the OS

unlikely as the program has not changed and the data file size in only 8K … I am not running this on a cloud based service as I could not figure out how to write the data to the local machine with the program running on PythonAnywhere and I don’t need this accessible from anywhere other than my home … Initially I wanted to make the program available online for anyone to use but it seemed to hard and I didn’t want to do it that bad.

is there a log file where the traceback is stored or do I have to add lines of code to create a printed error to see?

How do I include the portion of code that is having the problem with the commands and comments in color … I tried to copy for you to look at but it stripped out the different colors making it very difficult to read

You can include formatted text by surrounding the block of code with triple-backticks (```):

```python
def foo():
    pass
```

becomes

def foo():
    pass

No, not unless you wrote some code to do that sort of logging yourself.

If an exception is being raised, you should be able to see the traceback wherever the programs output usually appears (assuming you’re running this in some terminal like environment that shows the stdout & stderr).

1 Like
def payday():#routine to add budgeted amounts to the account balance then add remainder
    global amount_left
    amount_left = "0"
    answer = ""
    paycheck = ""
    total = 0 #initially an integer
    while paycheck == "":
        cls()
        line=3
        paycheck = get_value(line,"payday")#returns a string of numbers
        if paycheck =="X":#change your mind
            return False#back to main menu nothing changed
        answer = ""
        while answer == "":
            print("%s%s" % (pos(line,1),"                                                                                  "),end="")
            print("%s%s" % (pos(line,2),(print_as_money(paycheck))),end="")
            print("%s%s" % (pos(line+2,1),"                                             "),end="")
            print("%s%s" % (pos(line+2,2),"IS THIS AMOUNT CORRECT? "),end="")
            answer = ynx(input())#test if paycheck is correct
            if answer == "X":#changed your mind
                return False#back to main menu nothing changed
            if answer == "N":#ask again
                paycheck = ""
                continue
            if answer == "Y":
                total = budget_total()#returns an integer value for the total of budget values
    amount_left = paycheck#assign value of paycheck to variable used to track what is left after each add - both are type <string>
    if int(paycheck)<total:#paycheck not enough 
        answer1 = paycheck_not_enough()#print message telling not enough
        if answer1 == "X" or answer1 == "x":#don't do anything just exit to main menu
            amount_left = "0"
            return False#back to main menu nothing changed
        while int(amount_left) >0:#still some left of the paycheck
            change_flag = add_to_account()#returns True if added or False if no add
            if int(amount_left) > 0 and change_flag == False:#if amount_left is still > 0 AND no change was made means "X" to get back to main menu
                amount_left = "0"#forget about what is left to add
                return False#Cancels the rest of payday - even if there is till some money that has not been added
            elif int(amount_left) > 0 and change_flag == True:#if amount_left is still > 0 AND some was added to one account
                write_data_file()#save the data to file
                change_flag = False#reset flag after write
                exit_flag = True#set to True if ANY change made to data file - offer to backup to USB on exit
                continue
    else:#paycheck is enough or more than enough
        for index in range(0,num_budget):#cycle through each budget account
            budget_balance[index] = add_values(budget_balance[index],budget_amount[index])#add budgeted amount to current balance
            amount_left = subtract_values(amount_left,budget_amount[index])#subtract budgeted amount from amount remaining of paycheck
            write_data_file()#write data to file
        while int(amount_left) > 0:#amount of paycheck was more than enough .. add the rest where you want
            answer2 = print_amount_left(3)#print remainder after autoadd or last add of part of remainder
            if answer2 == "X" or answer2 == "x":
                amount_left = "0"#forget about what is left to add
                return True#Cancels the rest of payday - even if there is till some money that has not been added
            change_flag = add_to_account()
            if int(amount_left) > 0 and change_flag == False:#if amount_left is still > 0 AND no change was made means "X" to get back to main menu
                amount_left = "0"#forget about what is left to add
                return True#Cancels the rest of payday - even if there is till some money that has not been added
            elif int(amount_left) > 0 and change_flag == True:#if amount_left is still > 0 AND some was added to one account
                write_data_file()#write data to file
                continue
            elif int(amount_left) == 0 and change_flag == True:#last add was all that remained of amount_left
                write_data_file()#write data to file
                amount_left = "0"#reset string to contain "0" before going back to main menu
                return True

this is the entire subroutine for payday

I am not sure but am I missing a way to increment the index ? and if so how has it worked for over two years as is? This is hurting my brain:-)

in this snipet

for index in range(0,num_budget):#cycle through each budget account
            budget_balance[index] = add_values(budget_balance[index],budget_amount[index])#add budgeted amount to current balance
            amount_left = subtract_values(amount_left,budget_amount[index])#subtract budgeted amount from amount remaining of paycheck

how is the index sequenced through the values of the argument? I know it does it … but it only gets partway through the numbers and then exits to the OS … and not at the same point even though the input value of paycheck is the same in each test case …

where would I put a trap for error in this case ?

The for loop evaluates the expression and then binds each value it yields to the variable.

If you run this:

for index in range(0, num_budget):
    print(f"Add budget_amount[{index}] to budget_balance[{index}]")
    print(f"Subtract budget_amount[{index}] from amount_left")

it’ll print out:

Add budget_amount[0] to budget_balance[0]
Subtract budget_amount[0] from amount_left
Add budget_amount[1] to budget_balance[1]
Subtract budget_amount[1] from amount_left
Add budget_amount[2] to budget_balance[2]
Subtract budget_amount[2] from amount_left
...

The traceback will tell you where it’s going wrong.

How are you running the program?

Are you double-clicking on it from File Explorer (assuming you’re using Windows here)?

If you are, open a Command Prompt window, change the working directory:

cd "path/to/folder"

and then run it:

py "my_program.py"

Does it finish properly or does it stop with a traceback (error message)?

3 Likes

I didn’t see any error … the only way I know where it stopped indexing the number is to look at the totals after restarting the program … reviewing the budget list shows that the amounts that were supposed to be added only went part way through the 113 budget items … on one computer it stopped at 34 … and another it stopped at 83 … and the third computer it completed the entire 113 items.

to Brian and Matthew … I am running the program by clicking a shortcut on my desktop that starts in C:/python34 and runs the budget.py script. A normal exit prompts for a manual backup to a USB stick. If there is any change to the data by adding a budget item, removing an item , adding to or subtracting from any budget balance … a normal exit will automatically make a local backup with the date in the title and then prompt to backup on the USB.

When this started malfunctioning … there was no backup file created and no prompts … simply the terminal window closed and I went back to the windows desktop

As I suggested, open a Command Prompt window, go to the directory where budget.py is with:

cd "folder/where/budget.py/is"

and then run budget.py with:

C:/python34/python.exe budget.py

The window should stay open even after the program has exited.

1 Like