Python Forum
Doctesting a function which prints a students name along with the maximum mark scored
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Doctesting a function which prints a students name along with the maximum mark scored
#1
How would I go about doctesting this? Output is following for e.g Maths Sam - 98

def Maximum():
    while True:
        print("Maximum marks: Please select a subject, (1) Maths (2) Physics (3) Biology (4) Geo (5) Chemistry (6) Total Marks (7) Menu")
        choice = input(" >> ")
        if choice == '1':
            # dictionary created which maps the students name to their score
            # Math
            mathtodict = dict(zip(Student, Maths_marks))
            maxmath = max(zip(mathtodict.values(), mathtodict.keys()))[1]
            print('Highest maths score: ' + maxmath + ' ' + '-' + ' ' + str(max(Maths_marks)))
        elif choice == '2':
            # Physics
            phystodict = dict(zip(Student, Physics_marks))
            maxphys = max(zip(phystodict.values(), phystodict.keys()))[1]
            print('Highest Physics score: ' + maxphys + ' ' + '-' + ' ' + str(max(Physics_marks)))
        elif choice == '3':
            # Biology
            biotodict = dict(zip(Student, Biology_marks))
            maxbio = max(zip(biotodict.values(), biotodict.keys()))[1]
            print('Highest Biology score: ' + maxbio + ' ' + '-' + ' ' + str(max(Biology_marks)))
        elif choice == '4':
            # Geography
            geogtodict = dict(zip(Student, Geog_marks))
            maxgeog = max(zip(geogtodict.values(), geogtodict.keys()))[1]
            print('Highest Geography score: ' + maxgeog + ' ' + '-' + ' ' + str(max(Geog_marks)))
        elif choice == '5':
            # Chemistry
            chemtodict = dict(zip(Student, Chemistry_marks))
            maxchem = max(zip(chemtodict.values(), chemtodict.keys()))[1]
            print('Highest Chemistry score: ' + maxchem + ' ' + '-' + ' ' + str(max(Chemistry_marks)))
        elif choice == '6':
            # calculates highest total marks scored across all subjects
            max_marks = 0
            for y in Total_marks:
              if y > max_marks:
                max_marks = y
                totaltodict = dict(zip(Student, Total_marks))
                totmax = max(zip(totaltodict.values(), totaltodict.keys()))[1]
            print('Highest total score: ' + totmax + ' ' + '-' + ' ' + str(max_marks))
        elif choice == '7':
            # exits the program and asks user if they want to return to menu or quit the program
            break

        else:
            print("Choice not found. Please choose again.")
            continue
