lundi 23 septembre 2019

Why is my Python code jumping from one function into another that I didn't call?

I am testing a program that creates a list of stations on a railroad, with information about their name, milepost location, and how long of a train can clear the main track at these points. I have three "edit" functions set up: edit_mp(), edit_name(), and edit_clear(). These three can ONLY be called from a menu at the beginning of the edit_station() function. However, edit_mp() is currently taking user input and then jumping into the middle of the edit_clear() function.

I have two types of objects at play: a Station object which stores milepost, name, and clearing information; and a Subdivision object which stores the list of stations and a sorted list of mileposts at those stations.

I have tried adding extra checks into the function, which has demonstrated that the function stops right after the "New milepost is" line and confirming the input.upper(). It should move on to the if/else loop immediately following, but the print statements I put into the if are not working and the else is not calling the edit_station_menu() function. Instead, I get the "Please enter a whole number" statement and the siding length prompt from edit_clear().


    def edit_station():
        global n
        global mp_edit
        n = 0
        mp_edit = input("Enter milepost of station to edit.")
        while n <= len(sub_list[i].stations):
            if sub_list[i].stations[n].mp == float(mp_edit):
                edit_station_menu()
            elif n < len(sub_list[i].stations):
                n += 1
            else:
                print("Milepost not found.  Enter 1 to try again, or any other key to return.")
                choice = input()
                if choice == "1":
                    edit_station()
                else:
                    display_sub()

    def edit_station_menu():
        global n
        global mp_edit
        sta = sub_list[i].stations[n]
        def edit_mp():
            print("STATION SELECTED: " + sta.name)
            mp = input("Station milepost: ")
            try:
                mp = float(mp)
            except ValueError:
                print("Please enter a valid milepost number (numerals and decimals only).")
                edit_mp()
            else:
                print("New milepost is " + str(mp) + ". Is this correct? Y/N")
                correct = input()
                if correct.upper() == "Y":
                    sub_list[i].mp.remove(mp_edit)
                    print("Original milepost removed.")
                    sta.mp = mp
                    sub_list[i].mp.append(sta.mp)
                    print("New milepost added.")
                    if sub_list[i].ascend_dir == "W" or sub_list[i].ascend_dir == "S":
                        sub_list[i].mp.sort()
                    else:
                        sub_list[i].mp.sort()
                        sub_list[i].mp.reverse()
                    edit_station_menu()
                else:
                    print("Ready to move on, nothing has changed.")
                    input()
                    edit_mp()

        def edit_name():
            print("STATION SELECTED: " + sta.name)
            name = input("Enter new station name: ").upper()
            print("New station name is " + name + ". Is this correct? Y/N")
            correct = input()
            if correct.upper() == "Y":
                sta.name = name
                edit_station_menu()
            else:
                edit_name()

        def edit_clear():
            def edit_sdglen():
                sdglen = input("Enter siding length: ")
                try:
                    sta.sdglen = int(sdglen)
                except ValueError:
                    print("Please enter a whole number.")
                    edit_sdglen()
                else:
                    edit_station_menu()

            def edit_maxtoclear():
                maxtoclear = input("Maximum length that can clear main line at this station: ")
                try:
                    sta.clearlen = int(maxtoclear)
                except ValueError:
                    print("Please enter a whole number.")
                    edit_maxtoclear()
                else:
                    sta.canclear = True
                    edit_station_menu()

            print("STATION SELECTED: " + sta.name)
            sdg = input("Does this station have a designated passing siding? Y/N")
            if sdg.upper() == "Y":
                edit_sdglen()
            else:
                sta.sdglen = 0
                canclear = input("Can a train clear main track at this station? Y/N")
                if canclear.upper() == "Y":
                    edit_maxtoclear()
                else:
                    sta.canclear = False
                    sta.clearlen = 0
                    edit_station_menu()




        print("STATION SELECTED: " + sta.name)
        print("1. Edit MP")
        print("2. Edit name")
        print("3. Edit clearing information")
        print("4. Any other key to return to subdivision")
        choice = input()
        if choice == "1":
            edit_mp()
        elif choice == "2":
            edit_name()
        elif choice == "3":
            edit_clear()
        else:
            display_sub()

Here is the output of my testing:

SOUTHWARD | ALASKA DIVISION                                   |    NORTHWARD
MP        | STATIONS                          | SDG   | CLEAR | CLEAR LENGTH
29.4      | MOOSE PASS                        | 990   | False | 0
18.4      | CROWN POINT                       | 3704  | False | 0
12.0      | DIVIDE                            | 1920  | False | 0
3.4       | SEWARD                            | 0     | True  | 15000
1. Add Station
2. Edit Station
Any other key to save and return.
2
Enter milepost of station to edit.18.4
STATION SELECTED: CROWN POINT
1. Edit MP
2. Edit name
3. Edit clearing information
4. Any other key to return to subdivision
1
STATION SELECTED: CROWN POINT
Station milepost: 25.4
New milepost is 25.4. Is this correct? Y/N
y
Please enter a whole number.
Enter siding length: 

First, the program displays the station list as I have created it so far, then prompts whether I want to add a station or edit an existing one. I put in the wrong milepost at Crown Point, so I select edit, put in the milepost that has been assigned to Crown Point, and edit it. After asking me whether this is correct, the program should execute the if/else after the prompt and either a) correct the milepost in the station object and change itself in the list of mileposts (which is necessary for sorting purposes on the display of all stations) or b) tell me I didn't change a thing and go back to the menu. Instead, it's going all the way down to edit_clear() on the except ValueError statement.

I am happy to provide additional information as needed and as I am able.

Aucun commentaire:

Enregistrer un commentaire