Gribouillis write Jan-26-2022, 12:21 PM:
Please post all code, output and errors (it it's entirety) between their respective tags. Refer to BBCode help topic on how to post. Use the "Preview Post" button to make sure the code is presented as you expect before hitting the "Post Reply/Thread" button.
Reply
#2
Convert it to a more useful function that takes input as arguments instead of using the input function and have it return a value instead of printing. Most functions should not use stdio.
ndc85430 and sean1 like this post
Reply
#3
Yes, so called pure functions are easier to test.
Reply
#4
Do you know how I could refactor this code to do that?

(Jan-26-2022, 11:58 AM)sean1 Wrote: How would I go about doctesting this? Output is following for e.g Maths Sam - 98

def Maximum():
    while True:
        print("Maximum marks: Please select a subject, (1) Maths (2) Physics (3) Biology (4) Geo (5) Chemistry (6) Total Marks (7) Menu")
        choice = input(" >> ")
        if choice == '1':
            # dictionary created which maps the students name to their score
            # Math
            mathtodict = dict(zip(Student, Maths_marks))
            maxmath = max(zip(mathtodict.values(), mathtodict.keys()))[1]
            print('Highest maths score: ' + maxmath + ' ' + '-' + ' ' + str(max(Maths_marks)))
        elif choice == '2':
            # Physics
            phystodict = dict(zip(Student, Physics_marks))
            maxphys = max(zip(phystodict.values(), phystodict.keys()))[1]
            print('Highest Physics score: ' + maxphys + ' ' + '-' + ' ' + str(max(Physics_marks)))
        elif choice == '3':
            # Biology
            biotodict = dict(zip(Student, Biology_marks))
            maxbio = max(zip(biotodict.values(), biotodict.keys()))[1]
            print('Highest Biology score: ' + maxbio + ' ' + '-' + ' ' + str(max(Biology_marks)))
        elif choice == '4':
            # Geography
            geogtodict = dict(zip(Student, Geog_marks))
            maxgeog = max(zip(geogtodict.values(), geogtodict.keys()))[1]
            print('Highest Geography score: ' + maxgeog + ' ' + '-' + ' ' + str(max(Geog_marks)))
        elif choice == '5':
            # Chemistry
            chemtodict = dict(zip(Student, Chemistry_marks))
            maxchem = max(zip(chemtodict.values(), chemtodict.keys()))[1]
            print('Highest Chemistry score: ' + maxchem + ' ' + '-' + ' ' + str(max(Chemistry_marks)))
        elif choice == '6':
            # calculates highest total marks scored across all subjects
            max_marks = 0
            for y in Total_marks:
              if y > max_marks:
                max_marks = y
                totaltodict = dict(zip(Student, Total_marks))
                totmax = max(zip(totaltodict.values(), totaltodict.keys()))[1]
            print('Highest total score: ' + totmax + ' ' + '-' + ' ' + str(max_marks))
        elif choice == '7':
            # exits the program and asks user if they want to return to menu or quit the program
            break

        else:
            print("Choice not found. Please choose again.")
            continue
Reply
#5
I think I would write 3 functions: max_mark(marks, students), total_marks(marks) and get_input(). max_marks does what your current function does, except it does not loop, it does not ask for input, and it returns a tuple (student, score). Since choice 6 is completely different than choices 1-5 I would write that as a separate function instead of messing up max_mark() trying to make it do two different things.

get_input() displays a prompt, gets user input, VERIFIES USER INPUT, and returns user input. I would write it to return something more friendly than 1, 2, 3... Perhaps "Math", "Physics"..."Total", "Exit". I would probably make an enum for this, but that is overkill for a homework assignment.

The loop gets moved to the body of the script.
while True:
    choice = user_input()
    if choice == "Exit":
        break
    elif choice == "Total":
        totmax, max_marks = total_marks(Total_marks)
        print(f'Highest total score: {totmax} - {max_marks}')
    else:
        high_mark, student = max_marks(total_marks[choice], Students)
        print(f'Highest {choice} score: {student} - {high_mark}')
This makes the assumption that "total_marks" is a dictionary of all of the marks and that the keys are "Math", "Physics"...

Now that max_marks does not take input and returns output you can write a doctest. You also have a function that can be used by other scripts/programs.
Reply
#6
Where are you getting your data from? Excel? MySQL?

Assume Excel, then I would have an Excel file with a sheet for each subject and one sheet for totals. Each sheet would have the columns:

student_number, name, score1, score2, .... , scoreX

No two student numbers can be the same, so they are safer than names.

Hope you don't have millions of data!

import openpyxl

path2file = '/home/pedro/temp/'
scoresXL = 'getmax.xlsx'
sourceFile = openpyxl.load_workbook(path2file + scoresXL)
sourceSheetNames = sourceFile.sheetnames

for sheet in sourceSheetNames:
    print('Which maximum do you want?', sheet)

mymax = input('Copy and paste one of the above sheet names here ... ')

# maybe you want to change this for equally high scores or add the name
def getData(sheet):
    high_score = 0
    maxRow = sourceFile[sheet].max_row + 1 # + 1 makes sure you get the last row
    maxCol = sourceFile[sheet].max_column + 1 # ditto
    for rowNum in range(2, maxRow):
        for col in range(3, maxCol):           
            score = sourceFile[sheet].cell(row=rowNum, column=col).value
            if score > high_score:
                high_score = score
                studinr = sourceFile[sheet].cell(row=rowNum, column=1).value
    return (studinr, high_score)

tup = getData(mymax)
print('The student with student number', tup[0], 'achieved', tup[1], 'in', mymax)
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Mark outlook emails as read using Python! shane88 2 3,589 Feb-24-2022, 11:19 PM
Last Post: Pedroski55
  variable prints without being declared. ClockPillow 2 1,138 Jul-11-2021, 12:13 AM
Last Post: ClockPillow
  python prints none in function output chairmanme0wme0w 3 1,355 Jul-07-2021, 05:18 PM
Last Post: deanhystad
  Something wrong with the quotation mark in dictionary definition Mark17 1 1,429 Jan-29-2021, 03:34 PM
Last Post: buran
  Output prints Account.id at the end? LastStopDEVS 5 1,771 Dec-19-2020, 05:59 AM
Last Post: buran
  Try/Exept prints only ones tester_V 11 2,381 Nov-03-2020, 02:38 AM
Last Post: tester_V
  How to mark duplicate rows in pandas Mekala 3 1,749 Sep-17-2020, 11:32 PM
Last Post: scidam
  loop only prints last character. mcmxl22 1 1,114 Feb-17-2020, 02:36 AM
Last Post: menator01
  Custom function that prints function text gyaan_anveyshak 3 1,465 Jan-28-2020, 05:43 AM
Last Post: perfringo
  What is the correct syntax for list items that need to contain a quotation mark, etc? KaisoArt 7 2,456 Sep-14-2019, 05:26 AM
Last Post: buran

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020